diff options
-rw-r--r-- | lib/libelf/elf_update.3 | 9 | ||||
-rw-r--r-- | lib/libelf/elf_update.c | 61 |
2 files changed, 51 insertions, 19 deletions
diff --git a/lib/libelf/elf_update.3 b/lib/libelf/elf_update.3 index 9831168..ad5240c 100644 --- a/lib/libelf/elf_update.3 +++ b/lib/libelf/elf_update.3 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2006 Joseph Koshy. All rights reserved. +.\" Copyright (c) 2006,2007 Joseph Koshy. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 16, 2006 +.Dd September 08, 2007 .Os .Dt ELF_UPDATE 3 .Sh NAME @@ -228,6 +228,11 @@ Argument .Ar elf contained section descriptors that were incorrectly aligned or were too small for their data. +.It Bq Er ELF_E_LAYOUT +The flag +.Dv ELF_F_LAYOUT +was set on the Elf descriptor and the section header table overlapped +an extent in the object mapped by a section descriptor. .It Bq Er ELF_E_MODE An .Dv ELF_C_WRITE diff --git a/lib/libelf/elf_update.c b/lib/libelf/elf_update.c index 5e8ee9c..57b432e 100644 --- a/lib/libelf/elf_update.c +++ b/lib/libelf/elf_update.c @@ -68,7 +68,10 @@ __FBSDID("$FreeBSD$"); */ /* - * Compute the extents of a section, by looking at the. + * Compute the extents of a section, by looking at the data + * descriptors associated with it. The function returns zero if an + * error was detected. `*rc' holds the maximum file extent seen so + * far. */ static int _libelf_compute_section_extents(Elf *e, Elf_Scn *s, off_t *rc) @@ -267,7 +270,7 @@ _libelf_resync_sections(Elf *e, off_t rc) { int ec; off_t nrc; - size_t sh_type; + size_t sh_type, shdr_start, shdr_end; Elf_Scn *s, *ts; ec = e->e_class; @@ -311,6 +314,29 @@ _libelf_resync_sections(Elf *e, off_t rc) rc = s->s_offset + s->s_size; } + /* + * If the application is controlling file layout, check for an + * overlap between this section's extents and the SHDR table. + */ + if (e->e_flags & ELF_F_LAYOUT) { + + if (e->e_class == ELFCLASS32) + shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr32->e_shoff; + else + shdr_start = e->e_u.e_elf.e_ehdr.e_ehdr64->e_shoff; + + shdr_end = shdr_start + _libelf_fsize(ELF_T_SHDR, e->e_class, + e->e_version, e->e_u.e_elf.e_nscn); + + STAILQ_FOREACH(s, &e->e_u.e_elf.e_scn, s_next) { + if (s->s_offset >= shdr_end || + s->s_offset + s->s_size <= shdr_start) + continue; + LIBELF_SET_ERROR(LAYOUT, 0); + return ((off_t) -1); + } + } + assert(nrc == rc); return (rc); @@ -446,18 +472,17 @@ _libelf_resync_elf(Elf *e) /* * Compute the space taken up by the section header table, if - * one is needed. + * one is needed. If ELF_F_LAYOUT is asserted, the + * application may have placed the section header table in + * between existing sections, so the net size of the file need + * not increase due to the presence of the section header + * table. */ if (shnum) { fsz = _libelf_fsize(ELF_T_SHDR, ec, eh_version, (size_t) 1); align = _libelf_falign(ELF_T_SHDR, ec); if (e->e_flags & ELF_F_LAYOUT) { - if (rc > shoff) { - LIBELF_SET_ERROR(HEADER, 0); - return ((off_t) -1); - } - if (shoff % align) { LIBELF_SET_ERROR(LAYOUT, 0); return ((off_t) -1); @@ -465,7 +490,8 @@ _libelf_resync_elf(Elf *e) } else shoff = roundup(rc, align); - rc = shoff + fsz * shnum; + if (shoff + fsz * shnum > (size_t) rc) + rc = shoff + fsz * shnum; } else shoff = 0; @@ -619,7 +645,7 @@ static off_t _libelf_write_elf(Elf *e, off_t newsize) { int ec; - off_t rc; + off_t maxrc, rc; size_t fsz, msz, phnum, shnum; uint64_t phoff, shoff; void *ehdr; @@ -728,16 +754,17 @@ _libelf_write_elf(Elf *e, off_t newsize) goto error; /* - * Write out the section header table, if required. + * Write out the section header table, if required. Note that + * if flag ELF_F_LAYOUT has been set the section header table + * could reside in between byte ranges mapped by section + * descriptors. */ - if (shnum != 0 && shoff != 0) { - assert((unsigned) rc <= shoff); - if ((uint64_t) rc < shoff) (void) memset(newfile + rc, LIBELF_PRIVATE(fillchar), shoff - rc); + maxrc = rc; rc = shoff; assert(rc % _libelf_falign(ELF_T_SHDR, ec) == 0); @@ -763,10 +790,10 @@ _libelf_write_elf(Elf *e, off_t newsize) rc += fsz; } - } - /* - */ + if (maxrc > rc) + rc = maxrc; + } assert(rc == newsize); |