This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]