This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] readelf.c: fix multiple pointer overflows
- From: Xi Wang <xi dot wang at gmail dot com>
- To: binutils at sourceware dot org
- Cc: Xi Wang <xi dot wang at gmail dot com>
- Date: Mon, 28 Jan 2013 17:02:49 -0500
- Subject: [PATCH] readelf.c: fix multiple pointer overflows
Many compilers such as gcc and clang optimize away overflow checks
`p + n < p', because in C pointer overflow is undefined behavior.
Use a safe form `n > end - p' instead.
---
To verify this problem, compile the following simplified code.
void bar(void);
void foo(char *p, unsigned int n)
{
if (p + n < p)
bar();
}
$ gcc -S -o - -O2 p.c
...
foo:
.LFB0:
.cfi_startproc
rep
ret
.cfi_endproc
The overflow check is gone (gcc 4.7.2, x86-64).
---
binutils/readelf.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/binutils/readelf.c b/binutils/readelf.c
index f880825..b6dd390 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -8469,8 +8469,8 @@ process_version_sections (FILE * file)
int j;
int isum;
- /* Check for negative or very large indicies. */
- if ((unsigned char *) edefs + idx < (unsigned char *) edefs)
+ /* Check for very large indicies. */
+ if (idx > (size_t) (endbuf - (char *) edefs))
break;
vstart = ((char *) edefs) + idx;
@@ -8494,8 +8494,7 @@ process_version_sections (FILE * file)
ent.vd_ndx, ent.vd_cnt);
/* Check for overflow. */
- if ((unsigned char *)(vstart + ent.vd_aux) < (unsigned char *) vstart
- || (unsigned char *)(vstart + ent.vd_aux) > (unsigned char *) endbuf)
+ if (ent.vd_aux > (size_t) (endbuf - vstart))
break;
vstart += ent.vd_aux;
@@ -8515,8 +8514,7 @@ process_version_sections (FILE * file)
for (j = 1; j < ent.vd_cnt; j++)
{
/* Check for overflow. */
- if ((unsigned char *)(vstart + aux.vda_next) < (unsigned char *) vstart
- || (unsigned char *)(vstart + aux.vda_next) > (unsigned char *) endbuf)
+ if (aux.vda_next > (size_t) (endbuf - vstart))
break;
isum += aux.vda_next;
@@ -8586,7 +8584,7 @@ process_version_sections (FILE * file)
int isum;
char * vstart;
- if ((unsigned char *) eneed + idx < (unsigned char *) eneed)
+ if (idx > (size_t) (endbuf - (char *) eneed))
break;
vstart = ((char *) eneed) + idx;
@@ -8611,8 +8609,7 @@ process_version_sections (FILE * file)
printf (_(" Cnt: %d\n"), ent.vn_cnt);
/* Check for overflow. */
- if ((unsigned char *)(vstart + ent.vn_aux) < (unsigned char *) vstart
- || (unsigned char *)(vstart + ent.vn_aux) > (unsigned char *) endbuf)
+ if (ent.vn_aux > (size_t) (endbuf - vstart))
break;
vstart += ent.vn_aux;
@@ -8643,8 +8640,7 @@ process_version_sections (FILE * file)
get_ver_flags (aux.vna_flags), aux.vna_other);
/* Check for overflow. */
- if ((unsigned char *)(vstart + aux.vna_next) < (unsigned char *) vstart
- || (unsigned char *)(vstart + aux.vna_next) > (unsigned char *) endbuf)
+ if (aux.vna_next > (size_t) (endbuf - vstart))
break;
isum += aux.vna_next;
--
1.7.10.4