Perform additional checks when translating between file and memory
representations of ELF types. The ELF(3) API allows applications to request a conversion that is `in-place', i.e., with source and destinations data buffers being the same. However, the file and memory sizes of ELF sections that have additional internal structure, such as those of type `Elf_Note', or `Elf_GNU_Hash_Header', can be determined only known after the type-specific headers that comprise the first few words in these sections are read and translated. Pass in the size of destination buffer to type translation routines in "libelf_convert.m4" and have these routines return an error code if the translated data would not fit inside the destination buffer. Obtained from: elftoolchain MFC after: 1 month
This commit is contained in:
parent
4e55157fa4
commit
f0f10541db
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=210338
@ -171,8 +171,8 @@ void *_libelf_ehdr(Elf *_e, int _elfclass, int _allocate);
|
||||
int _libelf_falign(Elf_Type _t, int _elfclass);
|
||||
size_t _libelf_fsize(Elf_Type _t, int _elfclass, unsigned int _version,
|
||||
size_t count);
|
||||
void (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass))
|
||||
(char *_dst, char *_src, size_t _cnt, int _byteswap);
|
||||
int (*_libelf_get_translator(Elf_Type _t, int _direction, int _elfclass))
|
||||
(char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap);
|
||||
void *_libelf_getphdr(Elf *_e, int _elfclass);
|
||||
void *_libelf_getshdr(Elf_Scn *_scn, int _elfclass);
|
||||
void _libelf_init_elf(Elf *_e, Elf_Kind _kind);
|
||||
|
@ -43,7 +43,7 @@ elf_getdata(Elf_Scn *s, Elf_Data *d)
|
||||
int elfclass, elftype;
|
||||
unsigned int sh_type;
|
||||
uint64_t sh_align, sh_offset, sh_size;
|
||||
void (*xlate)(char *_d, char *_s, size_t _c, int _swap);
|
||||
int (*xlate)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
|
||||
|
||||
if (s == NULL || (e = s->s_elf) == NULL || e->e_kind != ELF_K_ELF ||
|
||||
(d != NULL && s != d->d_scn)) {
|
||||
@ -125,11 +125,16 @@ elf_getdata(Elf_Scn *s, Elf_Data *d)
|
||||
}
|
||||
|
||||
d->d_flags |= LIBELF_F_MALLOCED;
|
||||
STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
|
||||
|
||||
xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass);
|
||||
(*xlate)(d->d_buf, e->e_rawfile + sh_offset, count, e->e_byteorder !=
|
||||
LIBELF_PRIVATE(byteorder));
|
||||
if (!(*xlate)(d->d_buf, d->d_size, e->e_rawfile + sh_offset, count,
|
||||
e->e_byteorder != LIBELF_PRIVATE(byteorder))) {
|
||||
_libelf_release_data(d);
|
||||
LIBELF_SET_ERROR(DATA, 0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
|
||||
|
||||
return (d);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ _libelf_load_scn(Elf *e, void *ehdr)
|
||||
Elf32_Ehdr *eh32;
|
||||
Elf64_Ehdr *eh64;
|
||||
Elf_Scn *scn;
|
||||
void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
|
||||
int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
|
||||
|
||||
assert(e != NULL);
|
||||
assert(ehdr != NULL);
|
||||
@ -101,7 +101,8 @@ _libelf_load_scn(Elf *e, void *ehdr)
|
||||
if ((scn = _libelf_allocate_scn(e, i)) == NULL)
|
||||
return (0);
|
||||
|
||||
(*xlator)((char *) &scn->s_shdr, src, (size_t) 1, swapbytes);
|
||||
(*xlator)((char *) &scn->s_shdr, sizeof(scn->s_shdr), src,
|
||||
(size_t) 1, swapbytes);
|
||||
|
||||
if (ec == ELFCLASS32) {
|
||||
scn->s_offset = scn->s_rawoff =
|
||||
|
@ -236,6 +236,7 @@ IGNORE(MOVEP)
|
||||
IGNORE(NOTE)
|
||||
|
||||
define(IGNORE_BYTE, 1) /* 'lator, leave 'em bytes alone */
|
||||
define(IGNORE_GNUHASH, 1)
|
||||
define(IGNORE_NOTE, 1)
|
||||
define(IGNORE_SXWORD32, 1)
|
||||
define(IGNORE_XWORD32, 1)
|
||||
@ -274,18 +275,18 @@ define(`SIZEDEP_OFF', 1)
|
||||
* `$4': ELF class specifier for types, one of [`32', `64']
|
||||
*/
|
||||
define(`MAKEPRIM_TO_F',`
|
||||
static void
|
||||
libelf_cvt_$1$3_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt_$1$3_tof(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
Elf$4_$2 t, *s = (Elf$4_$2 *) (uintptr_t) src;
|
||||
size_t c;
|
||||
|
||||
if (dst == src && !byteswap)
|
||||
return;
|
||||
(void) dsz;
|
||||
|
||||
if (!byteswap) {
|
||||
(void) memcpy(dst, src, count * sizeof(*s));
|
||||
return;
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (c = 0; c < count; c++) {
|
||||
@ -293,22 +294,25 @@ libelf_cvt_$1$3_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
SWAP_$1$3(t);
|
||||
WRITE_$1$3(dst,t);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
')
|
||||
|
||||
define(`MAKEPRIM_TO_M',`
|
||||
static void
|
||||
libelf_cvt_$1$3_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt_$1$3_tom(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
Elf$4_$2 t, *d = (Elf$4_$2 *) (uintptr_t) dst;
|
||||
size_t c;
|
||||
|
||||
if (dst == src && !byteswap)
|
||||
return;
|
||||
if (dsz < count * sizeof(Elf$4_$2))
|
||||
return (0);
|
||||
|
||||
if (!byteswap) {
|
||||
(void) memcpy(dst, src, count * sizeof(*d));
|
||||
return;
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (c = 0; c < count; c++) {
|
||||
@ -316,6 +320,8 @@ libelf_cvt_$1$3_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
SWAP_$1$3(t);
|
||||
*d++ = t;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
')
|
||||
|
||||
@ -392,12 +398,15 @@ define(`READ_STRUCT',
|
||||
|
||||
define(`MAKE_TO_F',
|
||||
`ifdef(`IGNORE_'$1$3,`',`
|
||||
static void
|
||||
libelf_cvt$3_$1_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt$3_$1_tof(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
Elf$3_$2 t, *s;
|
||||
size_t c;
|
||||
|
||||
(void) dsz;
|
||||
|
||||
s = (Elf$3_$2 *) (uintptr_t) src;
|
||||
for (c = 0; c < count; c++) {
|
||||
t = *s++;
|
||||
@ -406,13 +415,16 @@ libelf_cvt$3_$1_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
}
|
||||
WRITE_STRUCT($2,$3)
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
')')
|
||||
|
||||
define(`MAKE_TO_M',
|
||||
`ifdef(`IGNORE_'$1$3,`',`
|
||||
static void
|
||||
libelf_cvt$3_$1_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt$3_$1_tom(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
Elf$3_$2 t, *d;
|
||||
unsigned char *s,*s0;
|
||||
@ -422,6 +434,9 @@ libelf_cvt$3_$1_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
d = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
|
||||
s0 = (unsigned char *) src + (count - 1) * fsz;
|
||||
|
||||
if (dsz < count * sizeof(Elf$3_$2))
|
||||
return (0);
|
||||
|
||||
while (count--) {
|
||||
s = s0;
|
||||
READ_STRUCT($2,$3)
|
||||
@ -430,6 +445,8 @@ libelf_cvt$3_$1_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
}
|
||||
*d-- = t; s0 -= fsz;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
')')
|
||||
|
||||
@ -475,12 +492,16 @@ divert(0)
|
||||
* simple memcpy suffices for both directions of conversion.
|
||||
*/
|
||||
|
||||
static void
|
||||
libelf_cvt_BYTE_tox(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt_BYTE_tox(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
(void) byteswap;
|
||||
if (dsz < count)
|
||||
return (0);
|
||||
if (dst != src)
|
||||
(void) memcpy(dst, src, count);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -490,69 +511,81 @@ libelf_cvt_BYTE_tox(char *dst, char *src, size_t count, int byteswap)
|
||||
*
|
||||
* Argument `count' denotes the total number of bytes to be converted.
|
||||
*/
|
||||
static void
|
||||
libelf_cvt_NOTE_tom(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt_NOTE_tom(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
uint32_t namesz, descsz, type;
|
||||
Elf_Note *en;
|
||||
size_t sz;
|
||||
size_t sz, hdrsz;
|
||||
|
||||
if (dst == src && !byteswap)
|
||||
return;
|
||||
if (dsz < count) /* Destination buffer is too small. */
|
||||
return (0);
|
||||
|
||||
hdrsz = 3 * sizeof(uint32_t);
|
||||
if (count < hdrsz) /* Source too small. */
|
||||
return (0);
|
||||
|
||||
if (!byteswap) {
|
||||
(void) memcpy(dst, src, count);
|
||||
return;
|
||||
return (1);
|
||||
}
|
||||
|
||||
while (count > sizeof(Elf_Note)) {
|
||||
|
||||
/* Process all notes in the section. */
|
||||
while (count > hdrsz) {
|
||||
/* Read the note header. */
|
||||
READ_WORD(src, namesz);
|
||||
READ_WORD(src, descsz);
|
||||
READ_WORD(src, type);
|
||||
|
||||
if (byteswap) {
|
||||
SWAP_WORD(namesz);
|
||||
SWAP_WORD(descsz);
|
||||
SWAP_WORD(type);
|
||||
}
|
||||
/* Translate. */
|
||||
SWAP_WORD(namesz);
|
||||
SWAP_WORD(descsz);
|
||||
SWAP_WORD(type);
|
||||
|
||||
/* Copy out the translated note header. */
|
||||
en = (Elf_Note *) (uintptr_t) dst;
|
||||
en->n_namesz = namesz;
|
||||
en->n_descsz = descsz;
|
||||
en->n_type = type;
|
||||
|
||||
dsz -= sizeof(Elf_Note);
|
||||
dst += sizeof(Elf_Note);
|
||||
count -= hdrsz;
|
||||
|
||||
ROUNDUP2(namesz, 4);
|
||||
ROUNDUP2(descsz, 4);
|
||||
|
||||
sz = namesz + descsz;
|
||||
|
||||
if (count < sz)
|
||||
sz = count;
|
||||
if (count < sz || dsz < sz) /* Buffers are too small. */
|
||||
return (0);
|
||||
|
||||
(void) memcpy(dst, src, sz);
|
||||
|
||||
src += sz;
|
||||
dst += sz;
|
||||
|
||||
count -= sz;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
libelf_cvt_NOTE_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
static int
|
||||
libelf_cvt_NOTE_tof(char *dst, size_t dsz, char *src, size_t count,
|
||||
int byteswap)
|
||||
{
|
||||
uint32_t namesz, descsz, type;
|
||||
Elf_Note *en;
|
||||
size_t sz;
|
||||
|
||||
if (dst == src && !byteswap)
|
||||
return;
|
||||
if (dsz < count)
|
||||
return (0);
|
||||
|
||||
if (!byteswap) {
|
||||
(void) memcpy(dst, src, count);
|
||||
return;
|
||||
return (1);
|
||||
}
|
||||
|
||||
while (count > sizeof(Elf_Note)) {
|
||||
@ -562,12 +595,9 @@ libelf_cvt_NOTE_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
descsz = en->n_descsz;
|
||||
type = en->n_type;
|
||||
|
||||
if (byteswap) {
|
||||
SWAP_WORD(namesz);
|
||||
SWAP_WORD(descsz);
|
||||
SWAP_WORD(type);
|
||||
}
|
||||
|
||||
SWAP_WORD(namesz);
|
||||
SWAP_WORD(descsz);
|
||||
SWAP_WORD(type);
|
||||
|
||||
WRITE_WORD(dst, namesz);
|
||||
WRITE_WORD(dst, descsz);
|
||||
@ -589,15 +619,21 @@ libelf_cvt_NOTE_tof(char *dst, char *src, size_t count, int byteswap)
|
||||
dst += sz;
|
||||
count -= sz;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
|
||||
|
||||
struct converters {
|
||||
void (*tof32)(char *dst, char *src, size_t cnt, int byteswap);
|
||||
void (*tom32)(char *dst, char *src, size_t cnt, int byteswap);
|
||||
void (*tof64)(char *dst, char *src, size_t cnt, int byteswap);
|
||||
void (*tom64)(char *dst, char *src, size_t cnt, int byteswap);
|
||||
int (*tof32)(char *dst, size_t dsz, char *src, size_t cnt,
|
||||
int byteswap);
|
||||
int (*tom32)(char *dst, size_t dsz, char *src, size_t cnt,
|
||||
int byteswap);
|
||||
int (*tof64)(char *dst, size_t dsz, char *src, size_t cnt,
|
||||
int byteswap);
|
||||
int (*tom64)(char *dst, size_t dsz, char *src, size_t cnt,
|
||||
int byteswap);
|
||||
};
|
||||
|
||||
divert(-1)
|
||||
@ -647,8 +683,8 @@ CONVERTER_NAMES(ELF_TYPE_LIST)
|
||||
}
|
||||
};
|
||||
|
||||
void (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
|
||||
(char *_dst, char *_src, size_t _cnt, int _byteswap)
|
||||
int (*_libelf_get_translator(Elf_Type t, int direction, int elfclass))
|
||||
(char *_dst, size_t dsz, char *_src, size_t _cnt, int _byteswap)
|
||||
{
|
||||
assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
|
||||
assert(direction == ELF_TOFILE || direction == ELF_TOMEMORY);
|
||||
|
@ -46,7 +46,7 @@ _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
|
||||
{
|
||||
Elf_Scn *scn;
|
||||
size_t fsz;
|
||||
void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
|
||||
int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
|
||||
uint32_t shtype;
|
||||
|
||||
assert(STAILQ_EMPTY(&e->e_u.e_elf.e_scn));
|
||||
@ -63,7 +63,8 @@ _libelf_load_extended(Elf *e, int ec, uint64_t shoff, uint16_t phnum,
|
||||
return (0);
|
||||
|
||||
xlator = _libelf_get_translator(ELF_T_SHDR, ELF_TOMEMORY, ec);
|
||||
(*xlator)((char *) &scn->s_shdr, e->e_rawfile + shoff, (size_t) 1,
|
||||
(*xlator)((char *) &scn->s_shdr, sizeof(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 : \
|
||||
@ -105,7 +106,7 @@ _libelf_ehdr(Elf *e, int ec, int allocate)
|
||||
size_t fsz, msz;
|
||||
uint16_t phnum, shnum, strndx;
|
||||
uint64_t shoff;
|
||||
void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
|
||||
int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
|
||||
|
||||
assert(ec == ELFCLASS32 || ec == ELFCLASS64);
|
||||
|
||||
@ -167,7 +168,7 @@ _libelf_ehdr(Elf *e, int ec, int allocate)
|
||||
return (ehdr);
|
||||
|
||||
xlator = _libelf_get_translator(ELF_T_EHDR, ELF_TOMEMORY, ec);
|
||||
(*xlator)(ehdr, e->e_rawfile, (size_t) 1,
|
||||
(*xlator)(ehdr, msz, e->e_rawfile, (size_t) 1,
|
||||
e->e_byteorder != LIBELF_PRIVATE(byteorder));
|
||||
|
||||
/*
|
||||
|
@ -45,7 +45,7 @@ _libelf_getphdr(Elf *e, int ec)
|
||||
Elf32_Ehdr *eh32;
|
||||
Elf64_Ehdr *eh64;
|
||||
void *ehdr, *phdr;
|
||||
void (*xlator)(char *_d, char *_s, size_t _c, int _swap);
|
||||
int (*xlator)(char *_d, size_t _dsz, char *_s, size_t _c, int _swap);
|
||||
|
||||
assert(ec == ELFCLASS32 || ec == ELFCLASS64);
|
||||
|
||||
@ -103,7 +103,7 @@ _libelf_getphdr(Elf *e, int ec)
|
||||
|
||||
|
||||
xlator = _libelf_get_translator(ELF_T_PHDR, ELF_TOMEMORY, ec);
|
||||
(*xlator)(phdr, e->e_rawfile + phoff, phnum,
|
||||
(*xlator)(phdr, phnum * msz, e->e_rawfile + phoff, phnum,
|
||||
e->e_byteorder != LIBELF_PRIVATE(byteorder));
|
||||
|
||||
return (phdr);
|
||||
|
@ -48,6 +48,7 @@ Elf_Data *
|
||||
_libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
|
||||
int elfclass, int direction)
|
||||
{
|
||||
int byteswap;
|
||||
size_t cnt, dsz, fsz, msz;
|
||||
uintptr_t sb, se, db, de;
|
||||
|
||||
@ -132,12 +133,17 @@ _libelf_xlate(Elf_Data *dst, const Elf_Data *src, unsigned int encoding,
|
||||
dst->d_type = src->d_type;
|
||||
dst->d_size = dsz;
|
||||
|
||||
byteswap = encoding != LIBELF_PRIVATE(byteorder);
|
||||
|
||||
if (src->d_size == 0 ||
|
||||
(db == sb && encoding == LIBELF_PRIVATE(byteorder) && fsz == msz))
|
||||
(db == sb && !byteswap && fsz == msz))
|
||||
return (dst); /* nothing more to do */
|
||||
|
||||
(_libelf_get_translator(src->d_type, direction, elfclass))(dst->d_buf,
|
||||
src->d_buf, cnt, encoding != LIBELF_PRIVATE(byteorder));
|
||||
if (!(_libelf_get_translator(src->d_type, direction, elfclass))
|
||||
(dst->d_buf, dsz, src->d_buf, cnt, byteswap)) {
|
||||
LIBELF_SET_ERROR(DATA, 0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (dst);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user