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]
This commit is contained in:
parent
a2dc08f2b8
commit
f6c0f35e07
@ -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 \
|
||||
|
@ -39,6 +39,7 @@ global:
|
||||
elf_getdata;
|
||||
elf_getident;
|
||||
elf_getscn;
|
||||
elf_getphnum;
|
||||
elf_getshnum;
|
||||
elf_getshstrndx;
|
||||
elf_hash;
|
||||
|
@ -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);
|
||||
|
87
lib/libelf/elf_getphnum.3
Normal file
87
lib/libelf/elf_getphnum.3
Normal file
@ -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
|
53
lib/libelf/elf_phnum.c
Normal file
53
lib/libelf/elf_phnum.c
Normal file
@ -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);
|
||||
}
|
@ -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;
|
||||
|
||||
/*
|
||||
* If the file is using extended numbering then section #0
|
||||
* would have already been read in.
|
||||
*/
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
scn->s_size = 0LL;
|
||||
scn->s_offset = scn->s_rawoff = 0LL;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -32,80 +32,6 @@ __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)
|
||||
{
|
||||
@ -113,11 +39,15 @@ elf_getshnum(Elf *e, size_t *shnum)
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
@ -471,6 +469,13 @@ _libelf_resync_elf(Elf *e)
|
||||
} else
|
||||
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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
136
lib/libelf/libelf_extended.c
Normal file
136
lib/libelf/libelf_extended.c
Normal file
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user