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