summaryrefslogtreecommitdiffstats
path: root/lib/libelf
diff options
context:
space:
mode:
authorjkoshy <jkoshy@FreeBSD.org>2006-12-25 02:22:22 +0000
committerjkoshy <jkoshy@FreeBSD.org>2006-12-25 02:22:22 +0000
commit26d8253ac6532abcb8d1c8d57743998f5368173b (patch)
tree1f1c4db9c6b866adf56e5cc3eccd23baaa57af28 /lib/libelf
parent44313eba34c379a180dc73dcd02ab9c415941db3 (diff)
downloadFreeBSD-src-26d8253ac6532abcb8d1c8d57743998f5368173b.zip
FreeBSD-src-26d8253ac6532abcb8d1c8d57743998f5368173b.tar.gz
Keep shadow copies of the `e_shnum', `e_phnum' and `e_shstrndx'
members of the ELF Executable Header inside the library-private `struct _Elf' descriptor and only update the underlying Elf{32,64}_Ehdr structure on an elf_update(3) call. These fields of the Ehdr structure are technically `out of bounds' for an application program per the ELF(3) API, but we've seen applications that initialize a new Ehdr structure using memcpy(), messing up the library's invariants. [1] Implement elf_getphnum() and handle ELF objects with more than 64K program header table entries. Reported by: jb [1]
Diffstat (limited to 'lib/libelf')
-rw-r--r--lib/libelf/Makefile3
-rw-r--r--lib/libelf/Version.map1
-rw-r--r--lib/libelf/_libelf.h8
-rw-r--r--lib/libelf/elf_getphnum.387
-rw-r--r--lib/libelf/elf_phnum.c53
-rw-r--r--lib/libelf/elf_scn.c68
-rw-r--r--lib/libelf/elf_shnum.c84
-rw-r--r--lib/libelf/elf_shstrndx.c72
-rw-r--r--lib/libelf/elf_update.c18
-rw-r--r--lib/libelf/libelf_checksum.c2
-rw-r--r--lib/libelf/libelf_ehdr.c85
-rw-r--r--lib/libelf/libelf_extended.c136
-rw-r--r--lib/libelf/libelf_phdr.c34
13 files changed, 432 insertions, 219 deletions
diff --git a/lib/libelf/Makefile b/lib/libelf/Makefile
index ae1ad42..0af640c 100644
--- a/lib/libelf/Makefile
+++ b/lib/libelf/Makefile
@@ -18,6 +18,7 @@ SRCS= elf_begin.c \
elf_next.c \
elf_rand.c \
elf_rawfile.c \
+ elf_phnum.c \
elf_shnum.c \
elf_shstrndx.c \
elf_scn.c \
@@ -46,6 +47,7 @@ SRCS= elf_begin.c \
libelf_checksum.c \
libelf_data.c \
libelf_ehdr.c \
+ libelf_extended.c \
libelf_phdr.c \
libelf_shdr.c \
libelf_xlate.c \
@@ -72,6 +74,7 @@ MAN= elf.3 \
elf_getdata.3 \
elf_getident.3 \
elf_getscn.3 \
+ elf_getphnum.3 \
elf_getshnum.3 \
elf_getshstrndx.3 \
elf_hash.3 \
diff --git a/lib/libelf/Version.map b/lib/libelf/Version.map
index e8cc819..2c8e81d 100644
--- a/lib/libelf/Version.map
+++ b/lib/libelf/Version.map
@@ -39,6 +39,7 @@ global:
elf_getdata;
elf_getident;
elf_getscn;
+ elf_getphnum;
elf_getshnum;
elf_getshstrndx;
elf_hash;
diff --git a/lib/libelf/_libelf.h b/lib/libelf/_libelf.h
index 02e7cf5..08185cc 100644
--- a/lib/libelf/_libelf.h
+++ b/lib/libelf/_libelf.h
@@ -71,6 +71,7 @@ extern struct _libelf_globals _libelf;
*/
#define LIBELF_F_MALLOCED 0x010000 /* whether data was malloc'ed */
#define LIBELF_F_MMAP 0x020000 /* whether e_rawfile was mmap'ed */
+#define LIBELF_F_SHDRS_LOADED 0x040000 /* whether all shdrs were read in */
struct _Elf {
int e_activations; /* activation count */
@@ -107,6 +108,9 @@ struct _Elf {
Elf64_Phdr *e_phdr64;
} e_phdr;
STAILQ_HEAD(, _Elf_Scn) e_scn; /* section list */
+ size_t e_nphdr; /* number of Phdr entries */
+ size_t e_nscn; /* number of sections */
+ size_t e_strndx; /* string table section index */
} e_elf;
} e_u;
};
@@ -171,9 +175,6 @@ void (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass))
(char *_dst, char *_src, size_t _cnt, int _byteswap);
void *_libelf_getphdr(Elf *_e, int _elfclass);
void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass);
-int _libelf_getshnum(Elf *_e, void *_eh, int _elfclass, size_t *_shnum);
-int _libelf_getshstrndx(Elf *_e, void *_eh, int _elfclass,
- size_t *_shstrndx);
void _libelf_init_elf(Elf *_e, Elf_Kind _kind);
int _libelf_malign(Elf_Type _t, int _elfclass);
size_t _libelf_msize(Elf_Type _t, int _elfclass, unsigned int _version);
@@ -181,6 +182,7 @@ void *_libelf_newphdr(Elf *_e, int _elfclass, size_t _count);
Elf_Data *_libelf_release_data(Elf_Data *_d);
Elf *_libelf_release_elf(Elf *_e);
Elf_Scn *_libelf_release_scn(Elf_Scn *_s);
+int _libelf_setphnum(Elf *_e, void *_eh, int _elfclass, size_t _phnum);
int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum);
int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass,
size_t _shstrndx);
diff --git a/lib/libelf/elf_getphnum.3 b/lib/libelf/elf_getphnum.3
new file mode 100644
index 0000000..606ceb0
--- /dev/null
+++ b/lib/libelf/elf_getphnum.3
@@ -0,0 +1,87 @@
+.\" Copyright (c) 2006 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 16, 2006
+.Os
+.Dt ELF_GETPHNUM 3
+.Sh NAME
+.Nm elf_getphnum
+.Nd return the number of program headers in an ELF file
+.Sh LIBRARY
+.Lb libelf
+.Sh SYNOPSIS
+.In libelf.h
+.Ft int
+.Fn elf_getphnum "Elf *elf" "size_t *phnum"
+.Sh DESCRIPTION
+Function
+.Fn elf_getphnum
+retrieves the number of ELF program headers associated with descriptor
+.Ar elf
+and stores it into the location pointed to by argument
+.Ar phnum .
+.Pp
+This routine allows applications to uniformly process both normal ELF
+objects and ELF objects that use extended numbering.
+.Pp
+.Sh RETURN VALUES
+Function
+.Fn elf_getphnum
+returns a non-zero value if successful, or zero in case of an
+error.
+.Sh ERRORS
+Function
+.Fn elf_getphnum
+can fail with the following errors:
+.Bl -tag -width "[ELF_E_RESOURCE]"
+.It Bq Er ELF_E_ARGUMENT
+A NULL value was passed in for argument
+.Ar elf .
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+was not for an ELF file.
+.It Bq Er ELF_E_ARGUMENT
+Argument
+.Ar elf
+lacks an ELF Executable Header.
+.It Bq Er ELF_E_HEADER
+The ELF Executable Header associated with argument
+.Ar elf
+was corrupt.
+.It Bq Er ELF_E_SECTION
+The section header at index
+.Dv SHN_UNDEF
+was corrupt.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf32_getehdr 3 ,
+.Xr elf64_getehdr 3 ,
+.Xr elf_getident 3 ,
+.Xr elf_getshnum 3 ,
+.Xr elf_getshstrndx 3 ,
+.Xr gelf 3 ,
+.Xr gelf_getehdr 3
diff --git a/lib/libelf/elf_phnum.c b/lib/libelf/elf_phnum.c
new file mode 100644
index 0000000..ff10c7e
--- /dev/null
+++ b/lib/libelf/elf_phnum.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2006 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ar.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+int
+elf_getphnum(Elf *e, size_t *phnum)
+{
+ void *eh;
+ int ec;
+
+ if (e == NULL || e->e_kind != ELF_K_ELF ||
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
+ LIBELF_SET_ERROR(ARGUMENT, 0);
+ return (0);
+ }
+
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (0);
+
+ *phnum = e->e_u.e_elf.e_nphdr;
+
+ return (1);
+}
diff --git a/lib/libelf/elf_scn.c b/lib/libelf/elf_scn.c
index fa1527f..139f6d9 100644
--- a/lib/libelf/elf_scn.c
+++ b/lib/libelf/elf_scn.c
@@ -44,7 +44,6 @@ _libelf_load_scn(Elf *e, void *ehdr)
int ec, swapbytes;
size_t fsz, i, shnum;
uint64_t shoff;
- uint32_t shtype;
char *src;
Elf32_Ehdr *eh32;
Elf64_Ehdr *eh64;
@@ -53,6 +52,7 @@ _libelf_load_scn(Elf *e, void *ehdr)
assert(e != NULL);
assert(ehdr != NULL);
+ assert((e->e_flags & LIBELF_F_SHDRS_LOADED) == 0);
#define CHECK_EHDR(E,EH) do { \
if (fsz != (EH)->e_shentsize || \
@@ -62,18 +62,18 @@ _libelf_load_scn(Elf *e, void *ehdr)
} \
} while (0)
- fsz = gelf_fsize(e, ELF_T_SHDR, (size_t) 1, e->e_version);
+ ec = e->e_class;
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
- ec = e->e_class;
+ shnum = e->e_u.e_elf.e_nscn;
+
if (ec == ELFCLASS32) {
eh32 = (Elf32_Ehdr *) ehdr;
- shnum = eh32->e_shnum;
shoff = (uint64_t) eh32->e_shoff;
CHECK_EHDR(e, eh32);
} else {
eh64 = (Elf64_Ehdr *) ehdr;
- shnum = eh64->e_shnum;
shoff = eh64->e_shoff;
CHECK_EHDR(e, eh64);
}
@@ -82,32 +82,18 @@ _libelf_load_scn(Elf *e, void *ehdr)
swapbytes = e->e_byteorder != LIBELF_PRIVATE(byteorder);
src = e->e_rawfile + shoff;
- i = 0;
-
- if (shnum == (size_t) 0 && shoff != 0LL) {
- /* Extended section numbering */
- if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL)
- return (0);
-
- (*xlator)((char *) &scn->s_shdr, src, (size_t) 1, swapbytes);
-
- if (ec == ELFCLASS32) {
- shtype = scn->s_shdr.s_shdr32.sh_type;
- shnum = scn->s_shdr.s_shdr32.sh_size;
- } else {
- shtype = scn->s_shdr.s_shdr64.sh_type;
- shnum = scn->s_shdr.s_shdr64.sh_size;
- }
- if (shtype != SHT_NULL) {
- LIBELF_SET_ERROR(SECTION, 0);
- return (0);
- }
+ /*
+ * If the file is using extended numbering then section #0
+ * would have already been read in.
+ */
- scn->s_size = 0LL;
- scn->s_offset = scn->s_rawoff = 0LL;
+ i = 0;
+ if (!STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
+ assert(STAILQ_FIRST(&e->e_u.e_elf.e_scn) ==
+ STAILQ_LAST(&e->e_u.e_elf.e_scn, _Elf_Scn, s_next));
- i++;
+ i = 1;
src += fsz;
}
@@ -127,6 +113,9 @@ _libelf_load_scn(Elf *e, void *ehdr)
scn->s_size = scn->s_shdr.s_shdr64.sh_size;
}
}
+
+ e->e_flags |= LIBELF_F_SHDRS_LOADED;
+
return (1);
}
@@ -147,7 +136,8 @@ elf_getscn(Elf *e, size_t index)
if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
return (NULL);
- if (e->e_cmd != ELF_C_WRITE && STAILQ_EMPTY(&e->e_u.e_elf.e_scn) &&
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
_libelf_load_scn(e, ehdr) == 0)
return (NULL);
@@ -174,7 +164,6 @@ elf_newscn(Elf *e)
{
int ec;
void *ehdr;
- size_t shnum;
Elf_Scn *scn;
if (e == NULL || e->e_kind != ELF_K_ELF) {
@@ -200,30 +189,25 @@ elf_newscn(Elf *e)
* file using ELF_C_READ, mess with its internal structure and
* use elf_update(...,ELF_C_NULL) to compute its new layout.
*/
- if (e->e_cmd != ELF_C_WRITE && STAILQ_EMPTY(&e->e_u.e_elf.e_scn) &&
+ if (e->e_cmd != ELF_C_WRITE &&
+ (e->e_flags & LIBELF_F_SHDRS_LOADED) == 0 &&
_libelf_load_scn(e, ehdr) == 0)
return (NULL);
- if (_libelf_getshnum(e, ehdr, ec, &shnum) == 0)
- return (NULL);
-
if (STAILQ_EMPTY(&e->e_u.e_elf.e_scn)) {
- assert(shnum == 0);
+ assert(e->e_u.e_elf.e_nscn == 0);
if ((scn = _libelf_allocate_scn(e, (size_t) SHN_UNDEF)) ==
NULL)
return (NULL);
- shnum++;
+ e->e_u.e_elf.e_nscn++;
}
- assert(shnum > 0);
+ assert(e->e_u.e_elf.e_nscn > 0);
- if ((scn = _libelf_allocate_scn(e, shnum)) == NULL)
+ if ((scn = _libelf_allocate_scn(e, e->e_u.e_elf.e_nscn)) == NULL)
return (NULL);
- shnum++;
-
- if (_libelf_setshnum(e, ehdr, ec, shnum) == 0)
- return (NULL);
+ e->e_u.e_elf.e_nscn++;
(void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY);
diff --git a/lib/libelf/elf_shnum.c b/lib/libelf/elf_shnum.c
index 8a53eed..d22a1fc 100644
--- a/lib/libelf/elf_shnum.c
+++ b/lib/libelf/elf_shnum.c
@@ -33,91 +33,21 @@ __FBSDID("$FreeBSD$");
#include "_libelf.h"
int
-_libelf_getshnum(Elf *e, void *eh, int ec, size_t *shnum)
-{
- Elf64_Off off;
- Elf_Scn *scn;
- void *sh;
- size_t n;
-
- if (ec == ELFCLASS32) {
- n = ((Elf32_Ehdr *) eh)->e_shnum;
- off = (Elf64_Off) ((Elf32_Ehdr *) eh)->e_shoff;
- } else {
- n = ((Elf64_Ehdr *) eh)->e_shnum;
- off = ((Elf64_Ehdr *) eh)->e_shoff;
- }
-
- if (n != 0) {
- *shnum = n;
- return (1);
- }
-
- if (off == 0L) {
- *shnum = (size_t) 0;
- return (1);
- }
-
- /*
- * If 'e_shnum' is zero and 'e_shoff' is non-zero, the file is
- * using extended section numbering, and the true section
- * number is kept in the 'sh_size' field of the section header
- * at offset SHN_UNDEF.
- */
- if ((scn = elf_getscn(e, (size_t) SHN_UNDEF)) == NULL)
- return (0);
- if ((sh = _libelf_getshdr(scn, ec)) == NULL)
- return (0);
-
- if (ec == ELFCLASS32)
- *shnum = ((Elf32_Shdr *) sh)->sh_size;
- else
- *shnum = ((Elf64_Shdr *) sh)->sh_size;
-
- return (1);
-}
-
-int
-_libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum)
-{
- Elf_Scn *scn;
- void *sh;
-
- if (shnum < SHN_LORESERVE) {
- if (ec == ELFCLASS32)
- ((Elf32_Ehdr *) eh)->e_shnum = shnum;
- else
- ((Elf64_Ehdr *) eh)->e_shnum = shnum;
- return (1);
- }
-
- if ((scn = elf_getscn(e, (size_t) SHN_UNDEF)) == NULL)
- return (0);
- if ((sh = _libelf_getshdr(scn, ec)) == NULL)
- return (0);
-
- if (ec == ELFCLASS32)
- ((Elf32_Shdr *) sh)->sh_size = shnum;
- else
- ((Elf64_Shdr *) sh)->sh_size = shnum;
-
- (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
-
- return (1);
-}
-
-int
elf_getshnum(Elf *e, size_t *shnum)
{
void *eh;
int ec;
if (e == NULL || e->e_kind != ELF_K_ELF ||
- ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) ||
- ((eh = _libelf_ehdr(e, ec, 0)) == NULL)) {
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (0);
}
- return (_libelf_getshnum(e, eh, ec, shnum));
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (0);
+
+ *shnum = e->e_u.e_elf.e_nscn;
+
+ return (1);
}
diff --git a/lib/libelf/elf_shstrndx.c b/lib/libelf/elf_shstrndx.c
index cae25c3..f4f502d 100644
--- a/lib/libelf/elf_shstrndx.c
+++ b/lib/libelf/elf_shstrndx.c
@@ -32,68 +32,6 @@ __FBSDID("$FreeBSD$");
#include "_libelf.h"
-/*
- * Helpers to get/set the e_shstrndx field of the ELF header.
- */
-
-int
-_libelf_getshstrndx(Elf *e, void *eh, int ec, size_t *strndx)
-{
- Elf_Scn *scn;
- void *sh;
- size_t n;
-
- n = (ec == ELFCLASS32) ? ((Elf32_Ehdr *) eh)->e_shstrndx :
- ((Elf64_Ehdr *) eh)->e_shstrndx;
-
- if (n < SHN_LORESERVE) {
- *strndx = n;
- return (1);
- }
-
- if ((scn = elf_getscn(e, (size_t) SHN_UNDEF)) == NULL)
- return (0);
- if ((sh = _libelf_getshdr(scn, ec)) == NULL)
- return (0);
-
- if (ec == ELFCLASS32)
- *strndx = ((Elf32_Shdr *) sh)->sh_link;
- else
- *strndx = ((Elf64_Shdr *) sh)->sh_link;
-
- return (1);
-}
-
-int
-_libelf_setshstrndx(Elf *e, void *eh, int ec, size_t strndx)
-{
- Elf_Scn *scn;
- void *sh;
-
- if (strndx < SHN_LORESERVE) {
- if (ec == ELFCLASS32)
- ((Elf32_Ehdr *) eh)->e_shstrndx = strndx;
- else
- ((Elf64_Ehdr *) eh)->e_shstrndx = strndx;
- return (1);
- }
-
- if ((scn = elf_getscn(e, (size_t) SHN_UNDEF)) == NULL)
- return (0);
- if ((sh = _libelf_getshdr(scn, ec)) == NULL)
- return (0);
-
- if (ec == ELFCLASS32) {
- ((Elf32_Ehdr *) eh)->e_shstrndx = SHN_XINDEX;
- ((Elf32_Shdr *) sh)->sh_link = strndx;
- } else {
- ((Elf64_Ehdr *) eh)->e_shstrndx = SHN_XINDEX;
- ((Elf64_Shdr *) sh)->sh_link = strndx;
- }
-
- return (1);
-}
-
int
elf_getshstrndx(Elf *e, size_t *strndx)
{
@@ -101,13 +39,17 @@ elf_getshstrndx(Elf *e, size_t *strndx)
int ec;
if (e == NULL || e->e_kind != ELF_K_ELF ||
- ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64) ||
- ((eh = _libelf_ehdr(e, ec, 0)) == NULL)) {
+ ((ec = e->e_class) != ELFCLASS32 && ec != ELFCLASS64)) {
LIBELF_SET_ERROR(ARGUMENT, 0);
return (0);
}
- return (_libelf_getshstrndx(e, eh, ec, strndx));
+ if ((eh = _libelf_ehdr(e, ec, 0)) == NULL)
+ return (0);
+
+ *strndx = e->e_u.e_elf.e_strndx;
+
+ return (1);
}
int
diff --git a/lib/libelf/elf_update.c b/lib/libelf/elf_update.c
index c0203f9..5e8ee9c 100644
--- a/lib/libelf/elf_update.c
+++ b/lib/libelf/elf_update.c
@@ -346,7 +346,6 @@ _libelf_resync_elf(Elf *e)
if (ec == ELFCLASS32) {
eh_byteorder = eh32->e_ident[EI_DATA];
eh_class = eh32->e_ident[EI_CLASS];
- phnum = eh32->e_phnum;
phoff = (uint64_t) eh32->e_phoff;
shoff = (uint64_t) eh32->e_shoff;
eh_type = eh32->e_type;
@@ -354,7 +353,6 @@ _libelf_resync_elf(Elf *e)
} else {
eh_byteorder = eh64->e_ident[EI_DATA];
eh_class = eh64->e_ident[EI_CLASS];
- phnum = eh64->e_phnum;
phoff = eh64->e_phoff;
shoff = eh64->e_shoff;
eh_type = eh64->e_type;
@@ -379,8 +377,8 @@ _libelf_resync_elf(Elf *e)
return ((off_t) -1);
}
- if (_libelf_getshnum(e, ehdr, ec, &shnum) == 0)
- return ((off_t) -1);
+ shnum = e->e_u.e_elf.e_nscn;
+ phnum = e->e_u.e_elf.e_nphdr;
e->e_byteorder = eh_byteorder;
@@ -472,6 +470,13 @@ _libelf_resync_elf(Elf *e)
shoff = 0;
/*
+ * Set the fields of the Executable Header that could potentially use
+ * extended numbering.
+ */
+ _libelf_setphnum(e, ehdr, ec, phnum);
+ _libelf_setshnum(e, ehdr, ec, shnum);
+
+ /*
* Update the `e_phoff' and `e_shoff' fields if the library is
* doing the layout.
*/
@@ -638,18 +643,17 @@ _libelf_write_elf(Elf *e, off_t newsize)
ehdr = _libelf_ehdr(e, ec, 0);
assert(ehdr != NULL);
+ phnum = e->e_u.e_elf.e_nphdr;
+
if (ec == ELFCLASS32) {
eh32 = (Elf32_Ehdr *) ehdr;
- phnum = eh32->e_phnum;
phoff = (uint64_t) eh32->e_phoff;
shnum = eh32->e_shnum;
shoff = (uint64_t) eh32->e_shoff;
-
} else {
eh64 = (Elf64_Ehdr *) ehdr;
- phnum = eh64->e_phnum;
phoff = eh64->e_phoff;
shnum = eh64->e_shnum;
shoff = eh64->e_shoff;
diff --git a/lib/libelf/libelf_checksum.c b/lib/libelf/libelf_checksum.c
index 3210412..c7eb8a0 100644
--- a/lib/libelf/libelf_checksum.c
+++ b/lib/libelf/libelf_checksum.c
@@ -76,7 +76,7 @@ _libelf_checksum(Elf *e, int elfclass)
*/
checksum = 0;
- for (shn = 1; shn < eh.e_shnum; shn++) {
+ for (shn = 1; shn < e->e_u.e_elf.e_nscn; shn++) {
if ((scn = elf_getscn(e, shn)) == NULL)
return (0);
if (gelf_getshdr(scn, &shdr) == NULL)
diff --git a/lib/libelf/libelf_ehdr.c b/lib/libelf/libelf_ehdr.c
index 6c938b3..e0c4886 100644
--- a/lib/libelf/libelf_ehdr.c
+++ b/lib/libelf/libelf_ehdr.c
@@ -36,6 +36,54 @@ __FBSDID("$FreeBSD$");
#include "_libelf.h"
+/*
+ * Retrieve counts for sections, phdrs and the section string table index
+ * from section header #0 of the ELF object.
+ */
+static int
+_libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
+ uint16_t strndx)
+{
+ Elf_Scn *scn;
+ size_t fsz;
+ void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
+ uint32_t shtype;
+
+ assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
+
+ fsz = _libelf_fsize(ELF_T_SHDR, ec, e->e_version, 1);
+ assert(fsz > 0);
+
+ if (e->e_rawsize < shoff + fsz) { /* raw file too small */
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (0);
+ }
+
+ if ((scn = _libelf_allocate_scn(e, (size_t) 0)) == NULL)
+ return (0);
+
+ xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
+ (*xlator)((char *) &scn->s_shdr, e->e_rawfile + shoff, (size_t) 1,
+ e->e_byteorder != LIBELF_PRIVATE(byteorder));
+
+#define GET_SHDR_MEMBER(M) ((ec == ELFCLASS32) ? scn->s_shdr.s_shdr32.M : \
+ scn->s_shdr.s_shdr64.M)
+
+ if ((shtype = GET_SHDR_MEMBER(sh_type)) != SHT_NULL) {
+ LIBELF_SET_ERROR(SECTION, 0);
+ return (0);
+ }
+
+ e->e_u.e_elf.e_nscn = GET_SHDR_MEMBER(sh_size);
+ e->e_u.e_elf.e_nphdr = (phnum != PN_XNUM) ? phnum :
+ GET_SHDR_MEMBER(sh_info);
+ e->e_u.e_elf.e_strndx = (strndx != SHN_XINDEX) ? strndx :
+ GET_SHDR_MEMBER(sh_link);
+#undef GET_SHDR_MEMBER
+
+ return (1);
+}
+
#define EHDR_INIT(E,SZ) do { \
Elf##SZ##_Ehdr *eh = (E); \
eh->e_ident[EI_MAG0] = ELFMAG0; \
@@ -53,8 +101,10 @@ __FBSDID("$FreeBSD$");
void *
_libelf_ehdr(Elf *e, int ec, int allocate)
{
- size_t fsz, msz;
void *ehdr;
+ size_t fsz, msz;
+ uint16_t phnum, shnum, strndx;
+ uint64_t shoff;
void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
assert(ec == ELFCLASS32 || ec == ELFCLASS64);
@@ -85,8 +135,7 @@ _libelf_ehdr(Elf *e, int ec, int allocate)
if (ehdr != NULL) /* already have a translated ehdr */
return (ehdr);
- fsz = gelf_fsize(e, ELF_T_EHDR, (size_t) 1, e->e_version);
-
+ fsz = _libelf_fsize(ELF_T_EHDR, ec, e->e_version, (size_t) 1);
assert(fsz > 0);
if (e->e_cmd != ELF_C_WRITE && e->e_rawsize < fsz) {
@@ -121,5 +170,35 @@ _libelf_ehdr(Elf *e, int ec, int allocate)
(*xlator)(ehdr, e->e_rawfile, (size_t) 1,
e->e_byteorder != LIBELF_PRIVATE(byteorder));
+ /*
+ * If extended numbering is being used, read the correct
+ * number of sections and program header entries.
+ */
+ if (ec == ELFCLASS32) {
+ phnum = ((Elf32_Ehdr *) ehdr)->e_phnum;
+ shnum = ((Elf32_Ehdr *) ehdr)->e_shnum;
+ shoff = ((Elf32_Ehdr *) ehdr)->e_shoff;
+ strndx = ((Elf32_Ehdr *) ehdr)->e_shstrndx;
+ } else {
+ phnum = ((Elf64_Ehdr *) ehdr)->e_phnum;
+ shnum = ((Elf64_Ehdr *) ehdr)->e_shnum;
+ shoff = ((Elf64_Ehdr *) ehdr)->e_shoff;
+ strndx = ((Elf64_Ehdr *) ehdr)->e_shstrndx;
+ }
+
+ if (shnum >= SHN_LORESERVE ||
+ (shoff == 0LL && (shnum != 0 || phnum == PN_XNUM ||
+ strndx == SHN_XINDEX))) {
+ LIBELF_SET_ERROR(HEADER, 0);
+ return (NULL);
+ }
+
+ if (shnum != 0 || shoff == 0LL) { /* not using extended numbering */
+ e->e_u.e_elf.e_nphdr = phnum;
+ e->e_u.e_elf.e_nscn = shnum;
+ e->e_u.e_elf.e_strndx = strndx;
+ } else if (_libelf_load_extended(e, ec, shoff, phnum, strndx) == 0)
+ return (NULL);
+
return (ehdr);
}
diff --git a/lib/libelf/libelf_extended.c b/lib/libelf/libelf_extended.c
new file mode 100644
index 0000000..6e45d81
--- /dev/null
+++ b/lib/libelf/libelf_extended.c
@@ -0,0 +1,136 @@
+/*-
+ * Copyright (c) 2006 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <libelf.h>
+
+#include "_libelf.h"
+
+/*
+ * Retrieve section #0, allocating a new section if needed.
+ */
+static Elf_Scn *
+_libelf_getscn0(Elf *e)
+{
+ Elf_Scn *s;
+
+ if ((s = STAILQ_FIRST(&e->e_u.e_elf.e_scn)) != NULL)
+ return (s);
+
+ return (_libelf_allocate_scn(e, (size_t) SHN_UNDEF));
+}
+
+int
+_libelf_setshnum(Elf *e, void *eh, int ec, size_t shnum)
+{
+ Elf_Scn *scn;
+
+ if (shnum >= SHN_LORESERVE) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_size = shnum;
+ else
+ scn->s_shdr.s_shdr64.sh_size = shnum;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ shnum = 0;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_shnum = shnum;
+ else
+ ((Elf64_Ehdr *) eh)->e_shnum = shnum;
+
+
+ return (1);
+}
+
+int
+_libelf_setshstrndx(Elf *e, void *eh, int ec, size_t shstrndx)
+{
+ Elf_Scn *scn;
+
+ if (shstrndx >= SHN_LORESERVE) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_link = shstrndx;
+ else
+ scn->s_shdr.s_shdr64.sh_link = shstrndx;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ shstrndx = SHN_XINDEX;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_shstrndx = shstrndx;
+ else
+ ((Elf64_Ehdr *) eh)->e_shstrndx = shstrndx;
+
+ return (1);
+}
+
+int
+_libelf_setphnum(Elf *e, void *eh, int ec, size_t phnum)
+{
+ Elf_Scn *scn;
+
+ if (phnum >= PN_XNUM) {
+ if ((scn = _libelf_getscn0(e)) == NULL)
+ return (0);
+
+ assert(scn->s_ndx == SHN_UNDEF);
+
+ if (ec == ELFCLASS32)
+ scn->s_shdr.s_shdr32.sh_info = phnum;
+ else
+ scn->s_shdr.s_shdr64.sh_info = phnum;
+
+ (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
+
+ phnum = PN_XNUM;
+ }
+
+ if (ec == ELFCLASS32)
+ ((Elf32_Ehdr *) eh)->e_phnum = phnum;
+ else
+ ((Elf64_Ehdr *) eh)->e_phnum = phnum;
+
+ return (1);
+}
+
diff --git a/lib/libelf/libelf_phdr.c b/lib/libelf/libelf_phdr.c
index 5ba58d4..fd43851 100644
--- a/lib/libelf/libelf_phdr.c
+++ b/lib/libelf/libelf_phdr.c
@@ -66,14 +66,14 @@ _libelf_getphdr(Elf *e, int ec)
if ((ehdr = _libelf_ehdr(e, ec, 0)) == NULL)
return (NULL);
+ phnum = e->e_u.e_elf.e_nphdr;
+
if (ec == ELFCLASS32) {
eh32 = (Elf32_Ehdr *) ehdr;
- phnum = eh32->e_phnum;
phentsize = eh32->e_phentsize;
phoff = (uint64_t) eh32->e_phoff;
} else {
eh64 = (Elf64_Ehdr *) ehdr;
- phnum = eh64->e_phnum;
phentsize = eh64->e_phentsize;
phoff = (uint64_t) eh64->e_phoff;
}
@@ -112,9 +112,7 @@ _libelf_getphdr(Elf *e, int ec)
void *
_libelf_newphdr(Elf *e, int ec, size_t count)
{
- void *ehdr, *nphdr, *ophdr;
- Elf32_Ehdr *eh32;
- Elf64_Ehdr *eh64;
+ void *ehdr, *newphdr, *oldphdr;
size_t msz;
if (e == NULL) {
@@ -135,31 +133,25 @@ _libelf_newphdr(Elf *e, int ec, size_t count)
assert(msz > 0);
- nphdr = NULL;
- if (count > 0 && (nphdr = calloc(count, msz)) == NULL) {
+ newphdr = NULL;
+ if (count > 0 && (newphdr = calloc(count, msz)) == NULL) {
LIBELF_SET_ERROR(RESOURCE, 0);
return (NULL);
}
if (ec == ELFCLASS32) {
- if ((ophdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL)
- free(ophdr);
- e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) nphdr;
+ if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr32) != NULL)
+ free(oldphdr);
+ e->e_u.e_elf.e_phdr.e_phdr32 = (Elf32_Phdr *) newphdr;
} else {
- if ((ophdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL)
- free(ophdr);
- e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) nphdr;
+ if ((oldphdr = (void *) e->e_u.e_elf.e_phdr.e_phdr64) != NULL)
+ free(oldphdr);
+ e->e_u.e_elf.e_phdr.e_phdr64 = (Elf64_Phdr *) newphdr;
}
- if (ec == ELFCLASS32) {
- eh32 = (Elf32_Ehdr *) ehdr;
- eh32->e_phnum = count;
- } else {
- eh64 = (Elf64_Ehdr *) ehdr;
- eh64->e_phnum = count;
- }
+ e->e_u.e_elf.e_nphdr = count;
elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
- return (nphdr);
+ return (newphdr);
}
OpenPOWER on IntegriCloud