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