1 /* Test program for adding a section to an empty ELF file.
2    Copyright (C) 2016 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_string(Elf_Scn * scn,char * str)40 add_string (Elf_Scn *scn, char *str)
41 {
42   size_t lastidx = stridx;
43   size_t size = strlen (str) + 1;
44 
45   Elf_Data *data = elf_newdata (scn);
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 = str;
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 void
check_elf(const char * fname,int class,int use_mmap)65 check_elf (const char *fname, int class, int use_mmap)
66 {
67   printf ("\nfname: %s\n", fname);
68   stridx = 0; // Reset strtab strings index
69 
70   int fd = open (fname, O_RDWR | O_CREAT | O_TRUNC, 0666);
71   if (fd == -1)
72     {
73       printf ("cannot open `%s': %s\n", fname, strerror (errno));
74       exit (1);
75     }
76 
77   Elf *elf = elf_begin (fd, use_mmap ? ELF_C_WRITE_MMAP : ELF_C_WRITE, NULL);
78   if (elf == NULL)
79     {
80       printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
81       exit (1);
82     }
83 
84   // Create an ELF header.
85   if (gelf_newehdr (elf, class) == 0)
86     {
87       printf ("cannot create ELF header: %s\n", elf_errmsg (-1));
88       exit (1);
89     }
90 
91   GElf_Ehdr ehdr_mem;
92   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
93   if (ehdr == NULL)
94     {
95       printf ("cannot get ELF header: %s\n", elf_errmsg (-1));
96       exit (1);
97     }
98 
99   // Initialize header.
100   ehdr->e_ident[EI_DATA] = class == ELFCLASS64 ? ELFDATA2LSB : ELFDATA2MSB;
101   ehdr->e_ident[EI_OSABI] = ELFOSABI_GNU;
102   ehdr->e_type = ET_NONE;
103   ehdr->e_machine = EM_X86_64;
104   ehdr->e_version = EV_CURRENT;
105 
106   if (gelf_update_ehdr (elf, ehdr) == 0)
107     {
108       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
109       exit (1);
110     }
111 
112   // Write everything to disk.
113   if (elf_update (elf, ELF_C_WRITE) < 0)
114     {
115       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
116       exit (1);
117     }
118 
119   if (elf_end (elf) != 0)
120     {
121       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
122       exit (1);
123     }
124 
125   close (fd);
126 
127   /* Reread the ELF from disk now.  */
128   fd = open (fname, O_RDWR, 0666);
129   if (fd == -1)
130     {
131       printf ("cannot (re)open `%s': %s\n", fname, strerror (errno));
132       exit (1);
133     }
134 
135   elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
136   if (elf == NULL)
137     {
138       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
139       exit (1);
140     }
141 
142   // There are no sections yet.
143   if (elf_nextscn (elf, NULL) != NULL)
144     {
145       printf ("Empty elf had a section???\n");
146       exit (1);
147     }
148 
149   // Create strtab section.
150   Elf_Scn *scn = elf_newscn (elf);
151   if (scn == NULL)
152     {
153       printf ("cannot create strings section: %s\n", elf_errmsg (-1));
154       exit (1);
155     }
156 
157   // Add an empty string to the table as NUL entry for section zero.
158   add_string (scn, "");
159 
160   GElf_Shdr shdr_mem;
161   GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
162   if (shdr == NULL)
163     {
164       printf ("cannot get header for strings section: %s\n", elf_errmsg (-1));
165       exit (1);
166     }
167 
168   shdr->sh_type = SHT_STRTAB;
169   shdr->sh_flags = 0;
170   shdr->sh_addr = 0;
171   shdr->sh_link = SHN_UNDEF;
172   shdr->sh_info = SHN_UNDEF;
173   shdr->sh_addralign = 1;
174   shdr->sh_entsize = 0;
175   shdr->sh_name = add_string (scn, ".strtab");
176 
177   // We have to store the section strtab index in the ELF header.
178   // So sections have actual names.
179   int ndx = elf_ndxscn (scn);
180   ehdr->e_shstrndx = ndx;
181 
182   if (gelf_update_ehdr (elf, ehdr) == 0)
183     {
184       printf ("cannot update ELF header: %s\n", elf_errmsg (-1));
185       exit (1);
186     }
187 
188   // Finished strtab section, update the header.
189   if (gelf_update_shdr (scn, shdr) == 0)
190     {
191       printf ("cannot update STRTAB section header: %s\n", elf_errmsg (-1));
192       exit (1);
193     }
194 
195   // Write everything to disk.
196   if (elf_update (elf, ELF_C_WRITE) < 0)
197     {
198       printf ("failure in elf_update(WRITE): %s\n", elf_errmsg (-1));
199       exit (1);
200     }
201 
202   if (elf_end (elf) != 0)
203     {
204       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
205       exit (1);
206     }
207 
208   close (fd);
209 
210   // And read it in one last time.
211   fd = open (fname, O_RDONLY, 0666);
212   if (fd == -1)
213     {
214       printf ("cannot open `%s' read-only: %s\n", fname, strerror (errno));
215       exit (1);
216     }
217 
218   elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
219   if (elf == NULL)
220     {
221       printf ("cannot create ELF descriptor read-only: %s\n", elf_errmsg (-1));
222       exit (1);
223     }
224 
225   // Is our new section there?
226   scn = elf_nextscn (elf, NULL);
227   if (scn == NULL)
228     {
229       printf ("cannot get new section: %s\n", elf_errmsg (-1));
230       exit (1);
231     }
232 
233   shdr = gelf_getshdr (scn, &shdr_mem);
234   if (shdr == NULL)
235     {
236       printf ("cannot get header for new section: %s\n", elf_errmsg (-1));
237       exit (1);
238     }
239 
240   size_t shstrndx;
241   if (elf_getshdrstrndx (elf, &shstrndx) < 0)
242     {
243       printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
244       exit (1);
245     }
246 
247   const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
248   if (sname == NULL || strcmp (sname, ".strtab") != 0)
249     {
250       printf ("Bad section name: %s\n", sname);
251       exit (1);
252     }
253 
254   if (elf_end (elf) != 0)
255     {
256       printf ("failure in elf_end: %s\n", elf_errmsg (-1));
257       exit (1);
258     }
259 
260   close (fd);
261 
262   unlink (fname);
263 }
264 
265 int
main(int argc,char * argv[])266 main (int argc __attribute__ ((unused)),
267       char *argv[] __attribute__ ((unused)))
268 {
269   elf_version (EV_CURRENT);
270 
271   check_elf ("empty.elf.32", ELFCLASS32, 0);
272   check_elf ("empty.elf.32.mmap", ELFCLASS32, 1);
273   check_elf ("empty.elf.64", ELFCLASS64, 0);
274   check_elf ("empty.elf.64.mmap", ELFCLASS64, 1);
275 
276   return 0;
277 }
278