1 /* Test program for elf_strptr function.
2    Copyright (C) 2015 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 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include ELFUTILS_HEADER(elf)
31 #include <gelf.h>
32 
33 
34 /* Index of last string added.  Returned by add_string ().  */
35 static size_t stridx = 0;
36 
37 /* Some random strings.  */
38 static char *str1;
39 static size_t str1_off;
40 static char *str2;
41 static size_t str2_off;
42 static char *str3;
43 static size_t str3_off;
44 
45 /* First three strings we write out. They should always be there.  */
46 static char *orig_str1;
47 static size_t orig_str1_off;
48 static char *orig_str2;
49 static size_t orig_str2_off;
50 static char *orig_str3;
51 static size_t orig_str3_off;
52 
53 static void
check_orig_strings(Elf * elf,int ndx,const char * msg)54 check_orig_strings (Elf *elf, int ndx, const char *msg)
55 {
56   printf ("checking orig strings: %s\n", msg);
57 
58   const char *str = elf_strptr (elf, ndx, 0);
59   printf ("\t'%s'\n", str);
60   if (str == NULL || strcmp ("", str) != 0)
61     exit (1);
62 
63   str = elf_strptr (elf, ndx, 1);
64   printf ("\t'%s'\n", str);
65   if (str == NULL || strcmp (".strings", str) != 0)
66     exit (1);
67 
68   str = elf_strptr (elf, ndx, orig_str1_off);
69   printf ("\t'%s'\n", str);
70   if (str == NULL || strcmp (orig_str1, str) != 0)
71     exit (1);
72 
73   str = elf_strptr (elf, ndx, orig_str2_off);
74   printf ("\t'%s'\n", str);
75   if (str == NULL || strcmp (orig_str2, str) != 0)
76     exit (1);
77 
78   str = elf_strptr (elf, ndx, orig_str3_off);
79   printf ("\t'%s'\n", str);
80   if (str == NULL || strcmp (orig_str3, str) != 0)
81     exit (1);
82 }
83 
84 static void
check_strings(Elf * elf,int ndx,const char * msg)85 check_strings (Elf *elf, int ndx, const char *msg)
86 {
87   check_orig_strings (elf, ndx, msg);
88 
89   const char *str = elf_strptr (elf, ndx, str1_off);
90   printf ("\t'%s'\n", str);
91   if (str == NULL || strcmp (str1, str) != 0)
92     exit (1);
93 
94   str = elf_strptr (elf, ndx, str2_off);
95   printf ("\t'%s'\n", str);
96   if (str == NULL || strcmp (str2, str) != 0)
97     exit (1);
98 
99   str = elf_strptr (elf, ndx, str3_off);
100   printf ("\t'%s'\n", str);
101   if (str == NULL || strcmp (str3, str) != 0)
102     exit (1);
103 }
104 
105 /* Adds a string and returns the offset in the section.  */
106 static size_t
add_string(Elf_Scn * scn,char * str)107 add_string (Elf_Scn *scn, char *str)
108 {
109   size_t lastidx = stridx;
110   size_t size = strlen (str) + 1;
111 
112   Elf_Data *data = elf_newdata (scn);
113   if (data == NULL)
114     {
115       printf ("cannot create data SHSTRTAB section: %s\n", elf_errmsg (-1));
116       exit (1);
117     }
118 
119   data->d_buf = str;
120   data->d_type = ELF_T_BYTE;
121   data->d_size = size;
122   data->d_align = 1;
123   data->d_version = EV_CURRENT;
124 
125   stridx += size;
126   printf ("add_string: '%s', stridx: %zd, lastidx: %zd\n",
127 	  str, stridx, lastidx);
128   return lastidx;
129 }
130 
131 static void
check_elf(const char * fname,int class,int use_mmap)132 check_elf (const char *fname, int class, int use_mmap)
133 {
134   printf ("\nfname: %s\n", fname);
135   stridx = 0;
136 
137   int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
138   if (fd == -1)
139     {
140       printf ("cannot open `%s': %s\n", fname, strerror (errno));
141       exit (1);
142     }
143 
144   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
145   if (elf == NULL)
146     {
147       printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
148       exit (1);
149     }
150 
151   // Create an ELF header.
152   if (gelf_newehdr (elf, class) == 0)
153     {
154       printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
155       exit (1);
156     }
157 
158   GElf_Ehdr ehdr_mem;
159   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
160   if (ehdr == NULL)
161     {
162       printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
163       exit (1);
164     }
165 
166   // Initialize header.
167   ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
168   ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
169   ehdr->e_type = ET_NONE;
170   ehdr->e_machine = EM_X86_64;
171   ehdr->e_version = EV_CURRENT;
172 
173   // Create strings section.
174   Elf_Scn *scn = elf_newscn (elf);
175   if (scn == NULL)
176     {
177       printf ("cannot create strings section: %s\n", elf_errmsg (-1));
178       exit (1);
179     }
180 
181   // Add an empty string to the table as NUL entry for section zero.
182   add_string (scn, "");
183 
184   GElf_Shdr shdr_mem;
185   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
186   if (shdr == NULL)
187     {
188       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
189       exit (1);
190     }
191 
192   shdr->sh_type = SHT_STRTAB;
193   shdr->sh_flags = 0;
194   shdr->sh_addr = 0;
195   shdr->sh_link = SHN_UNDEF;
196   shdr->sh_info = SHN_UNDEF;
197   shdr->sh_addralign = 1;
198   shdr->sh_entsize = 0;
199   shdr->sh_name = add_string (scn, ".strings");
200 
201   // We have to store the section strtab index in the ELF header.
202   // So sections have actual names.
203   int ndx = elf_ndxscn (scn);
204   ehdr->e_shstrndx = ndx;
205 
206   if (gelf_update_ehdr (elf, ehdr) == 0)
207     {
208       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
209       exit (1);
210     }
211 
212   // Add some random strings. These are the original ones. They should
213   // always be there (together with the empty "" and .strings section
214   // name strings.
215   orig_str1 = "elfutils";
216   orig_str1_off = add_string (scn, orig_str1);
217   orig_str2 = "strtabelf";
218   orig_str2_off = add_string (scn, orig_str2);
219   orig_str3 = "three";
220   orig_str3_off = add_string (scn, orig_str3);
221 
222   // Finished strings section, update the header.
223   if (gelf_update_shdr (scn, shdr) == 0)
224     {
225       printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
226       exit (1);
227     }
228 
229   // Let the library compute the internal structure information.
230   if (elf_update (elf, ELF_C_NULL) < 0)
231     {
232       printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1));
233       exit (1);
234     }
235 
236   // Check our strings are there.
237   check_orig_strings (elf, ndx, "first elf_update, before write");
238 
239   // Write everything to disk.
240   if (elf_update (elf, ELF_C_WRITE) < 0)
241     {
242       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
243       exit (1);
244     }
245 
246   // Check out strings are there.
247   check_orig_strings (elf, ndx, "first elf_update, after write");
248 
249   // Add some more random strings.  These will not be written to disk.
250   scn = elf_getscn (elf, ndx);
251   if (scn == NULL)
252     {
253       printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
254       exit (1);
255     }
256 
257   str1 = "elfutils2";
258   str1_off = add_string (scn, str1);
259   str2 = "strtabelf2";
260   str2_off = add_string (scn, str2);
261   str3 = "three2";
262   str3_off = add_string (scn, str3);
263 
264   // Update internal structure information again.
265   if (elf_update (elf, ELF_C_NULL) < 0)
266     {
267       printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
268       exit (1);
269     }
270 
271   // Check our new strings are there.
272   check_strings (elf, ndx, "first extra strings");
273 
274   if (elf_end (elf) != 0)
275     {
276       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
277       exit (1);
278     }
279 
280   close (fd);
281 
282   /* Read the ELF from disk now.  */
283   fd = open (fname, O_RDWR, 0666);
284   if (fd == -1)
285     {
286       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
287       exit (1);
288     }
289 
290   elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
291   if (elf == NULL)
292     {
293       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
294       exit (1);
295     }
296 
297   /* Are our strings there?  */
298   check_orig_strings (elf, ndx, "read ELF file, orig strings");
299 
300   // Add some more random strings.
301   scn = elf_getscn (elf, ndx);
302   if (scn == NULL)
303     {
304       printf ("couldn't re-get strings section: %s\n", elf_errmsg (-1));
305       exit (1);
306     }
307 
308   shdr = gelf_getshdr (scn, &shdr_mem);
309   if (shdr == NULL)
310     {
311       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
312       exit (1);
313     }
314 
315   // Reset stridx to end of section.
316   printf ("sh_size: %" PRIu64 "\n", shdr->sh_size);
317   stridx = shdr->sh_size;
318 
319   str1 = "0123456789";
320   str1_off = add_string (scn, str1);
321   str2 = "supercalifragilisticexpialidocious";
322   str2_off = add_string (scn, str2);
323   str3 = "forty-two";
324   str3_off = add_string (scn, str3);
325 
326   // Update internal structure information.
327   if (elf_update (elf, ELF_C_NULL) < 0)
328     {
329       printf ("failure in rw-elf_update(NULL): %s\n", elf_errmsg (-1));
330       exit (1);
331     }
332 
333   /* Check our new strings are there.  */
334   check_strings (elf, ndx, "read file, added strings");
335 
336   // Write updated ELF file.
337   if (elf_update (elf, ELF_C_WRITE) < 0)
338     {
339       printf ("failure in re-elf_update(NULL): %s\n", elf_errmsg (-1));
340       exit (1);
341     }
342 
343   if (elf_end (elf) != 0)
344     {
345       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
346       exit (1);
347     }
348 
349   close (fd);
350 
351   // And read it in one last time.
352   fd = open (fname, O_RDONLY, 0666);
353   if (fd == -1)
354     {
355       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
356       exit (1);
357     }
358 
359   elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
360   if (elf == NULL)
361     {
362       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
363       exit (1);
364     }
365 
366   /* Are all our strings there?  */
367   check_strings (elf, ndx, "all together now");
368 
369   if (elf_end (elf) != 0)
370     {
371       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
372       exit (1);
373     }
374 
375   close (fd);
376 
377   unlink (fname);
378 }
379 
380 int
main(int argc,char * argv[])381 main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
382 {
383   elf_version (EV_CURRENT);
384 
385   // Fill holes with something non-zero to more easily spot
386   // unterminated strings.
387   elf_fill ('X');
388 
389   check_elf ("strtab.elf.32", ELFCLASS32, 0);
390   check_elf ("strtab.elf.32.mmap", ELFCLASS32, 1);
391   check_elf ("strtab.elf.64", ELFCLASS64, 0);
392   check_elf ("strtab.elf.64.mmap", ELFCLASS64, 1);
393 
394   return 0;
395 }
396 
397