Author: kaiw
Date: Wed Jul 21 10:25:02 2010
New Revision: 210338
URL: http://svn.freebsd.org/changeset/base/210338

Log:
  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

Modified:
  head/lib/libelf/_libelf.h
  head/lib/libelf/elf_data.c
  head/lib/libelf/elf_scn.c
  head/lib/libelf/libelf_convert.m4
  head/lib/libelf/libelf_ehdr.c
  head/lib/libelf/libelf_phdr.c
  head/lib/libelf/libelf_xlate.c

Modified: head/lib/libelf/_libelf.h
==============================================================================
--- head/lib/libelf/_libelf.h   Wed Jul 21 10:14:04 2010        (r210337)
+++ head/lib/libelf/_libelf.h   Wed Jul 21 10:25:02 2010        (r210338)
@@ -171,8 +171,8 @@ void        *_libelf_ehdr(Elf *_e, int _elfclas
 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);

Modified: head/lib/libelf/elf_data.c
==============================================================================
--- head/lib/libelf/elf_data.c  Wed Jul 21 10:14:04 2010        (r210337)
+++ head/lib/libelf/elf_data.c  Wed Jul 21 10:25:02 2010        (r210338)
@@ -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);
 }

Modified: head/lib/libelf/elf_scn.c
==============================================================================
--- head/lib/libelf/elf_scn.c   Wed Jul 21 10:14:04 2010        (r210337)
+++ head/lib/libelf/elf_scn.c   Wed Jul 21 10:25:02 2010        (r210338)
@@ -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 =

Modified: head/lib/libelf/libelf_convert.m4
==============================================================================
--- head/lib/libelf/libelf_convert.m4   Wed Jul 21 10:14:04 2010        
(r210337)
+++ head/lib/libelf/libelf_convert.m4   Wed Jul 21 10:25:02 2010        
(r210338)
@@ -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
                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
                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
                }
                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
        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
                }
                *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
  *
  * 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 (dsz < count)        /* Destination buffer is too small. */
+               return (0);
 
-       if (dst == src && !byteswap)
-               return;
+       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
                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
                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);

Modified: head/lib/libelf/libelf_ehdr.c
==============================================================================
--- head/lib/libelf/libelf_ehdr.c       Wed Jul 21 10:14:04 2010        
(r210337)
+++ head/lib/libelf/libelf_ehdr.c       Wed Jul 21 10:25:02 2010        
(r210338)
@@ -46,7 +46,7 @@ _libelf_load_extended(Elf *e, int ec, ui
 {
        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, ui
                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 allocat
        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 allocat
                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));
 
        /*

Modified: head/lib/libelf/libelf_phdr.c
==============================================================================
--- head/lib/libelf/libelf_phdr.c       Wed Jul 21 10:14:04 2010        
(r210337)
+++ head/lib/libelf/libelf_phdr.c       Wed Jul 21 10:25:02 2010        
(r210338)
@@ -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);

Modified: head/lib/libelf/libelf_xlate.c
==============================================================================
--- head/lib/libelf/libelf_xlate.c      Wed Jul 21 10:14:04 2010        
(r210337)
+++ head/lib/libelf/libelf_xlate.c      Wed Jul 21 10:25:02 2010        
(r210338)
@@ -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_D
        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);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to