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