1 /* Test program for elf_newdata 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 // Random data string (16 bytes).
34 static char *DATA = "123456789ABCDEF";
35 static size_t DATA_LEN = 16;
36 
37 static void
add_section_data(Elf * elf,char * buf,size_t len)38 add_section_data (Elf *elf, char *buf, size_t len)
39 {
40   printf ("Adding %zd bytes.\n", len);
41 
42   Elf_Scn *scn = elf_getscn (elf, 1);
43   if (scn == NULL)
44     {
45       printf ("couldn't get data section: %s\n", elf_errmsg (-1));
46       exit (1);
47     }
48 
49   Elf_Data *data = elf_newdata (scn);
50   if (data == NULL)
51     {
52       printf ("cannot create newdata for section: %s\n", elf_errmsg (-1));
53       exit (1);
54     }
55 
56   data->d_buf = buf;
57   data->d_type = ELF_T_BYTE;
58   data->d_size = len;
59   data->d_align = 1;
60   data->d_version = EV_CURRENT;
61 
62   // Let the library compute the internal structure information.
63   if (elf_update (elf, ELF_C_NULL) < 0)
64     {
65       printf ("failure in elf_update(NULL): %s\n", elf_errmsg (-1));
66       exit (1);
67     }
68 
69 }
70 
71 static Elf *
create_elf(int fd,int class,int use_mmap)72 create_elf (int fd, int class, int use_mmap)
73 {
74   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
75   if (elf == NULL)
76     {
77       printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
78       exit (1);
79     }
80 
81   // Create an ELF header.
82   if (gelf_newehdr (elf, class) == 0)
83     {
84       printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
85       exit (1);
86     }
87 
88   GElf_Ehdr ehdr_mem;
89   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
90   if (ehdr == NULL)
91     {
92       printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
93       exit (1);
94     }
95 
96   // Initialize header.
97   ehdr->e_ident[EI_DATA] = class == ELFCLASS32 ? ELFDATA2LSB : ELFDATA2MSB;
98   ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
99   ehdr->e_type = ET_NONE;
100   ehdr->e_machine = class == ELFCLASS32 ? EM_PPC : EM_X86_64;
101   ehdr->e_version = EV_CURRENT;
102 
103   // Update the ELF header.
104   if (gelf_update_ehdr (elf, ehdr) == 0)
105     {
106       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
107       exit (1);
108     }
109 
110   // Create a section.
111   Elf_Scn *scn = elf_newscn (elf);
112   if (scn == NULL)
113     {
114       printf ("cannot create new section: %s\n", elf_errmsg (-1));
115       exit (1);
116     }
117 
118   GElf_Shdr shdr_mem;
119   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
120   if (shdr == NULL)
121     {
122       printf ("cannot get header for data section: %s\n", elf_errmsg (-1));
123       exit (1);
124     }
125 
126   shdr->sh_type = SHT_PROGBITS;
127   shdr->sh_flags = 0;
128   shdr->sh_addr = 0;
129   shdr->sh_link = SHN_UNDEF;
130   shdr->sh_info = SHN_UNDEF;
131   shdr->sh_addralign = 1;
132   shdr->sh_entsize = 1;
133   shdr->sh_name = 0;
134 
135   // Finish section, update the header.
136   if (gelf_update_shdr (scn, shdr) == 0)
137     {
138       printf ("cannot update header for DATA section: %s\n", elf_errmsg (-1));
139       exit (1);
140     }
141 
142   // Add some data to the section.
143   add_section_data (elf, DATA, DATA_LEN);
144 
145   // Write everything to disk.
146   if (elf_update (elf, ELF_C_WRITE) < 0)
147     {
148       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
149       exit (1);
150     }
151 
152   return elf;
153 }
154 
155 static Elf *
read_elf(int fd,int use_mmap)156 read_elf (int fd, int use_mmap)
157 {
158   printf ("Reading ELF file\n");
159   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
160   if (elf == NULL)
161     {
162       printf ("cannot create ELF descriptor read-again: %s\n", elf_errmsg (-1));
163       exit (1);
164     }
165 
166   return elf;
167 }
168 
169 static void
check_section_size(Elf * elf,size_t size)170 check_section_size (Elf *elf, size_t size)
171 {
172   Elf_Scn *scn = elf_getscn (elf, 1);
173   if (scn == NULL)
174     {
175       printf ("couldn't get data section: %s\n", elf_errmsg (-1));
176       exit (1);
177     }
178 
179   GElf_Shdr shdr_mem;
180   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
181   if (shdr == NULL)
182     {
183       printf ("cannot get header for DATA section: %s\n", elf_errmsg (-1));
184       exit (1);
185     }
186 
187   if (shdr->sh_size == size)
188     printf ("OK %zd bytes.\n", size);
189   else
190     {
191       printf ("BAD size, expected %zd, got %" PRIu64 "\n",
192 	      size, shdr->sh_size);
193       exit (-1);
194     }
195 }
196 
197 static void
check_section_data(Elf * elf,char * data,size_t len,size_t times)198 check_section_data (Elf *elf, char *data, size_t len, size_t times)
199 {
200   Elf_Scn *scn = elf_getscn (elf, 1);
201   if (scn == NULL)
202     {
203       printf ("couldn't get data section: %s\n", elf_errmsg (-1));
204       exit (1);
205     }
206 
207   Elf_Data *d = NULL;
208   for (size_t i = 0; i < times; i++)
209     {
210       if (d == NULL || i * len >= d->d_off + d->d_size)
211 	{
212 	  d = elf_getdata (scn, d);
213 	  if (d == NULL)
214 	    {
215 	      printf ("cannot get data for section item %zd: %s\n",
216 		      i, elf_errmsg (-1));
217 	      exit (1);
218 	    }
219 	  else
220 	    printf ("OK, section data item %zd (d_off: %" PRId64
221 		    ", d_size: %zd)\n", i, d->d_off, d->d_size);
222 	}
223       char *d_data = (char *) d->d_buf + (len * i) - d->d_off;
224       printf ("%zd data (d_off: %" PRId64
225 	      ", len * i: %zd): (%p + %" PRId64 ") %s\n",
226 	      i, d->d_off, len * i, d->d_buf, (len * i) - d->d_off, d_data);
227       if (memcmp (data, d_data, len) != 0)
228 	{
229 	  printf ("Got bad data in section for item %zd.\n", i);
230 	  exit (1);
231 	}
232     }
233 }
234 
235 static void
check_elf(int class,int use_mmap)236 check_elf (int class, int use_mmap)
237 {
238   static const char *fname;
239   if (class == ELFCLASS32)
240     fname = use_mmap ? "newdata.elf32.mmap" : "newdata.elf32";
241   else
242     fname = use_mmap ? "newdata.elf64.mmap" : "newdata.elf64";
243 
244   printf ("\ncheck_elf: %s\n", fname);
245 
246   int fd = open (fname, O_RDWR|O_CREAT|O_TRUNC, 00666);
247   if (fd == -1)
248     {
249       printf ("cannot create `%s': %s\n", fname, strerror (errno));
250       exit (1);
251     }
252 
253   Elf *elf = create_elf (fd, class, use_mmap);
254   check_section_size (elf, DATA_LEN);
255   check_section_data (elf, DATA, DATA_LEN, 1);
256 
257   // Add some more data (won't be written to disk).
258   add_section_data (elf, DATA, DATA_LEN);
259   check_section_size (elf, 2 * DATA_LEN);
260   check_section_data (elf, DATA, DATA_LEN, 2);
261 
262   if (elf_end (elf) != 0)
263     {
264       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
265       exit (1);
266     }
267 
268   close (fd);
269 
270   // Read the ELF from disk now.  And add new data directly.
271   fd = open (fname, O_RDONLY);
272   if (fd == -1)
273     {
274       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
275       exit (1);
276     }
277 
278   elf = read_elf (fd, use_mmap);
279   check_section_size (elf, DATA_LEN);
280   // But don't check contents, that would read the data...
281 
282   // Add some more data.
283   add_section_data (elf, DATA, DATA_LEN);
284   check_section_size (elf, 2 * DATA_LEN);
285   check_section_data (elf, DATA, DATA_LEN, 2);
286 
287   // And some more.
288   add_section_data (elf, DATA, DATA_LEN);
289   check_section_size (elf, 3 * DATA_LEN);
290   check_section_data (elf, DATA, DATA_LEN, 3);
291 
292   if (elf_end (elf) != 0)
293     {
294       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
295       exit (1);
296     }
297 
298   close (fd);
299 
300   // Read the ELF from disk now.  And add new data after raw reading.
301   fd = open (fname, O_RDONLY);
302   if (fd == -1)
303     {
304       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
305       exit (1);
306     }
307 
308   elf = read_elf (fd, use_mmap);
309   check_section_size (elf, DATA_LEN);
310   // But don't check contents, that would read the data...
311 
312   // Get raw data before adding new data.
313   Elf_Scn *scn = elf_getscn (elf, 1);
314   if (scn == NULL)
315     {
316       printf ("couldn't get data section: %s\n", elf_errmsg (-1));
317       exit (1);
318     }
319 
320   printf ("elf_rawdata\n");
321   Elf_Data *data = elf_rawdata (scn, NULL);
322   if (data == NULL)
323     {
324       printf ("couldn't get raw data from section: %s\n", elf_errmsg (-1));
325       exit (1);
326     }
327 
328   if (data->d_size != DATA_LEN)
329     {
330       printf ("Unexpected Elf_Data: %zd", data->d_size);
331       exit (1);
332     }
333 
334   // Now add more data.
335   add_section_data (elf, DATA, DATA_LEN);
336   check_section_size (elf, 2 * DATA_LEN);
337   check_section_data (elf, DATA, DATA_LEN, 2);
338 
339   // And some more.
340   add_section_data (elf, DATA, DATA_LEN);
341   check_section_size (elf, 3 * DATA_LEN);
342   check_section_data (elf, DATA, DATA_LEN, 3);
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   // Read the ELF from disk now.  And add new data after data reading.
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 = read_elf (fd, use_mmap);
361   check_section_size (elf, DATA_LEN);
362   // Get (converted) data before adding new data.
363   check_section_data (elf, DATA, DATA_LEN, 1);
364 
365   printf ("elf_getdata\n");
366 
367   // Now add more data.
368   add_section_data (elf, DATA, DATA_LEN);
369   check_section_size (elf, 2 * DATA_LEN);
370   check_section_data (elf, DATA, DATA_LEN, 2);
371 
372   // And some more.
373   add_section_data (elf, DATA, DATA_LEN);
374   check_section_size (elf, 3 * DATA_LEN);
375   check_section_data (elf, DATA, DATA_LEN, 3);
376 
377   if (elf_end (elf) != 0)
378     {
379       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
380       exit (1);
381     }
382 
383   close (fd);
384 
385   unlink (fname);
386 }
387 
388 int
main(int argc,char * argv[])389 main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
390 {
391   // Initialize libelf.
392   elf_version (EV_CURRENT);
393 
394   // Fill holes with something non-zero to more easily spot bad data.
395   elf_fill ('X');
396 
397   check_elf (ELFCLASS32, 0);
398   check_elf (ELFCLASS32, 1);
399   check_elf (ELFCLASS64, 0);
400   check_elf (ELFCLASS64, 1);
401 
402   return 0;
403 }
404