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