1/* Test program for changing data in one section (but not others) with gaps. 2 Copyright (C) 2017 Red Hat, Inc. 3 This file is part of elfutils. 4 5 This file is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 19#ifdef HAVE_CONFIG_H 20# include <config.h> 21#endif 22 23#include <errno.h> 24#include <fcntl.h> 25#include <inttypes.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <unistd.h> 30#include "system.h" 31 32#include ELFUTILS_HEADER(elf) 33#include <gelf.h> 34 35 36/* Index of last string added. Returned by add_string (). */ 37static size_t stridx = 0; 38 39/* Adds a string and returns the offset in the section. */ 40static size_t 41add_strtab_entry (Elf_Scn *strtab, const char *str) 42{ 43 size_t lastidx = stridx; 44 size_t size = strlen (str) + 1; 45 46 Elf_Data *data = elf_newdata (strtab); 47 if (data == NULL) 48 { 49 printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1)); 50 exit (1); 51 } 52 53 data->d_buf = (char *) str; /* Discards const, but we will not change. */ 54 data->d_type = ELF_T_BYTE; 55 data->d_size = size; 56 data->d_align = 1; 57 data->d_version = EV_CURRENT; 58 59 stridx += size; 60 printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n", 61 str, stridx, lastidx); 62 return lastidx; 63} 64 65static Elf_Scn * 66create_strtab (Elf *elf) 67{ 68 // Create strtab section. 69 Elf_Scn *scn = elf_newscn (elf); 70 if (scn == NULL) 71 { 72 printf ("cannot create strings section: %s\n", elf_errmsg (-1)); 73 exit (1); 74 } 75 76 // Add an empty string to the table as NUL entry for section zero. 77 add_strtab_entry (scn, ""); 78 79 GElf_Shdr shdr_mem; 80 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 81 if (shdr == NULL) 82 { 83 printf ("cannot get header for new strtab section: %s\n", 84 elf_errmsg (-1)); 85 exit (1); 86 } 87 88 shdr->sh_type = SHT_STRTAB; 89 shdr->sh_flags = 0; 90 shdr->sh_addr = 0; 91 shdr->sh_link = SHN_UNDEF; 92 shdr->sh_info = SHN_UNDEF; 93 shdr->sh_addralign = 1; 94 shdr->sh_entsize = 0; 95 shdr->sh_name = add_strtab_entry (scn, ".strtab"); 96 97 // We have to store the section strtab index in the ELF header. 98 // So sections have actual names. 99 GElf_Ehdr ehdr_mem; 100 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 101 if (ehdr == NULL) 102 { 103 printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); 104 exit (1); 105 } 106 107 int ndx = elf_ndxscn (scn); 108 ehdr->e_shstrndx = ndx; 109 110 if (gelf_update_ehdr (elf, ehdr) == 0) 111 { 112 printf ("cannot update ELF header: %s\n", elf_errmsg (-1)); 113 exit (1); 114 } 115 116 // Finished strtab section, update the header. 117 if (gelf_update_shdr (scn, shdr) == 0) 118 { 119 printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1)); 120 exit (1); 121 } 122 123 return scn; 124} 125 126static char sec_data[] = { 1, 2, 3, 4, 5 }; 127static char new_data[] = { 5, 4, 3, 2, 1 }; 128 129static void 130add_data_section (Elf *elf, Elf_Scn *strtab, const char *sname) 131{ 132 printf ("Add data section %s\n", sname); 133 Elf_Scn *scn = elf_newscn (elf); 134 if (scn == NULL) 135 { 136 printf ("cannot create strings section: %s\n", elf_errmsg (-1)); 137 exit (1); 138 } 139 140 GElf_Shdr shdr_mem; 141 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 142 if (shdr == NULL) 143 { 144 printf ("cannot get header for new %s section: %s\n", 145 sname, elf_errmsg (-1)); 146 exit (1); 147 } 148 149 shdr->sh_type = SHT_PROGBITS; 150 shdr->sh_flags = 0; 151 shdr->sh_addr = 0; 152 shdr->sh_link = SHN_UNDEF; 153 shdr->sh_info = SHN_UNDEF; 154 shdr->sh_addralign = 128; // Large alignment to force gap between sections. 155 shdr->sh_entsize = 1; 156 shdr->sh_name = add_strtab_entry (strtab, sname); 157 158 if (gelf_update_shdr (scn, shdr) == 0) 159 { 160 printf ("cannot update %s section header: %s\n", sname, elf_errmsg (-1)); 161 exit (1); 162 } 163 164 /* Add some data, but less than alignment. */ 165 Elf_Data *data = elf_newdata (scn); 166 if (data == NULL) 167 { 168 printf ("cannot update %s section header: %s\n", sname, elf_errmsg (-1)); 169 exit (1); 170 } 171 data->d_buf = sec_data; 172 data->d_size = 5; 173} 174 175static void 176check_data (const char *sname, Elf_Data *data, char *buf) 177{ 178 printf ("check data %s [", sname); 179 for (int i = 0; i < 5; i++) 180 printf ("%d%s", buf[i], i < 4 ? "," : ""); 181 printf ("]\n"); 182 if (data == NULL || data->d_buf == NULL) 183 { 184 printf ("No data in section %s\n", sname); 185 exit (1); 186 } 187 188 if (data->d_size != 5 || memcmp (data->d_buf, buf, 5) != 0) 189 { 190 printf ("Wrong data in section %s [", sname); 191 for (size_t i = 0; i < data->d_size; i++) 192 printf ("%d%s", ((char *)data->d_buf)[i], 193 i < data->d_size - 1 ? "," : ""); 194 printf ("]\n"); 195 exit(1); 196 } 197} 198 199static void 200check_elf (const char *fname, int class, int use_mmap) 201{ 202 printf ("\nfname: %s\n", fname); 203 stridx = 0; // Reset strtab strings index 204 205 int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE); 206 if (fd == -1) 207 { 208 printf ("cannot open `%s': %s\n", fname, strerror (errno)); 209 exit (1); 210 } 211 212 Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL); 213 if (elf == NULL) 214 { 215 printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); 216 exit (1); 217 } 218 219 // Create an ELF header. 220 if (gelf_newehdr (elf, class) == 0) 221 { 222 printf ("cannot create ELF header: %s\n", elf_errmsg (-1)); 223 exit (1); 224 } 225 226 GElf_Ehdr ehdr_mem; 227 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 228 if (ehdr == NULL) 229 { 230 printf ("cannot get ELF header: %s\n", elf_errmsg (-1)); 231 exit (1); 232 } 233 234 // Initialize header. 235 ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB; 236 ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU; 237 ehdr->e_type = ET_NONE; 238 ehdr->e_machine = EM_X86_64; 239 ehdr->e_version = EV_CURRENT; 240 241 if (gelf_update_ehdr (elf, ehdr) == 0) 242 { 243 printf ("cannot update ELF header: %s\n", elf_errmsg (-1)); 244 exit (1); 245 } 246 247 Elf_Scn *strtab = create_strtab (elf); 248 add_data_section (elf, strtab, ".data1"); 249 add_data_section (elf, strtab, ".data2"); 250 add_data_section (elf, strtab, ".data3"); 251 add_data_section (elf, strtab, ".data4"); 252 253 // Write everything to disk. 254 if (elf_update (elf, ELF_C_WRITE) < 0) 255 { 256 printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); 257 exit (1); 258 } 259 260 if (elf_end (elf) != 0) 261 { 262 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 263 exit (1); 264 } 265 266 close (fd); 267 268 /* Reread the ELF from disk now. */ 269 printf ("Rereading %s\n", fname); 270 fd = open (fname, O_RDWR); 271 if (fd == -1) 272 { 273 printf ("cannot (re)open `%s': %s\n", fname, strerror (errno)); 274 exit (1); 275 } 276 277 elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL); 278 if (elf == NULL) 279 { 280 printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1)); 281 exit (1); 282 } 283 284 /* We are going to change some data (in-place), but want the layout 285 to stay exactly the same. */ 286 elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT); 287 288 size_t shdrstrndx; 289 if (elf_getshdrstrndx (elf, &shdrstrndx) != 0) 290 { 291 printf ("cannot get shdr str ndx\n"); 292 exit (1); 293 } 294 printf ("shdrstrndx: %zd\n", shdrstrndx); 295 296 // Get third data section and change it. 297 Elf_Scn *checkscn = NULL; 298 Elf_Scn *scn = elf_nextscn (elf, NULL); 299 while (scn != NULL) 300 { 301 GElf_Shdr shdr_mem; 302 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 303 if (shdr == NULL) 304 { 305 printf ("cannot get header for section: %s\n", elf_errmsg (-1)); 306 exit (1); 307 } 308 const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name); 309 if (sname != NULL && strcmp (".data3", sname) == 0) 310 checkscn = scn; 311 312 // Get all data, but don't really use it 313 // (this triggered the original bug). 314 Elf_Data *data = elf_getdata (scn, NULL); 315 if (data != NULL && data->d_buf != NULL && data->d_size == 0) 316 { 317 printf ("Bad data...n"); 318 exit (1); 319 } 320 scn = elf_nextscn (elf, scn); 321 } 322 323 if (checkscn == NULL) 324 { 325 printf ("ELF file doesn't have a .data3 section\n"); 326 exit (1); 327 } 328 329 Elf_Data *data = elf_getdata (checkscn, NULL); 330 check_data (".data3", data, sec_data); 331 memcpy (data->d_buf, new_data, 5); 332 elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); 333 334 // Write everything to disk. 335 if (elf_update (elf, ELF_C_WRITE) < 0) 336 { 337 printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1)); 338 exit (1); 339 } 340 341 if (elf_end (elf) != 0) 342 { 343 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 344 exit (1); 345 } 346 347 close (fd); 348 349 // And read it in one last time. 350 printf ("Rereading %s again\n", fname); 351 fd = open (fname, O_RDONLY); 352 if (fd == -1) 353 { 354 printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno)); 355 exit (1); 356 } 357 358 elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL); 359 if (elf == NULL) 360 { 361 printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1)); 362 exit (1); 363 } 364 365 // Get all .data sections and check them. 366 Elf_Scn *scn1 = NULL; 367 Elf_Scn *scn2 = NULL; 368 Elf_Scn *scn3 = NULL; 369 Elf_Scn *scn4 = NULL; 370 scn = elf_nextscn (elf, NULL); 371 while (scn != NULL) 372 { 373 GElf_Shdr shdr_mem; 374 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 375 if (shdr == NULL) 376 { 377 printf ("cannot get header for section: %s\n", elf_errmsg (-1)); 378 exit (1); 379 } 380 const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name); 381 if (sname != NULL && strcmp (".data1", sname) == 0) 382 scn1 = scn; 383 else if (sname != NULL && strcmp (".data2", sname) == 0) 384 scn2 = scn; 385 else if (sname != NULL && strcmp (".data3", sname) == 0) 386 scn3 = scn; 387 else if (sname != NULL && strcmp (".data4", sname) == 0) 388 scn4 = scn; 389 scn = elf_nextscn (elf, scn); 390 } 391 392 if (scn1 == NULL) 393 { 394 printf ("ELF file doesn't have a .data1 section\n"); 395 exit (1); 396 } 397 data = elf_getdata (scn1, NULL); 398 check_data (".data1", data, sec_data); 399 400 if (scn2 == NULL) 401 { 402 printf ("ELF file doesn't have a .data2 section\n"); 403 exit (1); 404 } 405 data = elf_getdata (scn2, NULL); 406 check_data (".data2", data, sec_data); 407 408 if (scn3 == NULL) 409 { 410 printf ("ELF file doesn't have a .data3 section\n"); 411 exit (1); 412 } 413 data = elf_getdata (scn3, NULL); 414 check_data (".data3", data, new_data); 415 416 if (scn4 == NULL) 417 { 418 printf ("ELF file doesn't have a .data4 section\n"); 419 exit (1); 420 } 421 data = elf_getdata (scn4, NULL); 422 check_data (".data4", data, sec_data); 423 424 if (elf_end (elf) != 0) 425 { 426 printf ("failure in elf_end: %s\n", elf_errmsg (-1)); 427 exit (1); 428 } 429 430 close (fd); 431 432 unlink (fname); 433} 434 435int 436main (int argc __attribute__ ((unused)), 437 char *argv[] __attribute__ ((unused))) 438{ 439 elf_version (EV_CURRENT); 440 441 elf_fill (0xA); 442 443 check_elf ("fill.elf.32", ELFCLASS32, 0); 444 check_elf ("fill.elf.32.mmap", ELFCLASS32, 1); 445 check_elf ("fill.elf.64", ELFCLASS64, 0); 446 check_elf ("fill.elf.64.mmap", ELFCLASS64, 1); 447 448 return 0; 449} 450