svn commit: r212208 - stable/8/lib/libelf

Kai Wang kaiw at FreeBSD.org
Sat Sep 4 13:13:01 UTC 2010


Author: kaiw
Date: Sat Sep  4 13:13:00 2010
New Revision: 212208
URL: http://svn.freebsd.org/changeset/base/212208

Log:
  MFC r210331-r210333,r210335,r210336,r210338,r210340,r210341,r210559.
  
  r210331:
    Add a new ELF type denoting GNU style hash tables.
  
  r210332:
    Changes for supporting GNU Hash sections.
  
  r210333:
    Note that the *_fsize() functions are only defined for ELF types that
    have a fixed size.
  
  r210335:
    - Return zero for file sizes of ELF types that have a variable size.
    - Neaten a few comments.
  
  r210336:
    Reduce verbosity.
  
  r210338:
    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.
  
  r210340:
    - Document that the *fsize() functions return a size of 1 for Elf
      types that don't have a fixed size.
    - The *fsize() functions should return a size of 1, for variable length
      types.
    - Redefine symbol ELF_T_LAST to match the current end of the list.
  
  r210341:
    Add support for translating sections of type ELF_T_GNUHASH.
  
  r210559:
    Protect GNUHASH translation functions with #ifdef; unbreak cross
    toolchain build.

Modified:
  stable/8/lib/libelf/_libelf.h
  stable/8/lib/libelf/elf_data.c
  stable/8/lib/libelf/elf_scn.c
  stable/8/lib/libelf/elf_types.m4
  stable/8/lib/libelf/gelf_fsize.3
  stable/8/lib/libelf/libelf.h
  stable/8/lib/libelf/libelf_align.c
  stable/8/lib/libelf/libelf_convert.m4
  stable/8/lib/libelf/libelf_data.c
  stable/8/lib/libelf/libelf_ehdr.c
  stable/8/lib/libelf/libelf_fsize.m4
  stable/8/lib/libelf/libelf_msize.m4
  stable/8/lib/libelf/libelf_phdr.c
  stable/8/lib/libelf/libelf_xlate.c
Directory Properties:
  stable/8/lib/libelf/   (props changed)

Modified: stable/8/lib/libelf/_libelf.h
==============================================================================
--- stable/8/lib/libelf/_libelf.h	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/_libelf.h	Sat Sep  4 13:13:00 2010	(r212208)
@@ -175,8 +175,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: stable/8/lib/libelf/elf_data.c
==============================================================================
--- stable/8/lib/libelf/elf_data.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/elf_data.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -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: stable/8/lib/libelf/elf_scn.c
==============================================================================
--- stable/8/lib/libelf/elf_scn.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/elf_scn.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -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: stable/8/lib/libelf/elf_types.m4
==============================================================================
--- stable/8/lib/libelf/elf_types.m4	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/elf_types.m4	Sat Sep  4 13:13:00 2010	(r212208)
@@ -46,6 +46,7 @@ define(`ELF_TYPE_LIST',
 	`CAP,		Cap,	700025',
 	`DYN,		Dyn,	600102',
 	`EHDR,		Ehdr,	600102',
+	`GNUHASH,	-,	800062',
 	`HALF,		Half,	600102',
 	`LWORD,		Lword,	700025',
 	`MOVE,		Move,	700025',

Modified: stable/8/lib/libelf/gelf_fsize.3
==============================================================================
--- stable/8/lib/libelf/gelf_fsize.3	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/gelf_fsize.3	Sat Sep  4 13:13:00 2010	(r212208)
@@ -47,6 +47,8 @@ These functions return the size in bytes
 .Ar count
 numbers of objects of ELF type
 .Ar type .
+For ELF types that are of variable length, these functions return a
+size of one byte.
 .Pp
 Functions
 .Fn elf32_fsize

Modified: stable/8/lib/libelf/libelf.h
==============================================================================
--- stable/8/lib/libelf/libelf.h	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf.h	Sat Sep  4 13:13:00 2010	(r212208)
@@ -75,11 +75,12 @@ typedef enum {
 	ELF_T_VNEED,
 	ELF_T_WORD,
 	ELF_T_XWORD,
+	ELF_T_GNUHASH,	/* GNU style hash tables. */
 	ELF_T_NUM
 } Elf_Type;
 
 #define	ELF_T_FIRST	ELF_T_ADDR
-#define	ELF_T_LAST	ELF_T_XWORD
+#define	ELF_T_LAST	ELF_T_GNUHASH
 
 /* Commands */
 typedef enum {

Modified: stable/8/lib/libelf/libelf_align.c
==============================================================================
--- stable/8/lib/libelf/libelf_align.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_align.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -51,6 +51,10 @@ struct align {
 		.a32 = 0,					\
 		.a64 = __alignof__(Elf64_##V)			\
 	}
+#define	MALIGN_WORD()	{					\
+		.a32 = __alignof__(int32_t),			\
+		.a64 = __alignof__(int64_t)			\
+	    }
 #else
 #error	Need the __alignof__ builtin.
 #endif
@@ -92,7 +96,10 @@ static struct align malign[ELF_T_NUM] = 
 	[ELF_T_VNEED]	= MALIGN(Verneed),
 #endif
 	[ELF_T_WORD]	= MALIGN(Word),
-	[ELF_T_XWORD]	= MALIGN64(Xword)
+	[ELF_T_XWORD]	= MALIGN64(Xword),
+#if	__FreeBSD_version >= 800062
+	[ELF_T_GNUHASH] = MALIGN_WORD()
+#endif
 };
 
 int
@@ -140,7 +147,10 @@ static struct align falign[ELF_T_NUM] = 
 	[ELF_T_VNEED]	= FALIGN(4,4),
 #endif
 	[ELF_T_WORD]	= FALIGN(4,4),
-	[ELF_T_XWORD]	= FALIGN(0,8)
+	[ELF_T_XWORD]	= FALIGN(0,8),
+#if	__FreeBSD_version >= 800062
+	[ELF_T_GNUHASH] = FALIGN(4,8)
+#endif
 };
 
 int

Modified: stable/8/lib/libelf/libelf_convert.m4
==============================================================================
--- stable/8/lib/libelf/libelf_convert.m4	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_convert.m4	Sat Sep  4 13:13:00 2010	(r212208)
@@ -234,8 +234,10 @@ define(`IGNORE',
 
 IGNORE(MOVEP)
 IGNORE(NOTE)
+IGNORE(GNUHASH)
 
 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 +276,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 +295,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 +321,8 @@ libelf_cvt_$1$3_tom(char *dst, char *src
 		SWAP_$1$3(t);
 		*d++ = t;
 	}
+
+	return (1);
 }
 ')
 
@@ -392,12 +399,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 +416,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;
 	char		*s,*s0;
@@ -422,6 +435,9 @@ libelf_cvt$3_$1_tom(char *dst, char *src
 	d   = ((Elf$3_$2 *) (uintptr_t) dst) + (count - 1);
 	s0  = (char *) src + (count - 1) * fsz;
 
+	if (dsz < count * sizeof(Elf$3_$2))
+		return (0);
+
 	while (count--) {
 		s = s0;
 		READ_STRUCT($2,$3)
@@ -430,6 +446,8 @@ libelf_cvt$3_$1_tom(char *dst, char *src
 		}
 		*d-- = t; s0 -= fsz;
 	}
+
+	return (1);
 }
 ')')
 
@@ -475,84 +493,300 @@ 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);
 }
 
+MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
+
+#if	__FreeBSD_version >= 800062
+/*
+ * Sections of type ELF_T_GNUHASH start with a header containing 4 32-bit
+ * words.  Bloom filter data comes next, followed by hash buckets and the
+ * hash chain.
+ *
+ * Bloom filter words are 64 bit wide on ELFCLASS64 objects and are 32 bit
+ * wide on ELFCLASS32 objects.  The other objects in this section are 32
+ * bits wide.
+ *
+ * Argument `srcsz' denotes the number of bytes to be converted.  In the
+ * 32-bit case we need to translate `srcsz' to a count of 32-bit words.
+ */
+
+static int
+libelf_cvt32_GNUHASH_tom(char *dst, size_t dsz, char *src, size_t srcsz,
+    int byteswap)
+{
+	return (libelf_cvt_WORD_tom(dst, dsz, src, srcsz / sizeof(uint32_t),
+	        byteswap));
+}
+
+static int
+libelf_cvt32_GNUHASH_tof(char *dst, size_t dsz, char *src, size_t srcsz,
+    int byteswap)
+{
+	return (libelf_cvt_WORD_tof(dst, dsz, src, srcsz / sizeof(uint32_t),
+	        byteswap));
+}
+
+static int
+libelf_cvt64_GNUHASH_tom(char *dst, size_t dsz, char *src, size_t srcsz,
+    int byteswap)
+{
+	size_t sz;
+	uint64_t t64, *bloom64;
+	Elf_GNU_Hash_Header *gh;
+	uint32_t n, nbuckets, nchains, maskwords, shift2, symndx, t32;
+	uint32_t *buckets, *chains;
+
+	sz = 4 * sizeof(uint32_t);	/* File header is 4 words long. */
+	if (dsz < sizeof(Elf_GNU_Hash_Header) || srcsz < sz)
+		return (0);
+
+	/* Read in the section header and byteswap if needed. */
+	READ_WORD(src, nbuckets);
+	READ_WORD(src, symndx);
+	READ_WORD(src, maskwords);
+	READ_WORD(src, shift2);
+
+	srcsz -= sz;
+
+	if (byteswap) {
+		SWAP_WORD(nbuckets);
+		SWAP_WORD(symndx);
+		SWAP_WORD(maskwords);
+		SWAP_WORD(shift2);
+	}
+
+	/* Check source buffer and destination buffer sizes. */
+	sz = nbuckets * sizeof(uint32_t) + maskwords * sizeof(uint64_t);
+	if (srcsz < sz || dsz < sz + sizeof(Elf_GNU_Hash_Header))
+		return (0);
+
+	gh = (Elf_GNU_Hash_Header *) (uintptr_t) dst;
+	gh->gh_nbuckets  = nbuckets;
+	gh->gh_symndx    = symndx;
+	gh->gh_maskwords = maskwords;
+	gh->gh_shift2    = shift2;
+	
+	dsz -= sizeof(Elf_GNU_Hash_Header);
+	dst += sizeof(Elf_GNU_Hash_Header);
+
+	bloom64 = (uint64_t *) (uintptr_t) dst;
+
+	/* Copy bloom filter data. */
+	for (n = 0; n < maskwords; n++) {
+		READ_XWORD(src, t64);
+		if (byteswap)
+			SWAP_XWORD(t64);
+		bloom64[n] = t64;
+	}
+
+	/* The hash buckets follows the bloom filter. */
+	dst += maskwords * sizeof(uint64_t);
+	buckets = (uint32_t *) (uintptr_t) dst;
+
+	for (n = 0; n < nbuckets; n++) {
+		READ_WORD(src, t32);
+		if (byteswap)
+			SWAP_WORD(t32);
+		buckets[n] = t32;
+	}
+
+	dst += nbuckets * sizeof(uint32_t);
+
+	/* The hash chain follows the hash buckets. */
+	dsz -= sz;
+	srcsz -= sz;
+
+	if (dsz < srcsz)	/* Destination lacks space. */
+	        return (0);
+
+	nchains = srcsz / sizeof(uint32_t);
+	chains = (uint32_t *) (uintptr_t) dst;
+
+	for (n = 0; n < nchains; n++) {
+		READ_WORD(src, t32);
+		if (byteswap)
+			SWAP_WORD(t32);
+		*chains++ = t32;
+	}
+
+	return (1);
+}
+
+static int
+libelf_cvt64_GNUHASH_tof(char *dst, size_t dsz, char *src, size_t srcsz,
+    int byteswap)
+{
+	uint32_t *s32;
+	size_t sz, hdrsz;
+	uint64_t *s64, t64;
+	Elf_GNU_Hash_Header *gh;
+	uint32_t maskwords, n, nbuckets, nchains, t0, t1, t2, t3, t32;
+
+	hdrsz = 4 * sizeof(uint32_t);	/* Header is 4x32 bits. */
+	if (dsz < hdrsz || srcsz < sizeof(Elf_GNU_Hash_Header))
+		return (0);
+
+	gh = (Elf_GNU_Hash_Header *) (uintptr_t) src;
+
+	t0 = nbuckets = gh->gh_nbuckets;
+	t1 = gh->gh_symndx;
+	t2 = maskwords = gh->gh_maskwords;
+	t3 = gh->gh_shift2;
+
+	src   += sizeof(Elf_GNU_Hash_Header);
+	srcsz -= sizeof(Elf_GNU_Hash_Header);
+	dsz   -= hdrsz;
+
+	sz = gh->gh_nbuckets * sizeof(uint32_t) + gh->gh_maskwords *
+	    sizeof(uint64_t);
+
+	if (srcsz < sz || dsz < sz)
+		return (0);
+
+ 	/* Write out the header. */
+	if (byteswap) {
+		SWAP_WORD(t0);
+		SWAP_WORD(t1);
+		SWAP_WORD(t2);
+		SWAP_WORD(t3);
+	}
+
+	WRITE_WORD(dst, t0);
+	WRITE_WORD(dst, t1);
+	WRITE_WORD(dst, t2);
+	WRITE_WORD(dst, t3);
+
+	/* Copy the bloom filter and the hash table. */
+	s64 = (uint64_t *) (uintptr_t) src;
+	for (n = 0; n < maskwords; n++) {
+		t64 = *s64++;
+		if (byteswap)
+			SWAP_XWORD(t64);
+		WRITE_WORD64(dst, t64);
+	}
+
+	s32 = (uint32_t *) s64;
+	for (n = 0; n < nbuckets; n++) {
+		t32 = *s32++;
+		if (byteswap)
+			SWAP_WORD(t32);
+		WRITE_WORD(dst, t32);
+	}
+
+	srcsz -= sz;
+	dsz   -= sz;
+
+	/* Copy out the hash chains. */
+	if (dsz < srcsz)
+		return (0);
+
+	nchains = srcsz / sizeof(uint32_t);
+	for (n = 0; n < nchains; n++) {
+		t32 = *s32++;
+		if (byteswap)
+			SWAP_WORD(t32);
+		WRITE_WORD(dst, t32);
+	}
+
+	return (1);
+}
+#endif
+
 /*
  * Elf_Note structures comprise a fixed size header followed by variable
  * length strings.  The fixed size header needs to be byte swapped, but
  * not the strings.
  *
  * Argument `count' denotes the total number of bytes to be converted.
+ * The destination buffer needs to be at least `count' bytes in size.
  */
-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;
+		dsz -= 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 +796,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 +820,19 @@ libelf_cvt_NOTE_tof(char *dst, char *src
 		dst += sz;
 		count -= sz;
 	}
-}
 
-MAKE_TYPE_CONVERTERS(ELF_TYPE_LIST)
+	return (1);
+}
 
 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)
@@ -639,6 +874,16 @@ CONVERTER_NAMES(ELF_TYPE_LIST)
 		.tof64 = libelf_cvt_BYTE_tox,
 		.tom64 = libelf_cvt_BYTE_tox
 	},
+
+#if	__FreeBSD_version >= 800062
+	[ELF_T_GNUHASH] = {
+		.tof32 = libelf_cvt32_GNUHASH_tof,
+		.tom32 = libelf_cvt32_GNUHASH_tom,
+		.tof64 = libelf_cvt64_GNUHASH_tof,
+		.tom64 = libelf_cvt64_GNUHASH_tom
+	},
+#endif
+
 	[ELF_T_NOTE] = {
 		.tof32 = libelf_cvt_NOTE_tof,
 		.tom32 = libelf_cvt_NOTE_tom,
@@ -647,8 +892,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: stable/8/lib/libelf/libelf_data.c
==============================================================================
--- stable/8/lib/libelf/libelf_data.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_data.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -42,6 +42,10 @@ _libelf_xlate_shtype(uint32_t sht)
 		return (ELF_T_SYM);
 	case SHT_FINI_ARRAY:
 		return (ELF_T_ADDR);
+#if	__FreeBSD_version >= 800062
+	case SHT_GNU_HASH:
+		return (ELF_T_GNUHASH);
+#endif
 	case SHT_GROUP:
 		return (ELF_T_WORD);
 	case SHT_HASH:

Modified: stable/8/lib/libelf/libelf_ehdr.c
==============================================================================
--- stable/8/lib/libelf/libelf_ehdr.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_ehdr.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -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: stable/8/lib/libelf/libelf_fsize.m4
==============================================================================
--- stable/8/lib/libelf/libelf_fsize.m4	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_fsize.m4	Sat Sep  4 13:13:00 2010	(r212208)
@@ -43,15 +43,18 @@ include(SRCDIR`/elf_types.m4')
  * representations.
  */
 
-/* `Basic' types */
+/* `Basic' types. */
 define(`BYTE_SIZE',	1)
 define(`IDENT_SIZE',	`EI_NIDENT')
-define(`NOTE_SIZE',	1) /* Elf_Note structures have variable length. */
 
-/* Currently unimplemented types */
+/* Types that have variable length. */
+define(`GNUHASH_SIZE',	1)
+define(`NOTE_SIZE',	1)
+
+/* Currently unimplemented types. */
 define(`MOVEP_SIZE',	0)
 
-/* Overrides for 32 bit types that do not exist */
+/* Overrides for 32 bit types that do not exist. */
 define(`XWORD_SIZE32',	0)
 define(`SXWORD_SIZE32',	0)
 

Modified: stable/8/lib/libelf/libelf_msize.m4
==============================================================================
--- stable/8/lib/libelf/libelf_msize.m4	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_msize.m4	Sat Sep  4 13:13:00 2010	(r212208)
@@ -49,6 +49,7 @@ divert(-1)
 include(SRCDIR`/elf_types.m4')
 
 define(BYTE_SIZE,	1)
+define(GNUHASH_SIZE,	1)
 define(NOTE_SIZE,	1)
 
 /*

Modified: stable/8/lib/libelf/libelf_phdr.c
==============================================================================
--- stable/8/lib/libelf/libelf_phdr.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_phdr.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -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: stable/8/lib/libelf/libelf_xlate.c
==============================================================================
--- stable/8/lib/libelf/libelf_xlate.c	Sat Sep  4 13:00:28 2010	(r212207)
+++ stable/8/lib/libelf/libelf_xlate.c	Sat Sep  4 13:13:00 2010	(r212208)
@@ -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);
 }


More information about the svn-src-stable-8 mailing list