File: | src/lib/libelf/elf_update.c |
Warning: | line 1048, column 2 Value stored to 'nrc' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /*- |
2 | * Copyright (c) 2006-2011 Joseph Koshy |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
24 | * SUCH DAMAGE. |
25 | */ |
26 | |
27 | #include <sys/stat.h> |
28 | |
29 | #include <assert.h> |
30 | #include <errno(*__errno()).h> |
31 | #include <gelf.h> |
32 | #include <libelf.h> |
33 | #include <stdlib.h> |
34 | #include <string.h> |
35 | #include <unistd.h> |
36 | |
37 | #include "_libelf.h" |
38 | |
39 | #if ELFTC_HAVE_MMAP1 |
40 | #include <sys/mman.h> |
41 | #endif |
42 | |
43 | ELFTC_VCSID("$Id: elf_update.c,v 1.4 2021/09/02 21:12:25 deraadt Exp $")__asm__(".ident\t\"" "$Id: elf_update.c,v 1.4 2021/09/02 21:12:25 deraadt Exp $" "\""); |
44 | |
45 | /* |
46 | * Layout strategy: |
47 | * |
48 | * - Case 1: ELF_F_LAYOUT is asserted |
49 | * In this case the application has full control over where the |
50 | * section header table, program header table, and section data |
51 | * will reside. The library only perform error checks. |
52 | * |
53 | * - Case 2: ELF_F_LAYOUT is not asserted |
54 | * |
55 | * The library will do the object layout using the following |
56 | * ordering: |
57 | * - The executable header is placed first, are required by the |
58 | * ELF specification. |
59 | * - The program header table is placed immediately following the |
60 | * executable header. |
61 | * - Section data, if any, is placed after the program header |
62 | * table, aligned appropriately. |
63 | * - The section header table, if needed, is placed last. |
64 | * |
65 | * There are two sub-cases to be taken care of: |
66 | * |
67 | * - Case 2a: e->e_cmd == ELF_C_READ or ELF_C_RDWR |
68 | * |
69 | * In this sub-case, the underlying ELF object may already have |
70 | * content in it, which the application may have modified. The |
71 | * library will retrieve content from the existing object as |
72 | * needed. |
73 | * |
74 | * - Case 2b: e->e_cmd == ELF_C_WRITE |
75 | * |
76 | * The ELF object is being created afresh in this sub-case; |
77 | * there is no pre-existing content in the underlying ELF |
78 | * object. |
79 | */ |
80 | |
81 | /* |
82 | * The types of extents in an ELF object. |
83 | */ |
84 | enum elf_extent { |
85 | ELF_EXTENT_EHDR, |
86 | ELF_EXTENT_PHDR, |
87 | ELF_EXTENT_SECTION, |
88 | ELF_EXTENT_SHDR |
89 | }; |
90 | |
91 | /* |
92 | * A extent descriptor, used when laying out an ELF object. |
93 | */ |
94 | struct _Elf_Extent { |
95 | SLIST_ENTRY(_Elf_Extent)struct { struct _Elf_Extent *sle_next; } ex_next; |
96 | uint64_t ex_start; /* Start of the region. */ |
97 | uint64_t ex_size; /* The size of the region. */ |
98 | enum elf_extent ex_type; /* Type of region. */ |
99 | void *ex_desc; /* Associated descriptor. */ |
100 | }; |
101 | |
102 | SLIST_HEAD(_Elf_Extent_List, _Elf_Extent)struct _Elf_Extent_List { struct _Elf_Extent *slh_first; }; |
103 | |
104 | /* |
105 | * Compute the extents of a section, by looking at the data |
106 | * descriptors associated with it. The function returns 1 |
107 | * if successful, or zero if an error was detected. |
108 | */ |
109 | static int |
110 | _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t rc) |
111 | { |
112 | Elf_Data *d; |
113 | size_t fsz, msz; |
114 | int ec, elftype; |
115 | uint32_t sh_type; |
116 | uint64_t d_align; |
117 | Elf32_Shdr *shdr32; |
118 | Elf64_Shdr *shdr64; |
119 | struct _Libelf_Data *ld; |
120 | uint64_t scn_size, scn_alignment; |
121 | uint64_t sh_align, sh_entsize, sh_offset, sh_size; |
122 | |
123 | ec = e->e_class; |
124 | |
125 | shdr32 = &s->s_shdr.s_shdr32; |
126 | shdr64 = &s->s_shdr.s_shdr64; |
127 | if (ec == ELFCLASS321) { |
128 | sh_type = shdr32->sh_type; |
129 | sh_align = (uint64_t) shdr32->sh_addralign; |
130 | sh_entsize = (uint64_t) shdr32->sh_entsize; |
131 | sh_offset = (uint64_t) shdr32->sh_offset; |
132 | sh_size = (uint64_t) shdr32->sh_size; |
133 | } else { |
134 | sh_type = shdr64->sh_type; |
135 | sh_align = shdr64->sh_addralign; |
136 | sh_entsize = shdr64->sh_entsize; |
137 | sh_offset = shdr64->sh_offset; |
138 | sh_size = shdr64->sh_size; |
139 | } |
140 | |
141 | assert(sh_type != SHT_NULL && sh_type != SHT_NOBITS)((sh_type != 0 && sh_type != 8) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 141, __func__, "sh_type != SHT_NULL && sh_type != SHT_NOBITS" )); |
142 | |
143 | elftype = _libelf_xlate_shtype(sh_type); |
144 | if (elftype < ELF_T_FIRSTELF_T_ADDR || elftype > ELF_T_LASTELF_T_GNUHASH) { |
145 | LIBELF_SET_ERROR(SECTION, 0)do { (_libelf.libelf_error) = (((ELF_E_SECTION) & 0xFF) | (((0)) << 8)); } while (0); |
146 | return (0); |
147 | } |
148 | |
149 | if (sh_align == 0) |
150 | sh_align = _libelf_falign(elftype, ec); |
151 | |
152 | /* |
153 | * Compute the section's size and alignment using the data |
154 | * descriptors associated with the section. |
155 | */ |
156 | if (STAILQ_EMPTY(&s->s_data)(((&s->s_data)->stqh_first) == ((void *)0))) { |
157 | /* |
158 | * The section's content (if any) has not been read in |
159 | * yet. If section is not dirty marked dirty, we can |
160 | * reuse the values in the 'sh_size' and 'sh_offset' |
161 | * fields of the section header. |
162 | */ |
163 | if ((s->s_flags & ELF_F_DIRTY0x002U) == 0) { |
164 | /* |
165 | * If the library is doing the layout, then we |
166 | * compute the new start offset for the |
167 | * section based on the current offset and the |
168 | * section's alignment needs. |
169 | * |
170 | * If the application is doing the layout, we |
171 | * can use the value in the 'sh_offset' field |
172 | * in the section header directly. |
173 | */ |
174 | if (e->e_flags & ELF_F_LAYOUT0x001U) |
175 | goto updatedescriptor; |
176 | else |
177 | goto computeoffset; |
178 | } |
179 | |
180 | /* |
181 | * Otherwise, we need to bring in the section's data |
182 | * from the underlying ELF object. |
183 | */ |
184 | if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL((void *)0)) == NULL((void *)0)) |
185 | return (0); |
186 | } |
187 | |
188 | /* |
189 | * Loop through the section's data descriptors. |
190 | */ |
191 | scn_size = 0L; |
192 | scn_alignment = 0; |
193 | STAILQ_FOREACH(ld, &s->s_data, d_next)for ((ld) = ((&s->s_data)->stqh_first); (ld) != ((void *)0); (ld) = ((ld)->d_next.stqe_next)) { |
194 | |
195 | d = &ld->d_data; |
196 | |
197 | /* |
198 | * The data buffer's type is known. |
199 | */ |
200 | if (d->d_type >= ELF_T_NUM) { |
201 | LIBELF_SET_ERROR(DATA, 0)do { (_libelf.libelf_error) = (((ELF_E_DATA) & 0xFF) | (( (0)) << 8)); } while (0); |
202 | return (0); |
203 | } |
204 | |
205 | /* |
206 | * The data buffer's version is supported. |
207 | */ |
208 | if (d->d_version != e->e_version) { |
209 | LIBELF_SET_ERROR(VERSION, 0)do { (_libelf.libelf_error) = (((ELF_E_VERSION) & 0xFF) | (((0)) << 8)); } while (0); |
210 | return (0); |
211 | } |
212 | |
213 | /* |
214 | * The buffer's alignment is non-zero and a power of |
215 | * two. |
216 | */ |
217 | if ((d_align = d->d_align) == 0 || |
218 | (d_align & (d_align - 1))) { |
219 | LIBELF_SET_ERROR(DATA, 0)do { (_libelf.libelf_error) = (((ELF_E_DATA) & 0xFF) | (( (0)) << 8)); } while (0); |
220 | return (0); |
221 | } |
222 | |
223 | /* |
224 | * The data buffer's ELF type, ELF class and ELF version |
225 | * should be supported. |
226 | */ |
227 | if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0) |
228 | return (0); |
229 | |
230 | /* |
231 | * The buffer's size should be a multiple of the |
232 | * memory size of the underlying type. |
233 | */ |
234 | if (d->d_size % msz) { |
235 | LIBELF_SET_ERROR(DATA, 0)do { (_libelf.libelf_error) = (((ELF_E_DATA) & 0xFF) | (( (0)) << 8)); } while (0); |
236 | return (0); |
237 | } |
238 | |
239 | /* |
240 | * If the application is controlling layout, then the |
241 | * d_offset field should be compatible with the |
242 | * buffer's specified alignment. |
243 | */ |
244 | if ((e->e_flags & ELF_F_LAYOUT0x001U) && |
245 | (d->d_off & (d_align - 1))) { |
246 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
247 | return (0); |
248 | } |
249 | |
250 | /* |
251 | * Compute the section's size. |
252 | */ |
253 | if (e->e_flags & ELF_F_LAYOUT0x001U) { |
254 | if ((uint64_t) d->d_off + d->d_size > scn_size) |
255 | scn_size = d->d_off + d->d_size; |
256 | } else { |
257 | scn_size = roundup2(scn_size, d->d_align)((((scn_size)+((d->d_align)-1))/(d->d_align))*(d->d_align )); |
258 | d->d_off = scn_size; |
259 | fsz = _libelf_fsize(d->d_type, ec, d->d_version, |
260 | (size_t) d->d_size / msz); |
261 | scn_size += fsz; |
262 | } |
263 | |
264 | /* |
265 | * The section's alignment is the maximum alignment |
266 | * needed for its data buffers. |
267 | */ |
268 | if (d_align > scn_alignment) |
269 | scn_alignment = d_align; |
270 | } |
271 | |
272 | |
273 | /* |
274 | * If the application is requesting full control over the |
275 | * layout of the section, check the section's specified size, |
276 | * offsets and alignment for sanity. |
277 | */ |
278 | if (e->e_flags & ELF_F_LAYOUT0x001U) { |
279 | if (scn_alignment > sh_align || |
280 | sh_offset % sh_align || |
281 | sh_size < scn_size || |
282 | sh_offset % _libelf_falign(elftype, ec)) { |
283 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
284 | return (0); |
285 | } |
286 | goto updatedescriptor; |
287 | } |
288 | |
289 | /* |
290 | * Otherwise, compute the values in the section header. |
291 | * |
292 | * The section alignment is the maximum alignment for any of |
293 | * its contained data descriptors. |
294 | */ |
295 | if (scn_alignment > sh_align) |
296 | sh_align = scn_alignment; |
297 | |
298 | /* |
299 | * If the section entry size is zero, try and fill in an |
300 | * appropriate entry size. Per the elf(5) manual page |
301 | * sections without fixed-size entries should have their |
302 | * 'sh_entsize' field set to zero. |
303 | */ |
304 | if (sh_entsize == 0 && |
305 | (sh_entsize = _libelf_fsize(elftype, ec, e->e_version, |
306 | (size_t) 1)) == 1) |
307 | sh_entsize = 0; |
308 | |
309 | sh_size = scn_size; |
310 | |
311 | computeoffset: |
312 | /* |
313 | * Compute the new offset for the section based on |
314 | * the section's alignment needs. |
315 | */ |
316 | sh_offset = roundup((uint64_t) rc, sh_align)(((((uint64_t) rc)+((sh_align)-1))/(sh_align))*(sh_align)); |
317 | |
318 | /* |
319 | * Update the section header. |
320 | */ |
321 | if (ec == ELFCLASS321) { |
322 | shdr32->sh_addralign = (uint32_t) sh_align; |
323 | shdr32->sh_entsize = (uint32_t) sh_entsize; |
324 | shdr32->sh_offset = (uint32_t) sh_offset; |
325 | shdr32->sh_size = (uint32_t) sh_size; |
326 | } else { |
327 | shdr64->sh_addralign = sh_align; |
328 | shdr64->sh_entsize = sh_entsize; |
329 | shdr64->sh_offset = sh_offset; |
330 | shdr64->sh_size = sh_size; |
331 | } |
332 | |
333 | updatedescriptor: |
334 | /* |
335 | * Update the section descriptor. |
336 | */ |
337 | s->s_size = sh_size; |
338 | s->s_offset = sh_offset; |
339 | |
340 | return (1); |
341 | } |
342 | |
343 | /* |
344 | * Free a list of extent descriptors. |
345 | */ |
346 | |
347 | static void |
348 | _libelf_release_extents(struct _Elf_Extent_List *extents) |
349 | { |
350 | struct _Elf_Extent *ex; |
351 | |
352 | while ((ex = SLIST_FIRST(extents)((extents)->slh_first)) != NULL((void *)0)) { |
353 | SLIST_REMOVE_HEAD(extents, ex_next)do { (extents)->slh_first = (extents)->slh_first->ex_next .sle_next; } while (0); |
354 | free(ex); |
355 | } |
356 | } |
357 | |
358 | /* |
359 | * Check if an extent 's' defined by [start..start+size) is free. |
360 | * This routine assumes that the given extent list is sorted in order |
361 | * of ascending extent offsets. |
362 | */ |
363 | |
364 | static int |
365 | _libelf_extent_is_unused(struct _Elf_Extent_List *extents, |
366 | const uint64_t start, const uint64_t size, struct _Elf_Extent **prevt) |
367 | { |
368 | uint64_t tmax, tmin; |
369 | struct _Elf_Extent *t, *pt; |
370 | const uint64_t smax = start + size; |
371 | |
372 | /* First, look for overlaps with existing extents. */ |
373 | pt = NULL((void *)0); |
374 | SLIST_FOREACH(t, extents, ex_next)for((t) = ((extents)->slh_first); (t) != ((void *)0); (t) = ((t)->ex_next.sle_next)) { |
375 | tmin = t->ex_start; |
376 | tmax = tmin + t->ex_size; |
377 | |
378 | if (tmax <= start) { |
379 | /* |
380 | * 't' lies entirely before 's': ...| t |...| s |... |
381 | */ |
382 | pt = t; |
383 | continue; |
384 | } else if (smax <= tmin) { |
385 | /* |
386 | * 's' lies entirely before 't', and after 'pt': |
387 | * ...| pt |...| s |...| t |... |
388 | */ |
389 | assert(pt == NULL ||((pt == ((void *)0) || pt->ex_start + pt->ex_size <= start) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 390, __func__, "pt == NULL || pt->ex_start + pt->ex_size <= start" )) |
390 | pt->ex_start + pt->ex_size <= start)((pt == ((void *)0) || pt->ex_start + pt->ex_size <= start) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 390, __func__, "pt == NULL || pt->ex_start + pt->ex_size <= start" )); |
391 | break; |
392 | } else |
393 | /* 's' and 't' overlap. */ |
394 | return (0); |
395 | } |
396 | |
397 | if (prevt) |
398 | *prevt = pt; |
399 | return (1); |
400 | } |
401 | |
402 | /* |
403 | * Insert an extent into the list of extents. |
404 | */ |
405 | |
406 | static int |
407 | _libelf_insert_extent(struct _Elf_Extent_List *extents, int type, |
408 | uint64_t start, uint64_t size, void *desc) |
409 | { |
410 | struct _Elf_Extent *ex, *prevt; |
411 | |
412 | assert(type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR)((type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR ) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 412 , __func__, "type >= ELF_EXTENT_EHDR && type <= ELF_EXTENT_SHDR" )); |
413 | |
414 | prevt = NULL((void *)0); |
415 | |
416 | /* |
417 | * If the requested range overlaps with an existing extent, |
418 | * signal an error. |
419 | */ |
420 | if (!_libelf_extent_is_unused(extents, start, size, &prevt)) { |
421 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
422 | return (0); |
423 | } |
424 | |
425 | /* Allocate and fill in a new extent descriptor. */ |
426 | if ((ex = malloc(sizeof(struct _Elf_Extent))) == NULL((void *)0)) { |
427 | LIBELF_SET_ERROR(RESOURCE, errno)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | ((((*__errno()))) << 8)); } while (0); |
428 | return (0); |
429 | } |
430 | ex->ex_start = start; |
431 | ex->ex_size = size; |
432 | ex->ex_desc = desc; |
433 | ex->ex_type = type; |
434 | |
435 | /* Insert the region descriptor into the list. */ |
436 | if (prevt) |
437 | SLIST_INSERT_AFTER(prevt, ex, ex_next)do { (ex)->ex_next.sle_next = (prevt)->ex_next.sle_next ; (prevt)->ex_next.sle_next = (ex); } while (0); |
438 | else |
439 | SLIST_INSERT_HEAD(extents, ex, ex_next)do { (ex)->ex_next.sle_next = (extents)->slh_first; (extents )->slh_first = (ex); } while (0); |
440 | return (1); |
441 | } |
442 | |
443 | /* |
444 | * Recompute section layout. |
445 | */ |
446 | |
447 | static off_t |
448 | _libelf_resync_sections(Elf *e, off_t rc, struct _Elf_Extent_List *extents) |
449 | { |
450 | int ec; |
451 | Elf_Scn *s; |
452 | size_t sh_type; |
453 | |
454 | ec = e->e_class; |
455 | |
456 | /* |
457 | * Make a pass through sections, computing the extent of each |
458 | * section. |
459 | */ |
460 | STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next)for ((s) = ((&e->e_u.e_elf.e_scn)->stqh_first); (s) != ((void *)0); (s) = ((s)->s_next.stqe_next)) { |
461 | if (ec == ELFCLASS321) |
462 | sh_type = s->s_shdr.s_shdr32.sh_type; |
463 | else |
464 | sh_type = s->s_shdr.s_shdr64.sh_type; |
465 | |
466 | if (sh_type == SHT_NOBITS8 || sh_type == SHT_NULL0) |
467 | continue; |
468 | |
469 | if (_libelf_compute_section_extents(e, s, rc) == 0) |
470 | return ((off_t) -1); |
471 | |
472 | if (s->s_size == 0) |
473 | continue; |
474 | |
475 | if (!_libelf_insert_extent(extents, ELF_EXTENT_SECTION, |
476 | s->s_offset, s->s_size, s)) |
477 | return ((off_t) -1); |
478 | |
479 | if ((size_t) rc < s->s_offset + s->s_size) |
480 | rc = (off_t) (s->s_offset + s->s_size); |
481 | } |
482 | |
483 | return (rc); |
484 | } |
485 | |
486 | /* |
487 | * Recompute the layout of the ELF object and update the internal data |
488 | * structures associated with the ELF descriptor. |
489 | * |
490 | * Returns the size in bytes the ELF object would occupy in its file |
491 | * representation. |
492 | * |
493 | * After a successful call to this function, the following structures |
494 | * are updated: |
495 | * |
496 | * - The ELF header is updated. |
497 | * - All extents in the ELF object are sorted in order of ascending |
498 | * addresses. Sections have their section header table entries |
499 | * updated. An error is signalled if an overlap was detected among |
500 | * extents. |
501 | * - Data descriptors associated with sections are checked for valid |
502 | * types, offsets and alignment. |
503 | * |
504 | * After a resync_elf() successfully returns, the ELF descriptor is |
505 | * ready for being handed over to _libelf_write_elf(). |
506 | */ |
507 | |
508 | static off_t |
509 | _libelf_resync_elf(Elf *e, struct _Elf_Extent_List *extents) |
510 | { |
511 | int ec, eh_class; |
512 | unsigned int eh_byteorder, eh_version; |
513 | size_t align, fsz; |
514 | size_t phnum, shnum; |
515 | off_t rc, phoff, shoff; |
516 | void *ehdr, *phdr; |
517 | Elf32_Ehdr *eh32; |
518 | Elf64_Ehdr *eh64; |
519 | |
520 | rc = 0; |
521 | |
522 | ec = e->e_class; |
523 | |
524 | assert(ec == ELFCLASS32 || ec == ELFCLASS64)((ec == 1 || ec == 2) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 524, __func__, "ec == ELFCLASS32 || ec == ELFCLASS64")); |
525 | |
526 | /* |
527 | * Prepare the EHDR. |
528 | */ |
529 | if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL((void *)0)) |
530 | return ((off_t) -1); |
531 | |
532 | eh32 = ehdr; |
533 | eh64 = ehdr; |
534 | |
535 | if (ec == ELFCLASS321) { |
536 | eh_byteorder = eh32->e_ident[EI_DATA5]; |
537 | eh_class = eh32->e_ident[EI_CLASS4]; |
538 | phoff = (off_t) eh32->e_phoff; |
539 | shoff = (off_t) eh32->e_shoff; |
540 | eh_version = eh32->e_version; |
541 | } else { |
542 | eh_byteorder = eh64->e_ident[EI_DATA5]; |
543 | eh_class = eh64->e_ident[EI_CLASS4]; |
544 | phoff = (off_t) eh64->e_phoff; |
545 | shoff = (off_t) eh64->e_shoff; |
546 | eh_version = eh64->e_version; |
547 | } |
548 | |
549 | if (phoff < 0 || shoff < 0) { |
550 | LIBELF_SET_ERROR(HEADER, 0)do { (_libelf.libelf_error) = (((ELF_E_HEADER) & 0xFF) | ( ((0)) << 8)); } while (0); |
551 | return ((off_t) -1); |
552 | } |
553 | |
554 | if (eh_version == EV_NONE0) |
555 | eh_version = EV_CURRENT1; |
556 | |
557 | if (eh_version != e->e_version) { /* always EV_CURRENT */ |
558 | LIBELF_SET_ERROR(VERSION, 0)do { (_libelf.libelf_error) = (((ELF_E_VERSION) & 0xFF) | (((0)) << 8)); } while (0); |
559 | return ((off_t) -1); |
560 | } |
561 | |
562 | if (eh_class != e->e_class) { |
563 | LIBELF_SET_ERROR(CLASS, 0)do { (_libelf.libelf_error) = (((ELF_E_CLASS) & 0xFF) | ( ((0)) << 8)); } while (0); |
564 | return ((off_t) -1); |
565 | } |
566 | |
567 | if (e->e_cmd != ELF_C_WRITE && eh_byteorder != e->e_byteorder) { |
568 | LIBELF_SET_ERROR(HEADER, 0)do { (_libelf.libelf_error) = (((ELF_E_HEADER) & 0xFF) | ( ((0)) << 8)); } while (0); |
569 | return ((off_t) -1); |
570 | } |
571 | |
572 | shnum = e->e_u.e_elf.e_nscn; |
573 | phnum = e->e_u.e_elf.e_nphdr; |
574 | |
575 | e->e_byteorder = eh_byteorder; |
576 | |
577 | #define INITIALIZE_EHDR(E,EC,V)do { unsigned int _version = (unsigned int) (V); (E)->e_ident [0] = 0x7f; (E)->e_ident[1] = 'E'; (E)->e_ident[2] = 'L' ; (E)->e_ident[3] = 'F'; (E)->e_ident[4] = (unsigned char ) (EC); (E)->e_ident[6] = (_version & 0xFFU); (E)-> e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR, (EC), _version , (size_t) 1); (E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : _libelf_fsize(ELF_T_PHDR, (EC), _version, (size_t) 1)) ; (E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR, ( EC), _version, (size_t) 1); } while (0) do { \ |
578 | unsigned int _version = (unsigned int) (V); \ |
579 | (E)->e_ident[EI_MAG00] = ELFMAG00x7f; \ |
580 | (E)->e_ident[EI_MAG11] = ELFMAG1'E'; \ |
581 | (E)->e_ident[EI_MAG22] = ELFMAG2'L'; \ |
582 | (E)->e_ident[EI_MAG33] = ELFMAG3'F'; \ |
583 | (E)->e_ident[EI_CLASS4] = (unsigned char) (EC); \ |
584 | (E)->e_ident[EI_VERSION6] = (_version & 0xFFU); \ |
585 | (E)->e_ehsize = (uint16_t) _libelf_fsize(ELF_T_EHDR, \ |
586 | (EC), _version, (size_t) 1); \ |
587 | (E)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : \ |
588 | _libelf_fsize(ELF_T_PHDR, (EC), _version, \ |
589 | (size_t) 1)); \ |
590 | (E)->e_shentsize = (uint16_t) _libelf_fsize(ELF_T_SHDR, \ |
591 | (EC), _version, (size_t) 1); \ |
592 | } while (0) |
593 | |
594 | if (ec == ELFCLASS321) |
595 | INITIALIZE_EHDR(eh32, ec, eh_version)do { unsigned int _version = (unsigned int) (eh_version); (eh32 )->e_ident[0] = 0x7f; (eh32)->e_ident[1] = 'E'; (eh32)-> e_ident[2] = 'L'; (eh32)->e_ident[3] = 'F'; (eh32)->e_ident [4] = (unsigned char) (ec); (eh32)->e_ident[6] = (_version & 0xFFU); (eh32)->e_ehsize = (uint16_t) _libelf_fsize (ELF_T_EHDR, (ec), _version, (size_t) 1); (eh32)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : _libelf_fsize(ELF_T_PHDR, ( ec), _version, (size_t) 1)); (eh32)->e_shentsize = (uint16_t ) _libelf_fsize(ELF_T_SHDR, (ec), _version, (size_t) 1); } while (0); |
596 | else |
597 | INITIALIZE_EHDR(eh64, ec, eh_version)do { unsigned int _version = (unsigned int) (eh_version); (eh64 )->e_ident[0] = 0x7f; (eh64)->e_ident[1] = 'E'; (eh64)-> e_ident[2] = 'L'; (eh64)->e_ident[3] = 'F'; (eh64)->e_ident [4] = (unsigned char) (ec); (eh64)->e_ident[6] = (_version & 0xFFU); (eh64)->e_ehsize = (uint16_t) _libelf_fsize (ELF_T_EHDR, (ec), _version, (size_t) 1); (eh64)->e_phentsize = (uint16_t) ((phnum == 0) ? 0 : _libelf_fsize(ELF_T_PHDR, ( ec), _version, (size_t) 1)); (eh64)->e_shentsize = (uint16_t ) _libelf_fsize(ELF_T_SHDR, (ec), _version, (size_t) 1); } while (0); |
598 | |
599 | (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY0x002U); |
600 | |
601 | rc += (off_t) _libelf_fsize(ELF_T_EHDR, ec, eh_version, (size_t) 1); |
602 | |
603 | if (!_libelf_insert_extent(extents, ELF_EXTENT_EHDR, 0, (uint64_t) rc, |
604 | ehdr)) |
605 | return ((off_t) -1); |
606 | |
607 | /* |
608 | * Compute the layout the program header table, if one is |
609 | * present. The program header table needs to be aligned to a |
610 | * `natural' boundary. |
611 | */ |
612 | if (phnum) { |
613 | fsz = _libelf_fsize(ELF_T_PHDR, ec, eh_version, phnum); |
614 | align = _libelf_falign(ELF_T_PHDR, ec); |
615 | |
616 | if (e->e_flags & ELF_F_LAYOUT0x001U) { |
617 | /* |
618 | * Check offsets for sanity. |
619 | */ |
620 | if (rc > phoff) { |
621 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
622 | return ((off_t) -1); |
623 | } |
624 | |
625 | if (phoff % (off_t) align) { |
626 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
627 | return ((off_t) -1); |
628 | } |
629 | |
630 | } else |
631 | phoff = roundup(rc, (off_t) align)((((rc)+(((off_t) align)-1))/((off_t) align))*((off_t) align) ); |
632 | |
633 | rc = phoff + (off_t) fsz; |
634 | |
635 | phdr = _libelf_getphdr(e, ec); |
636 | |
637 | if (!_libelf_insert_extent(extents, ELF_EXTENT_PHDR, |
638 | (uint64_t) phoff, fsz, phdr)) |
639 | return ((off_t) -1); |
640 | } else |
641 | phoff = 0; |
642 | |
643 | /* |
644 | * Compute the layout of the sections associated with the |
645 | * file. |
646 | */ |
647 | |
648 | if (e->e_cmd != ELF_C_WRITE && |
649 | (e->e_flags & LIBELF_F_SHDRS_LOADED0x200000U) == 0 && |
650 | _libelf_load_section_headers(e, ehdr) == 0) |
651 | return ((off_t) -1); |
652 | |
653 | if ((rc = _libelf_resync_sections(e, rc, extents)) < 0) |
654 | return ((off_t) -1); |
655 | |
656 | /* |
657 | * Compute the space taken up by the section header table, if |
658 | * one is needed. |
659 | * |
660 | * If ELF_F_LAYOUT has been asserted, the application may have |
661 | * placed the section header table in between existing |
662 | * sections, so the net size of the file need not increase due |
663 | * to the presence of the section header table. |
664 | * |
665 | * If the library is responsible for laying out the object, |
666 | * the section header table is placed after section data. |
667 | */ |
668 | if (shnum) { |
669 | fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, shnum); |
670 | align = _libelf_falign(ELF_T_SHDR, ec); |
671 | |
672 | if (e->e_flags & ELF_F_LAYOUT0x001U) { |
673 | if (shoff % (off_t) align) { |
674 | LIBELF_SET_ERROR(LAYOUT, 0)do { (_libelf.libelf_error) = (((ELF_E_LAYOUT) & 0xFF) | ( ((0)) << 8)); } while (0); |
675 | return ((off_t) -1); |
676 | } |
677 | } else |
678 | shoff = roundup(rc, (off_t) align)((((rc)+(((off_t) align)-1))/((off_t) align))*((off_t) align) ); |
679 | |
680 | if (shoff + (off_t) fsz > rc) |
681 | rc = shoff + (off_t) fsz; |
682 | |
683 | if (!_libelf_insert_extent(extents, ELF_EXTENT_SHDR, |
684 | (uint64_t) shoff, fsz, NULL((void *)0))) |
685 | return ((off_t) -1); |
686 | } else |
687 | shoff = 0; |
688 | |
689 | /* |
690 | * Set the fields of the Executable Header that could potentially use |
691 | * extended numbering. |
692 | */ |
693 | _libelf_setphnum(e, ehdr, ec, phnum); |
694 | _libelf_setshnum(e, ehdr, ec, shnum); |
695 | |
696 | /* |
697 | * Update the `e_phoff' and `e_shoff' fields if the library is |
698 | * doing the layout. |
699 | */ |
700 | if ((e->e_flags & ELF_F_LAYOUT0x001U) == 0) { |
701 | if (ec == ELFCLASS321) { |
702 | eh32->e_phoff = (uint32_t) phoff; |
703 | eh32->e_shoff = (uint32_t) shoff; |
704 | } else { |
705 | eh64->e_phoff = (uint64_t) phoff; |
706 | eh64->e_shoff = (uint64_t) shoff; |
707 | } |
708 | } |
709 | |
710 | return (rc); |
711 | } |
712 | |
713 | /* |
714 | * Write out the contents of an ELF section. |
715 | */ |
716 | |
717 | static off_t |
718 | _libelf_write_scn(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) |
719 | { |
720 | off_t rc; |
721 | int ec, em; |
722 | Elf_Scn *s; |
723 | int elftype; |
724 | Elf_Data *d, dst; |
725 | uint32_t sh_type; |
726 | struct _Libelf_Data *ld; |
727 | uint64_t sh_off, sh_size; |
728 | size_t fsz, msz, nobjects; |
729 | |
730 | assert(ex->ex_type == ELF_EXTENT_SECTION)((ex->ex_type == ELF_EXTENT_SECTION) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 730, __func__, "ex->ex_type == ELF_EXTENT_SECTION" )); |
731 | |
732 | s = ex->ex_desc; |
733 | rc = (off_t) ex->ex_start; |
734 | |
735 | if ((ec = e->e_class) == ELFCLASS321) { |
736 | sh_type = s->s_shdr.s_shdr32.sh_type; |
737 | sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; |
738 | } else { |
739 | sh_type = s->s_shdr.s_shdr64.sh_type; |
740 | sh_size = s->s_shdr.s_shdr64.sh_size; |
741 | } |
742 | |
743 | /* |
744 | * Ignore sections that do not allocate space in the file. |
745 | */ |
746 | if (sh_type == SHT_NOBITS8 || sh_type == SHT_NULL0 || sh_size == 0) |
747 | return (rc); |
748 | |
749 | elftype = _libelf_xlate_shtype(sh_type); |
750 | assert(elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST)((elftype >= ELF_T_ADDR && elftype <= ELF_T_GNUHASH ) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 750 , __func__, "elftype >= ELF_T_FIRST && elftype <= ELF_T_LAST" )); |
751 | |
752 | sh_off = s->s_offset; |
753 | assert(sh_off % _libelf_falign(elftype, ec) == 0)((sh_off % _libelf_falign(elftype, ec) == 0) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 753, __func__, "sh_off % _libelf_falign(elftype, ec) == 0" )); |
754 | |
755 | em = _libelf_elfmachine(e); |
756 | assert(em >= EM_NONE && em < EM__LAST__)((em >= 0 && em < (0x9026 + 1)) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 756, __func__, "em >= EM_NONE && em < EM__LAST__" )); |
757 | |
758 | /* |
759 | * If the section has a `rawdata' descriptor, and the section |
760 | * contents have not been modified, use its contents directly. |
761 | * The `s_rawoff' member contains the offset into the original |
762 | * file, while `s_offset' contains its new location in the |
763 | * destination. |
764 | */ |
765 | |
766 | if (STAILQ_EMPTY(&s->s_data)(((&s->s_data)->stqh_first) == ((void *)0))) { |
767 | |
768 | if ((d = elf_rawdata(s, NULL((void *)0))) == NULL((void *)0)) |
769 | return ((off_t) -1); |
770 | |
771 | STAILQ_FOREACH(ld, &s->s_rawdata, d_next)for ((ld) = ((&s->s_rawdata)->stqh_first); (ld) != ( (void *)0); (ld) = ((ld)->d_next.stqe_next)) { |
772 | |
773 | d = &ld->d_data; |
774 | |
775 | if ((uint64_t) rc < sh_off + d->d_off) |
776 | (void) memset(nf + rc, |
777 | LIBELF_PRIVATE(fillchar)(_libelf.libelf_fillchar), |
778 | (size_t) (sh_off + d->d_off - |
779 | (uint64_t) rc)); |
780 | rc = (off_t) (sh_off + d->d_off); |
781 | |
782 | assert(d->d_buf != NULL)((d->d_buf != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 782, __func__, "d->d_buf != NULL")); |
783 | assert(d->d_type == ELF_T_BYTE)((d->d_type == ELF_T_BYTE) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 783, __func__, "d->d_type == ELF_T_BYTE")); |
784 | assert(d->d_version == e->e_version)((d->d_version == e->e_version) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 784, __func__, "d->d_version == e->e_version")); |
785 | |
786 | (void) memcpy(nf + rc, |
787 | e->e_rawfile + s->s_rawoff + d->d_off, |
788 | (size_t) d->d_size); |
789 | |
790 | rc += (off_t) d->d_size; |
791 | } |
792 | |
793 | return (rc); |
794 | } |
795 | |
796 | /* |
797 | * Iterate over the set of data descriptors for this section. |
798 | * The prior call to _libelf_resync_elf() would have setup the |
799 | * descriptors for this step. |
800 | */ |
801 | |
802 | dst.d_version = e->e_version; |
803 | |
804 | STAILQ_FOREACH(ld, &s->s_data, d_next)for ((ld) = ((&s->s_data)->stqh_first); (ld) != ((void *)0); (ld) = ((ld)->d_next.stqe_next)) { |
805 | |
806 | d = &ld->d_data; |
807 | |
808 | if ((msz = _libelf_msize(d->d_type, ec, e->e_version)) == 0) |
809 | return ((off_t) -1); |
810 | |
811 | if ((uint64_t) rc < sh_off + d->d_off) |
812 | (void) memset(nf + rc, |
813 | LIBELF_PRIVATE(fillchar)(_libelf.libelf_fillchar), |
814 | (size_t) (sh_off + d->d_off - (uint64_t) rc)); |
815 | |
816 | rc = (off_t) (sh_off + d->d_off); |
817 | |
818 | assert(d->d_buf != NULL)((d->d_buf != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 818, __func__, "d->d_buf != NULL")); |
819 | assert(d->d_version == e->e_version)((d->d_version == e->e_version) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 819, __func__, "d->d_version == e->e_version")); |
820 | assert(d->d_size % msz == 0)((d->d_size % msz == 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 820, __func__, "d->d_size % msz == 0")); |
821 | assert(msz != 0)((msz != 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 821, __func__, "msz != 0")); |
822 | |
823 | nobjects = (size_t) (d->d_size / msz); |
824 | |
825 | fsz = _libelf_fsize(d->d_type, ec, e->e_version, nobjects); |
826 | |
827 | dst.d_buf = nf + rc; |
828 | dst.d_size = fsz; |
829 | |
830 | if (_libelf_xlate(&dst, d, e->e_byteorder, ec, em, ELF_TOFILE) |
831 | == NULL((void *)0)) |
832 | return ((off_t) -1); |
833 | |
834 | rc += (off_t) fsz; |
835 | } |
836 | |
837 | return (rc); |
838 | } |
839 | |
840 | /* |
841 | * Write out an ELF Executable Header. |
842 | */ |
843 | |
844 | static off_t |
845 | _libelf_write_ehdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) |
846 | { |
847 | int ec, em; |
848 | void *ehdr; |
849 | size_t fsz, msz; |
850 | Elf_Data dst, src; |
851 | |
852 | assert(ex->ex_type == ELF_EXTENT_EHDR)((ex->ex_type == ELF_EXTENT_EHDR) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 852, __func__, "ex->ex_type == ELF_EXTENT_EHDR")); |
853 | assert(ex->ex_start == 0)((ex->ex_start == 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 853, __func__, "ex->ex_start == 0")); /* Ehdr always comes first. */ |
854 | |
855 | ec = e->e_class; |
856 | |
857 | ehdr = _libelf_ehdr(e, ec, 0); |
858 | assert(ehdr != NULL)((ehdr != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 858, __func__, "ehdr != NULL")); |
859 | |
860 | fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1); |
861 | if ((msz = _libelf_msize(ELF_T_EHDR, ec, e->e_version)) == 0) |
862 | return ((off_t) -1); |
863 | |
864 | em = _libelf_elfmachine(e); |
865 | |
866 | (void) memset(&dst, 0, sizeof(dst)); |
867 | (void) memset(&src, 0, sizeof(src)); |
868 | |
869 | src.d_buf = ehdr; |
870 | src.d_size = msz; |
871 | src.d_type = ELF_T_EHDR; |
872 | src.d_version = dst.d_version = e->e_version; |
873 | |
874 | dst.d_buf = nf; |
875 | dst.d_size = fsz; |
876 | |
877 | if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) == |
878 | NULL((void *)0)) |
879 | return ((off_t) -1); |
880 | |
881 | return ((off_t) fsz); |
882 | } |
883 | |
884 | /* |
885 | * Write out an ELF program header table. |
886 | */ |
887 | |
888 | static off_t |
889 | _libelf_write_phdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) |
890 | { |
891 | int ec, em; |
892 | void *ehdr; |
893 | Elf32_Ehdr *eh32; |
894 | Elf64_Ehdr *eh64; |
895 | Elf_Data dst, src; |
896 | size_t fsz, msz, phnum; |
897 | uint64_t phoff; |
898 | |
899 | assert(ex->ex_type == ELF_EXTENT_PHDR)((ex->ex_type == ELF_EXTENT_PHDR) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 899, __func__, "ex->ex_type == ELF_EXTENT_PHDR")); |
900 | |
901 | ec = e->e_class; |
902 | |
903 | ehdr = _libelf_ehdr(e, ec, 0); |
904 | assert(ehdr != NULL)((ehdr != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 904, __func__, "ehdr != NULL")); |
905 | |
906 | phnum = e->e_u.e_elf.e_nphdr; |
907 | assert(phnum > 0)((phnum > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 907, __func__, "phnum > 0")); |
908 | |
909 | if (ec == ELFCLASS321) { |
910 | eh32 = (Elf32_Ehdr *) ehdr; |
911 | phoff = (uint64_t) eh32->e_phoff; |
912 | } else { |
913 | eh64 = (Elf64_Ehdr *) ehdr; |
914 | phoff = eh64->e_phoff; |
915 | } |
916 | |
917 | em = _libelf_elfmachine(e); |
918 | |
919 | assert(phoff > 0)((phoff > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 919, __func__, "phoff > 0")); |
920 | assert(ex->ex_start == phoff)((ex->ex_start == phoff) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 920, __func__, "ex->ex_start == phoff")); |
921 | assert(phoff % _libelf_falign(ELF_T_PHDR, ec) == 0)((phoff % _libelf_falign(ELF_T_PHDR, ec) == 0) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 921, __func__, "phoff % _libelf_falign(ELF_T_PHDR, ec) == 0" )); |
922 | |
923 | (void) memset(&dst, 0, sizeof(dst)); |
924 | (void) memset(&src, 0, sizeof(src)); |
925 | |
926 | if ((msz = _libelf_msize(ELF_T_PHDR, ec, e->e_version)) == 0) |
927 | return ((off_t) -1); |
928 | fsz = _libelf_fsize(ELF_T_PHDR, ec, e->e_version, phnum); |
929 | assert(fsz > 0)((fsz > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 929, __func__, "fsz > 0")); |
930 | |
931 | src.d_buf = _libelf_getphdr(e, ec); |
932 | src.d_version = dst.d_version = e->e_version; |
933 | src.d_type = ELF_T_PHDR; |
934 | src.d_size = phnum * msz; |
935 | |
936 | dst.d_size = fsz; |
937 | dst.d_buf = nf + ex->ex_start; |
938 | |
939 | if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, ELF_TOFILE) == |
940 | NULL((void *)0)) |
941 | return ((off_t) -1); |
942 | |
943 | return ((off_t) (phoff + fsz)); |
944 | } |
945 | |
946 | /* |
947 | * Write out an ELF section header table. |
948 | */ |
949 | |
950 | static off_t |
951 | _libelf_write_shdr(Elf *e, unsigned char *nf, struct _Elf_Extent *ex) |
952 | { |
953 | int ec, em; |
954 | void *ehdr; |
955 | Elf_Scn *scn; |
956 | uint64_t shoff; |
957 | Elf32_Ehdr *eh32; |
958 | Elf64_Ehdr *eh64; |
959 | size_t fsz, msz, nscn; |
960 | Elf_Data dst, src; |
961 | |
962 | assert(ex->ex_type == ELF_EXTENT_SHDR)((ex->ex_type == ELF_EXTENT_SHDR) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 962, __func__, "ex->ex_type == ELF_EXTENT_SHDR")); |
963 | |
964 | ec = e->e_class; |
965 | |
966 | ehdr = _libelf_ehdr(e, ec, 0); |
967 | assert(ehdr != NULL)((ehdr != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 967, __func__, "ehdr != NULL")); |
968 | |
969 | nscn = e->e_u.e_elf.e_nscn; |
970 | |
971 | if (ec == ELFCLASS321) { |
972 | eh32 = (Elf32_Ehdr *) ehdr; |
973 | shoff = (uint64_t) eh32->e_shoff; |
974 | } else { |
975 | eh64 = (Elf64_Ehdr *) ehdr; |
976 | shoff = eh64->e_shoff; |
977 | } |
978 | |
979 | em = _libelf_elfmachine(e); |
980 | |
981 | assert(nscn > 0)((nscn > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 981, __func__, "nscn > 0")); |
982 | assert(shoff % _libelf_falign(ELF_T_SHDR, ec) == 0)((shoff % _libelf_falign(ELF_T_SHDR, ec) == 0) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 982, __func__, "shoff % _libelf_falign(ELF_T_SHDR, ec) == 0" )); |
983 | assert(ex->ex_start == shoff)((ex->ex_start == shoff) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 983, __func__, "ex->ex_start == shoff")); |
984 | |
985 | (void) memset(&dst, 0, sizeof(dst)); |
986 | (void) memset(&src, 0, sizeof(src)); |
987 | |
988 | if ((msz = _libelf_msize(ELF_T_SHDR, ec, e->e_version)) == 0) |
989 | return ((off_t) -1); |
990 | |
991 | src.d_type = ELF_T_SHDR; |
992 | src.d_size = msz; |
993 | src.d_version = dst.d_version = e->e_version; |
994 | |
995 | fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1); |
996 | |
997 | STAILQ_FOREACH(scn, &e->e_u.e_elf.e_scn, s_next)for ((scn) = ((&e->e_u.e_elf.e_scn)->stqh_first); ( scn) != ((void *)0); (scn) = ((scn)->s_next.stqe_next)) { |
998 | if (ec == ELFCLASS321) |
999 | src.d_buf = &scn->s_shdr.s_shdr32; |
1000 | else |
1001 | src.d_buf = &scn->s_shdr.s_shdr64; |
1002 | |
1003 | dst.d_size = fsz; |
1004 | dst.d_buf = nf + ex->ex_start + scn->s_ndx * fsz; |
1005 | |
1006 | if (_libelf_xlate(&dst, &src, e->e_byteorder, ec, em, |
1007 | ELF_TOFILE) == NULL((void *)0)) |
1008 | return ((off_t) -1); |
1009 | } |
1010 | |
1011 | return ((off_t) (ex->ex_start + nscn * fsz)); |
1012 | } |
1013 | |
1014 | /* |
1015 | * Write out the file image. |
1016 | * |
1017 | * The original file could have been mapped in with an ELF_C_RDWR |
1018 | * command and the application could have added new content or |
1019 | * re-arranged its sections before calling elf_update(). Consequently |
1020 | * its not safe to work `in place' on the original file. So we |
1021 | * malloc() the required space for the updated ELF object and build |
1022 | * the object there and write it out to the underlying file at the |
1023 | * end. Note that the application may have opened the underlying file |
1024 | * in ELF_C_RDWR and only retrieved/modified a few sections. We take |
1025 | * care to avoid translating file sections unnecessarily. |
1026 | * |
1027 | * Gaps in the coverage of the file by the file's sections will be |
1028 | * filled with the fill character set by elf_fill(3). |
1029 | */ |
1030 | |
1031 | static off_t |
1032 | _libelf_write_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) |
1033 | { |
1034 | off_t nrc, rc; |
1035 | Elf_Scn *scn, *tscn; |
1036 | struct _Elf_Extent *ex; |
1037 | unsigned char *newfile; |
1038 | |
1039 | assert(e->e_kind == ELF_K_ELF)((e->e_kind == ELF_K_ELF) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1039, __func__, "e->e_kind == ELF_K_ELF")); |
1040 | assert(e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE)((e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE) ? ( void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 1040, __func__ , "e->e_cmd == ELF_C_RDWR || e->e_cmd == ELF_C_WRITE")); |
1041 | assert(e->e_fd >= 0)((e->e_fd >= 0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1041, __func__, "e->e_fd >= 0")); |
1042 | |
1043 | if ((newfile = malloc((size_t) newsize)) == NULL((void *)0)) { |
1044 | LIBELF_SET_ERROR(RESOURCE, errno)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | ((((*__errno()))) << 8)); } while (0); |
1045 | return ((off_t) -1); |
1046 | } |
1047 | |
1048 | nrc = rc = 0; |
Value stored to 'nrc' is never read | |
1049 | SLIST_FOREACH(ex, extents, ex_next)for((ex) = ((extents)->slh_first); (ex) != ((void *)0); (ex ) = ((ex)->ex_next.sle_next)) { |
1050 | |
1051 | /* Fill inter-extent gaps. */ |
1052 | if (ex->ex_start > (size_t) rc) |
1053 | (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar)(_libelf.libelf_fillchar), |
1054 | (size_t) (ex->ex_start - (uint64_t) rc)); |
1055 | |
1056 | switch (ex->ex_type) { |
1057 | case ELF_EXTENT_EHDR: |
1058 | if ((nrc = _libelf_write_ehdr(e, newfile, ex)) < 0) |
1059 | goto error; |
1060 | break; |
1061 | |
1062 | case ELF_EXTENT_PHDR: |
1063 | if ((nrc = _libelf_write_phdr(e, newfile, ex)) < 0) |
1064 | goto error; |
1065 | break; |
1066 | |
1067 | case ELF_EXTENT_SECTION: |
1068 | if ((nrc = _libelf_write_scn(e, newfile, ex)) < 0) |
1069 | goto error; |
1070 | break; |
1071 | |
1072 | case ELF_EXTENT_SHDR: |
1073 | if ((nrc = _libelf_write_shdr(e, newfile, ex)) < 0) |
1074 | goto error; |
1075 | break; |
1076 | |
1077 | default: |
1078 | assert(0)((0) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1078, __func__, "0")); |
1079 | break; |
1080 | } |
1081 | |
1082 | assert(ex->ex_start + ex->ex_size == (size_t) nrc)((ex->ex_start + ex->ex_size == (size_t) nrc) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 1082, __func__ , "ex->ex_start + ex->ex_size == (size_t) nrc")); |
1083 | assert(rc < nrc)((rc < nrc) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1083, __func__, "rc < nrc")); |
1084 | |
1085 | rc = nrc; |
1086 | } |
1087 | |
1088 | assert(rc == newsize)((rc == newsize) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1088, __func__, "rc == newsize")); |
1089 | |
1090 | /* |
1091 | * For regular files, throw away existing file content and |
1092 | * unmap any existing mappings. |
1093 | */ |
1094 | if ((e->e_flags & LIBELF_F_SPECIAL_FILE0x400000U) == 0) { |
1095 | if (ftruncate(e->e_fd, (off_t) 0) < 0 || |
1096 | lseek(e->e_fd, (off_t) 0, SEEK_SET0)) { |
1097 | LIBELF_SET_ERROR(IO, errno)do { (_libelf.libelf_error) = (((ELF_E_IO) & 0xFF) | (((( *__errno()))) << 8)); } while (0); |
1098 | goto error; |
1099 | } |
1100 | #if ELFTC_HAVE_MMAP1 |
1101 | if (e->e_flags & LIBELF_F_RAWFILE_MMAP0x100000U) { |
1102 | assert(e->e_rawfile != NULL)((e->e_rawfile != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1102, __func__, "e->e_rawfile != NULL")); |
1103 | assert(e->e_cmd == ELF_C_RDWR)((e->e_cmd == ELF_C_RDWR) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1103, __func__, "e->e_cmd == ELF_C_RDWR")); |
1104 | if (munmap(e->e_rawfile, (size_t) e->e_rawsize) < 0) { |
1105 | LIBELF_SET_ERROR(IO, errno)do { (_libelf.libelf_error) = (((ELF_E_IO) & 0xFF) | (((( *__errno()))) << 8)); } while (0); |
1106 | goto error; |
1107 | } |
1108 | } |
1109 | #endif |
1110 | } |
1111 | |
1112 | /* |
1113 | * Write out the new contents. |
1114 | */ |
1115 | if (write(e->e_fd, newfile, (size_t) newsize) != newsize) { |
1116 | LIBELF_SET_ERROR(IO, errno)do { (_libelf.libelf_error) = (((ELF_E_IO) & 0xFF) | (((( *__errno()))) << 8)); } while (0); |
1117 | goto error; |
1118 | } |
1119 | |
1120 | /* |
1121 | * For files opened in ELF_C_RDWR mode, set up the new 'raw' |
1122 | * contents. |
1123 | */ |
1124 | if (e->e_cmd == ELF_C_RDWR) { |
1125 | assert(e->e_rawfile != NULL)((e->e_rawfile != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1125, __func__, "e->e_rawfile != NULL")); |
1126 | assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) ||(((e->e_flags & 0x080000U) || (e->e_flags & 0x100000U )) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 1127 , __func__, "(e->e_flags & LIBELF_F_RAWFILE_MALLOC) || (e->e_flags & LIBELF_F_RAWFILE_MMAP)" )) |
1127 | (e->e_flags & LIBELF_F_RAWFILE_MMAP))(((e->e_flags & 0x080000U) || (e->e_flags & 0x100000U )) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c", 1127 , __func__, "(e->e_flags & LIBELF_F_RAWFILE_MALLOC) || (e->e_flags & LIBELF_F_RAWFILE_MMAP)" )); |
1128 | if (e->e_flags & LIBELF_F_RAWFILE_MALLOC0x080000U) { |
1129 | assert((e->e_flags & LIBELF_F_RAWFILE_MMAP) == 0)(((e->e_flags & 0x100000U) == 0) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 1129, __func__, "(e->e_flags & LIBELF_F_RAWFILE_MMAP) == 0" )); |
1130 | free(e->e_rawfile); |
1131 | e->e_rawfile = newfile; |
1132 | newfile = NULL((void *)0); |
1133 | } |
1134 | #if ELFTC_HAVE_MMAP1 |
1135 | else if (e->e_flags & LIBELF_F_RAWFILE_MMAP0x100000U) { |
1136 | assert((e->e_flags & LIBELF_F_RAWFILE_MALLOC) == 0)(((e->e_flags & 0x080000U) == 0) ? (void)0 : __assert2 ("/usr/src/lib/libelf/elf_update.c", 1136, __func__, "(e->e_flags & LIBELF_F_RAWFILE_MALLOC) == 0" )); |
1137 | if ((e->e_rawfile = mmap(NULL((void *)0), (size_t) newsize, |
1138 | PROT_READ0x01, MAP_PRIVATE0x0002, e->e_fd, (off_t) 0)) == |
1139 | MAP_FAILED((void *)-1)) { |
1140 | LIBELF_SET_ERROR(IO, errno)do { (_libelf.libelf_error) = (((ELF_E_IO) & 0xFF) | (((( *__errno()))) << 8)); } while (0); |
1141 | goto error; |
1142 | } |
1143 | } |
1144 | #endif /* ELFTC_HAVE_MMAP */ |
1145 | |
1146 | /* Record the new size of the file. */ |
1147 | e->e_rawsize = newsize; |
1148 | } else { |
1149 | /* File opened in ELF_C_WRITE mode. */ |
1150 | assert(e->e_rawfile == NULL)((e->e_rawfile == ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/elf_update.c" , 1150, __func__, "e->e_rawfile == NULL")); |
1151 | } |
1152 | |
1153 | /* |
1154 | * Reset flags, remove existing section descriptors and |
1155 | * {E,P}HDR pointers so that a subsequent elf_get{e,p}hdr() |
1156 | * and elf_getscn() will function correctly. |
1157 | */ |
1158 | |
1159 | e->e_flags &= ~ELF_F_DIRTY0x002U; |
1160 | |
1161 | STAILQ_FOREACH_SAFE(scn, &e->e_u.e_elf.e_scn, s_next, tscn)for ((scn) = ((&e->e_u.e_elf.e_scn)->stqh_first); ( scn) && ((tscn) = ((scn)->s_next.stqe_next), 1); ( scn) = (tscn)) |
1162 | _libelf_release_scn(scn); |
1163 | |
1164 | if (e->e_class == ELFCLASS321) { |
1165 | free(e->e_u.e_elf.e_ehdr.e_ehdr32); |
1166 | if (e->e_u.e_elf.e_phdr.e_phdr32) |
1167 | free(e->e_u.e_elf.e_phdr.e_phdr32); |
1168 | |
1169 | e->e_u.e_elf.e_ehdr.e_ehdr32 = NULL((void *)0); |
1170 | e->e_u.e_elf.e_phdr.e_phdr32 = NULL((void *)0); |
1171 | } else { |
1172 | free(e->e_u.e_elf.e_ehdr.e_ehdr64); |
1173 | if (e->e_u.e_elf.e_phdr.e_phdr64) |
1174 | free(e->e_u.e_elf.e_phdr.e_phdr64); |
1175 | |
1176 | e->e_u.e_elf.e_ehdr.e_ehdr64 = NULL((void *)0); |
1177 | e->e_u.e_elf.e_phdr.e_phdr64 = NULL((void *)0); |
1178 | } |
1179 | |
1180 | /* Free the temporary buffer. */ |
1181 | if (newfile) |
1182 | free(newfile); |
1183 | |
1184 | return (rc); |
1185 | |
1186 | error: |
1187 | free(newfile); |
1188 | |
1189 | return ((off_t) -1); |
1190 | } |
1191 | |
1192 | /* |
1193 | * Update an ELF object. |
1194 | */ |
1195 | |
1196 | off_t |
1197 | elf_update(Elf *e, Elf_Cmd c) |
1198 | { |
1199 | int ec; |
1200 | off_t rc; |
1201 | struct _Elf_Extent_List extents; |
1202 | |
1203 | rc = (off_t) -1; |
1204 | |
1205 | if (e == NULL((void *)0) || e->e_kind != ELF_K_ELF || |
1206 | (c != ELF_C_NULL && c != ELF_C_WRITE)) { |
1207 | LIBELF_SET_ERROR(ARGUMENT, 0)do { (_libelf.libelf_error) = (((ELF_E_ARGUMENT) & 0xFF) | (((0)) << 8)); } while (0); |
1208 | return (rc); |
1209 | } |
1210 | |
1211 | if ((ec = e->e_class) != ELFCLASS321 && ec != ELFCLASS642) { |
1212 | LIBELF_SET_ERROR(CLASS, 0)do { (_libelf.libelf_error) = (((ELF_E_CLASS) & 0xFF) | ( ((0)) << 8)); } while (0); |
1213 | return (rc); |
1214 | } |
1215 | |
1216 | if (e->e_version == EV_NONE0) |
1217 | e->e_version = EV_CURRENT1; |
1218 | |
1219 | if (c == ELF_C_WRITE && e->e_cmd == ELF_C_READ) { |
1220 | LIBELF_SET_ERROR(MODE, 0)do { (_libelf.libelf_error) = (((ELF_E_MODE) & 0xFF) | (( (0)) << 8)); } while (0); |
1221 | return (rc); |
1222 | } |
1223 | |
1224 | SLIST_INIT(&extents){ ((&extents)->slh_first) = ((void *)0); }; |
1225 | |
1226 | if ((rc = _libelf_resync_elf(e, &extents)) < 0) |
1227 | goto done; |
1228 | |
1229 | if (c == ELF_C_NULL) |
1230 | goto done; |
1231 | |
1232 | if (e->e_fd < 0) { |
1233 | rc = (off_t) -1; |
1234 | LIBELF_SET_ERROR(SEQUENCE, 0)do { (_libelf.libelf_error) = (((ELF_E_SEQUENCE) & 0xFF) | (((0)) << 8)); } while (0); |
1235 | goto done; |
1236 | } |
1237 | |
1238 | rc = _libelf_write_elf(e, rc, &extents); |
1239 | |
1240 | done: |
1241 | _libelf_release_extents(&extents); |
1242 | return (rc); |
1243 | } |