• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Update data structures for changes.
2    Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4 
5    This program 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, version 2.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <assert.h>
23 //#include <endian.h>
24 #include <libelf.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <sys/param.h>
28 
29 #include "libelfP.h"
30 #include "elf-knowledge.h"
31 
32 #ifndef LIBELFBITS
33 # define LIBELFBITS 32
34 #endif
35 
36 
37 
38 static int
ELFW(default_ehdr,LIBELFBITS)39 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
40 			       size_t shnum, int *change_bop)
41 {
42   /* Always write the magic bytes.  */
43   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
44     {
45       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
46       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
47     }
48 
49   /* Always set the file class.  */
50   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
51 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
52 
53   /* Set the data encoding if necessary.  */
54   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
55     {
56       ehdr->e_ident[EI_DATA] =
57 	BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
58       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
59     }
60   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
61     {
62       __libelf_seterrno (ELF_E_DATA_ENCODING);
63       return 1;
64     }
65   else
66     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
67 		    && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
68 		   || (BYTE_ORDER == BIG_ENDIAN
69 		       && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
70 
71   /* Unconditionally overwrite the ELF version.  */
72   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
73 		     elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
74 
75   if (unlikely (ehdr->e_version == EV_NONE)
76       || unlikely (ehdr->e_version >= EV_NUM))
77     {
78       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
79       return 1;
80     }
81 
82   if (unlikely (shnum >= SHN_LORESERVE))
83     {
84       update_if_changed (ehdr->e_shnum, 0,
85 			 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
86     }
87   else
88     update_if_changed (ehdr->e_shnum, shnum,
89 		       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
90 
91   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
92     {
93       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
94       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
95     }
96 
97   return 0;
98 }
99 
100 
101 off_t
102 internal_function_def
__elfw2(LIBELFBITS,updatenull)103 __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum)
104 {
105   ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf);
106   int changed = 0;
107   int ehdr_flags = 0;
108   off_t size;
109 
110   /* Set the default values.  */
111   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
112     return -1;
113 
114   /* At least the ELF header is there.  */
115   size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
116 
117   /* Set the program header position.  */
118   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
119     {
120       /* Only executables or shared objects have a program header.  */
121       if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN))
122 	{
123 	  __libelf_seterrno (ELF_E_INVALID_PHDR);
124 	  return -1;
125 	}
126 
127       if (elf->flags & ELF_F_LAYOUT)
128 	{
129 	  /* The user is supposed to fill out e_phoff.  Use it and
130 	     e_phnum to determine the maximum extend.  */
131 	  size = MAX ((size_t) size,
132 		      ehdr->e_phoff
133 		      + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
134 	}
135       else
136 	{
137 	  update_if_changed (ehdr->e_phoff,
138 			     elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
139 			     ehdr_flags);
140 
141 	  /* We need no alignment here.  */
142 	  size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum);
143 	}
144     }
145 
146   if (shnum > 0)
147     {
148       Elf_ScnList *list;
149       bool first = true;
150 
151       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
152 
153       if (shnum >= SHN_LORESERVE)
154 	{
155 	  /* We have to  fill in the number of sections in the header
156 	     of the zeroth section.  */
157 	  elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr.ELFW(e,LIBELFBITS)->sh_size
158 	    = shnum;
159 	  elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr_flags
160 	    |= ELF_F_DIRTY;
161 	}
162 
163 
164       /* Go over all sections and find out how large they are.  */
165       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
166 
167       do
168 	{
169 	  size_t cnt;
170 
171 	  for (cnt = first == true; cnt < list->cnt; ++cnt)
172 	    {
173 	      Elf_Scn *scn = &list->data[cnt];
174 	      ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
175 	      off_t offset = 0;
176 	      ElfW2(LIBELFBITS,Word) sh_entsize;
177 	      ElfW2(LIBELFBITS,Word) sh_align;
178 
179 	      assert (shdr != NULL);
180 	      sh_entsize = shdr->sh_entsize;
181 	      sh_align = shdr->sh_addralign ?: 1;
182 
183 	      /* Set the sh_entsize value if we can reliably detect it.  */
184 	      switch (shdr->sh_type)
185 		{
186 		case SHT_SYMTAB:
187 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
188 		  break;
189 		case SHT_RELA:
190 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
191 		  break;
192 		case SHT_GROUP:
193 		  /* Only relocatable files can contain section groups.  */
194 		  if (ehdr->e_type != ET_REL)
195 		    {
196 		      __libelf_seterrno (ELF_E_GROUP_NOT_REL);
197 		      return -1;
198 		    }
199 		  /* FALLTHROUGH */
200 		case SHT_SYMTAB_SHNDX:
201 		  sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
202 		  break;
203 		case SHT_HASH:
204 		  sh_entsize = SH_ENTSIZE_HASH (ehdr);
205 		  break;
206 		case SHT_DYNAMIC:
207 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
208 		  break;
209 		case SHT_REL:
210 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
211 		  break;
212 		case SHT_DYNSYM:
213 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
214 		  break;
215 		case SHT_SUNW_move:
216 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
217 		  break;
218 		case SHT_SUNW_syminfo:
219 		  sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
220 		  break;
221 		default:
222 		  break;
223 		}
224 
225 	      /* If the section header contained the wrong entry size
226 		 correct it and mark the header as modified.  */
227 	      update_if_changed (shdr->sh_entsize, sh_entsize,
228 				 scn->shdr_flags);
229 
230 	      /* Iterate over all data blocks.  */
231 	      if (list->data[cnt].data_list_rear != NULL)
232 		{
233 		  Elf_Data_List *dl = &scn->data_list;
234 
235 		  while (dl != NULL)
236 		    {
237 		      if (unlikely (dl->data.d.d_version == EV_NONE)
238 			  || unlikely (dl->data.d.d_version >= EV_NUM))
239 			{
240 			  __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
241 			  return -1;
242 			}
243 
244 		      if (unlikely (! powerof2 (dl->data.d.d_align)))
245 			{
246 			  __libelf_seterrno (ELF_E_INVALID_ALIGN);
247 			  return -1;
248 			}
249 
250 		      sh_align = MAX (sh_align, dl->data.d.d_align);
251 
252 		      if (elf->flags & ELF_F_LAYOUT)
253 			{
254 			  /* The user specified the offset and the size.
255 			     All we have to do is check whether this block
256 			     fits in the size specified for the section.  */
257 			  if (unlikely ((GElf_Word) (dl->data.d.d_off
258 						     + dl->data.d.d_size)
259 					> shdr->sh_size))
260 			    {
261 			      __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
262 			      return -1;
263 			    }
264 			}
265 		      else
266 			{
267 			  /* Determine the padding.  */
268 			  offset = ((offset + dl->data.d.d_align - 1)
269 				    & ~(dl->data.d.d_align - 1));
270 
271 			  update_if_changed (dl->data.d.d_off, offset,
272 					     changed);
273 
274 			  offset += dl->data.d.d_size;
275 			}
276 
277 		      /* Next data block.  */
278 		      dl = dl->next;
279 		    }
280 		}
281 
282 	      if (elf->flags & ELF_F_LAYOUT)
283 		{
284 		  size = MAX ((GElf_Word) size,
285 			      shdr->sh_offset
286 			      + (shdr->sh_type != SHT_NOBITS
287 				 ? shdr->sh_size : 0));
288 
289 		  /* The alignment must be a power of two.  This is a
290 		     requirement from the ELF specification.  Additionally
291 		     we test for the alignment of the section being large
292 		     enough for the largest alignment required by a data
293 		     block.  */
294 		  if (unlikely (! powerof2 (shdr->sh_addralign))
295 		      || unlikely (shdr->sh_addralign < sh_align))
296 		    {
297 		      __libelf_seterrno (ELF_E_INVALID_ALIGN);
298 		      return -1;
299 		    }
300 		}
301 	      else
302 		{
303 		  /* How much alignment do we need for this section.  */
304 		  update_if_changed (shdr->sh_addralign, sh_align,
305 				     scn->shdr_flags);
306 
307 		  size = (size + sh_align - 1) & ~(sh_align - 1);
308 		  update_if_changed (shdr->sh_offset, (GElf_Word) size,
309 				     changed);
310 
311 		  /* See whether the section size is correct.  */
312 		  update_if_changed (shdr->sh_size, (GElf_Word) offset,
313 				     changed);
314 
315 		  if (shdr->sh_type != SHT_NOBITS)
316 		    size += offset;
317 
318 		  scn->flags |= changed;
319 		}
320 
321 	      /* Check that the section size is actually a multiple of
322 		 the entry size.  */
323 	      if (shdr->sh_entsize != 0
324 		  && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
325 		  && (elf->flags & ELF_F_PERMISSIVE) == 0)
326 		{
327 		  __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
328 		  return -1;
329 		}
330 	    }
331 
332 	  assert (list->next == NULL || list->cnt == list->max);
333 
334 	  first = false;
335 	}
336       while ((list = list->next) != NULL);
337 
338       /* Store section information.  */
339       if (elf->flags & ELF_F_LAYOUT)
340 	{
341 	  /* The user is supposed to fill out e_phoff.  Use it and
342 	     e_phnum to determine the maximum extend.  */
343 	  size = MAX ((GElf_Word) size,
344 		      (ehdr->e_shoff
345 		       + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
346 	}
347       else
348 	{
349 	  /* Align for section header table.
350 
351 	     Yes, we use `sizeof' and not `__alignof__' since we do not
352 	     want to be surprised by architectures with less strict
353 	     alignment rules.  */
354 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
355 	  size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
356 
357 	  update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
358 	  update_if_changed (ehdr->e_shentsize,
359 			     elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
360 			     ehdr_flags);
361 
362 	  /* Account for the section header size.  */
363 	  size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
364 	}
365     }
366 
367   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
368 
369   return size;
370 }
371