From 36c39678d62186cea27ea8d77bd779bf8d85b582 Mon Sep 17 00:00:00 2001 From: Joseph Koshy Date: Sat, 8 Sep 2007 08:20:12 +0000 Subject: [PATCH] Fix a bug that prevented applications from laying out ELF objects with section header tables residing in between other sections. Introduce additional checks for overlaps between section data and the section header table when the application is performing section layout. Document additional error returns. Reported by: Kai Wang Approved by: re (rwatson) --- lib/libelf/elf_update.3 | 9 ++++-- 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 98311688687..ad5240c7465 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 5e8ee9c510c..57b432e54c8 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);