• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Create new ELF program header table.
2    Copyright (C) 1999-2010, 2014, 2015 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of either
8 
9      * the GNU Lesser General Public License as published by the Free
10        Software Foundation; either version 3 of the License, or (at
11        your option) any later version
12 
13    or
14 
15      * the GNU General Public License as published by the Free
16        Software Foundation; either version 2 of the License, or (at
17        your option) any later version
18 
19    or both in parallel, as here.
20 
21    elfutils is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25 
26    You should have received copies of the GNU General Public License and
27    the GNU Lesser General Public License along with this program.  If
28    not, see <http://www.gnu.org/licenses/>.  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33 
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "libelfP.h"
39 
40 #ifndef LIBELFBITS
41 # define LIBELFBITS 32
42 #endif
43 
44 
ElfW2(LIBELFBITS,Phdr)45 ElfW2(LIBELFBITS,Phdr) *
46 elfw2(LIBELFBITS,newphdr) (Elf *elf, size_t count)
47 {
48   ElfW2(LIBELFBITS,Phdr) *result;
49 
50   if (elf == NULL)
51     return NULL;
52 
53   if (unlikely (elf->kind != ELF_K_ELF))
54     {
55       __libelf_seterrno (ELF_E_INVALID_HANDLE);
56       return NULL;
57     }
58 
59   /* This check is correct, it is for sh_info, which is either
60      Elf32_Word or Elf64_Word, both being 32 bits.  But count is size_t
61      so might not fit on 32bit ELF files.  */
62   if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count))
63     {
64       __libelf_seterrno (ELF_E_INVALID_OPERAND);
65       return NULL;
66     }
67 
68   rwlock_wrlock (elf->lock);
69 
70   if (elf->class == 0)
71     elf->class = ELFW(ELFCLASS,LIBELFBITS);
72   else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS)))
73     {
74       __libelf_seterrno (ELF_E_INVALID_CLASS);
75       result = NULL;
76       goto out;
77     }
78 
79   if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL))
80     {
81       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
82       result = NULL;
83       goto out;
84     }
85 
86   /* A COUNT of zero means remove existing table.  */
87   if (count == 0)
88     {
89       /* Free the old program header.  */
90       if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
91 	{
92 	  if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED)
93 	    free (elf->state.ELFW(elf,LIBELFBITS).phdr);
94 
95 	  /* Set the pointer to NULL.  */
96 	  elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
97 	  /* Set the `e_phnum' member to the new value.  */
98 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0;
99 	  /* Also clear any old PN_XNUM extended value.  */
100 	  if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0)
101 	    elf->state.ELFW(elf,LIBELFBITS).scns.data[0]
102 	      .shdr.ELFW(e,LIBELFBITS)->sh_info = 0;
103 	  /* Also set the size.  */
104 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
105 	    sizeof (ElfW2(LIBELFBITS,Phdr));
106 
107 	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
108 	  elf->flags |= ELF_F_DIRTY;
109 	  __libelf_seterrno (ELF_E_NOERROR);
110 	}
111 
112       result = NULL;
113     }
114   else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count
115 	   || count == PN_XNUM
116 	   || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
117     {
118       if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))))
119 	{
120 	  __libelf_seterrno (ELF_E_INVALID_INDEX);
121 	  result = NULL;
122 	  goto out;
123 	}
124 
125       Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
126       if (unlikely (count >= PN_XNUM && scn0->shdr.ELFW(e,LIBELFBITS) == NULL))
127 	{
128 	  /* Something is wrong with section zero, but we need it to write
129 	     the extended phdr count.  */
130 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
131 	  result = NULL;
132 	  goto out;
133 	}
134 
135       /* Allocate a new program header with the appropriate number of
136 	 elements.  */
137       result = (ElfW2(LIBELFBITS,Phdr) *)
138 	realloc (elf->state.ELFW(elf,LIBELFBITS).phdr,
139 		 count * sizeof (ElfW2(LIBELFBITS,Phdr)));
140       if (result == NULL)
141 	__libelf_seterrno (ELF_E_NOMEM);
142       else
143 	{
144 	  /* Now set the result.  */
145 	  elf->state.ELFW(elf,LIBELFBITS).phdr = result;
146 	  if (count >= PN_XNUM)
147 	    {
148 	      /* We have to write COUNT into the zeroth section's sh_info.  */
149 	      if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0)
150 		{
151 		  assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0);
152 		  elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1;
153 		}
154 	      scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count;
155 	      scn0->shdr_flags |= ELF_F_DIRTY;
156 	      elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM;
157 	    }
158 	  else
159 	    /* Set the `e_phnum' member to the new value.  */
160 	    elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count;
161 	  /* Clear the whole memory.  */
162 	  memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
163 	  /* Also set the size.  */
164 	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
165 	    elf_typesize (LIBELFBITS, ELF_T_PHDR, 1);
166 	  /* Remember we allocated the array and mark the structure is
167 	     modified.  */
168 	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
169 	    ELF_F_DIRTY | ELF_F_MALLOCED;
170 	  /* We have to rewrite the entire file if the size of the
171 	     program header is changed.  */
172 	  elf->flags |= ELF_F_DIRTY;
173 	}
174     }
175   else
176     {
177       /* We have the same number of entries.  Just clear the array.  */
178       assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize
179 	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
180 
181       /* Mark the structure as modified.  */
182       elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
183 
184       result = elf->state.ELFW(elf,LIBELFBITS).phdr;
185       memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
186     }
187 
188  out:
189   rwlock_unlock (elf->lock);
190 
191   return result;
192 }
193 INTDEF(elfw2(LIBELFBITS,newphdr))
194