Bug 1174015: Keep the maxlen member of SprintfState under PR_INT32_MAX.
authorWan-Teh Chang <wtc@google.com>
Wed, 25 Nov 2015 14:04:47 -0800
changeset 4662 96381e3aaae27d50ddd877451c0b31d260c59931
parent 4661 aea5ad424c3bae2b67920d9afd7a6ce0df753b0a
child 4663 0c58fe90cf11dd55abefe640a312aa656499a1eb
push id193
push userwtc@google.com
push dateWed, 25 Nov 2015 22:04:54 +0000
bugs1174015
Bug 1174015: Keep the maxlen member of SprintfState under PR_INT32_MAX. r=kaie.
pr/src/io/prprf.c
--- a/pr/src/io/prprf.c
+++ b/pr/src/io/prprf.c
@@ -32,17 +32,17 @@
 
 typedef struct SprintfStateStr SprintfState;
 
 struct SprintfStateStr {
     int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
 
     char *base;
     char *cur;
-    PRUint32 maxlen;
+    PRUint32 maxlen;  /* Must not exceed PR_INT32_MAX. */
 
     int (*func)(void *arg, const char *sp, PRUint32 len);
     void *arg;
 };
 
 /*
 ** Numbered Argument
 */
@@ -1055,16 +1055,23 @@ static int dosprintf(SprintfState *ss, c
 }
 
 /************************************************************************/
 
 static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
 {
     int rv;
 
+    /*
+    ** We will add len to ss->maxlen at the end of the function. First check
+    ** if ss->maxlen + len would overflow or be greater than PR_INT32_MAX.
+    */
+    if (PR_UINT32_MAX - ss->maxlen < len || ss->maxlen + len > PR_INT32_MAX) {
+	return -1;
+    }
     rv = (*ss->func)(ss->arg, sp, len);
     if (rv < 0) {
 	return rv;
     }
     ss->maxlen += len;
     return 0;
 }
 
@@ -1100,19 +1107,31 @@ PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRSt
 */
 static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
 {
     ptrdiff_t off;
     char *newbase;
     PRUint32 newlen;
 
     off = ss->cur - ss->base;
+    if (PR_UINT32_MAX - len < off) {
+	/* off + len would be too big. */
+	return -1;
+    }
     if (off + len >= ss->maxlen) {
 	/* Grow the buffer */
-	newlen = ss->maxlen + ((len > 32) ? len : 32);
+	PRUint32 increment = (len > 32) ? len : 32;
+	if (PR_UINT32_MAX - ss->maxlen < increment) {
+	    /* ss->maxlen + increment would overflow. */
+	    return -1;
+	}
+	newlen = ss->maxlen + increment;
+	if (newlen > PR_INT32_MAX) {
+	    return -1;
+	}
 	if (ss->base) {
 	    newbase = (char*) PR_REALLOC(ss->base, newlen);
 	} else {
 	    newbase = (char*) PR_MALLOC(newlen);
 	}
 	if (!newbase) {
 	    /* Ran out of memory */
 	    return -1;
@@ -1205,18 +1224,18 @@ PR_IMPLEMENT(PRUint32) PR_snprintf(char 
 }
 
 PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
                                   va_list ap)
 {
     SprintfState ss;
     PRUint32 n;
 
-    PR_ASSERT((PRInt32)outlen > 0);
-    if ((PRInt32)outlen <= 0) {
+    PR_ASSERT(outlen != 0 && outlen <= PR_INT32_MAX);
+    if (outlen == 0 || outlen > PR_INT32_MAX) {
 	return 0;
     }
 
     ss.stuff = LimitStuff;
     ss.base = out;
     ss.cur = out;
     ss.maxlen = outlen;
     (void) dosprintf(&ss, fmt, ap);
@@ -1242,17 +1261,20 @@ PR_IMPLEMENT(char *) PR_sprintf_append(c
 
 PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
 {
     SprintfState ss;
     int rv;
 
     ss.stuff = GrowStuff;
     if (last) {
-	int lastlen = strlen(last);
+	size_t lastlen = strlen(last);
+	if (lastlen > PR_INT32_MAX) {
+	    return 0;
+	}
 	ss.base = last;
 	ss.cur = last + lastlen;
 	ss.maxlen = lastlen;
     } else {
 	ss.base = 0;
 	ss.cur = 0;
 	ss.maxlen = 0;
     }