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 
31 #include ELFUTILS_HEADER(elf)
32 #include <gelf.h>
33 
34 
35 /* Index of last string added.  Returned by add_string ().  */
36 static size_t stridx = 0;
37 
38 /* Adds a string and returns the offset in the section.  */
39 static size_t
add_strtab_entry(Elf_Scn * strtab,const char * str)40 add_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 
64 static Elf_Scn *
create_strtab(Elf * elf)65 create_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 
125 static char sec_data[] = { 1, 2, 3, 4, 5 };
126 static char new_data[] = { 5, 4, 3, 2, 1 };
127 
128 static void
add_data_section(Elf * elf,Elf_Scn * strtab,const char * sname)129 add_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 
174 static void
check_data(const char * sname,Elf_Data * data,char * buf)175 check_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 
198 static void
check_elf(const char * fname,int class,int use_mmap)199 check_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 
434 int
main(int argc,char * argv[])435 main (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 }
449