From c6e5547c9da87292c554449e8b91d83bac70b7be Mon Sep 17 00:00:00 2001
From: Peter Maydell <pmaydell@chiark.greenend.org.uk>
Date: Sun, 13 Nov 2005 22:36:07 +0000
Subject: [PATCH] Fix buffer overrun in address parsing code (would only show
 up if scan was run with -width 16536 or similar)

---
 ChangeLog |  5 +++++
 sbr/mf.c  | 55 +++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index de7542e0..7661e8a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-11-09  Peter Maydell  <pmaydell@chiark.greenend.org.uk>
+
+	* sbr/mf.c: fix buffer overrun with absurdly long addresses
+	(only causes crashes if scan is run with '-width 16536' or similar)
+
 2005-11-13  Oliver Kiddle  <okiddle@yahoo.co.uk>
 
 	* bug #7833: uip/Makefile.in: remove link to install-mh that caused
diff --git a/sbr/mf.c b/sbr/mf.c
index cb3e6e4e..27c06bb1 100644
--- a/sbr/mf.c
+++ b/sbr/mf.c
@@ -771,9 +771,13 @@ route (char *buffer)
 static int
 my_lex (char *buffer)
 {
+    /* buffer should be at least BUFSIZ bytes long */
     int i, gotat = 0;
     register char c, *bp;
 
+/* Add C to the buffer bp. After use of this macro *bp is guaranteed to be within the buffer. */
+#define ADDCHR(C) do { *bp++ = (C); if ((bp - buffer) == (BUFSIZ-1)) goto my_lex_buffull; } while (0)
+
     bp = buffer;
     *bp = 0;
     if (!cp)
@@ -788,27 +792,28 @@ my_lex (char *buffer)
 	return (last_lex = LX_END);
     }
 
-    if (c == '(')
-	for (*bp++ = c, i = 0;;)
+    if (c == '(') {
+	ADDCHR(c);
+	for (i = 0;;)
 	    switch (c = *cp++) {
 		case 0: 
 		    cp = NULL;
 		    return (last_lex = LX_ERR);
 		case QUOTE: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    if ((c = *cp++) == 0) {
 			cp = NULL;
 			return (last_lex = LX_ERR);
 		    }
-		    *bp++ = c;
+		    ADDCHR(c);
 		    continue;
 		case '(': 
 		    i++;
 		default: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    continue;
 		case ')': 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    if (--i < 0) {
 			*bp = 0;
 			note = note ? add (buffer, add (" ", note))
@@ -816,50 +821,55 @@ my_lex (char *buffer)
 			return my_lex (buffer);
 		    }
 	    }
+    }
 
-    if (c == '"')
-	for (*bp++ = c;;)
+    if (c == '"') {
+	ADDCHR(c);
+	for (;;)
 	    switch (c = *cp++) {
 		case 0: 
 		    cp = NULL;
 		    return (last_lex = LX_ERR);
 		case QUOTE: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    if ((c = *cp++) == 0) {
 			cp = NULL;
 			return (last_lex = LX_ERR);
 		    }
 		default: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    continue;
 		case '"': 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    *bp = 0;
 		    return (last_lex = LX_QSTR);
 	    }
-
-    if (c == '[')
-	for (*bp++ = c;;)
+    }
+    
+    if (c == '[') {
+	ADDCHR(c);
+	for (;;)
 	    switch (c = *cp++) {
 		case 0: 
 		    cp = NULL;
 		    return (last_lex = LX_ERR);
 		case QUOTE: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    if ((c = *cp++) == 0) {
 			cp = NULL;
 			return (last_lex = LX_ERR);
 		    }
 		default: 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    continue;
 		case ']': 
-		    *bp++ = c;
+		    ADDCHR(c);
 		    *bp = 0;
 		    return (last_lex = LX_DLIT);
 	    }
-
-    *bp++ = c;
+    }
+    
+    ADDCHR(c);
     *bp = 0;
     for (i = 0; special[i].lx_chr != 0; i++)
 	if (c == special[i].lx_chr)
@@ -876,7 +886,7 @@ my_lex (char *buffer)
 		goto got_atom;
 	if (iscntrl (c) || isspace (c))
 	    break;
-	*bp++ = c;
+	ADDCHR(c);
     }
 got_atom: ;
     if (c == 0)
@@ -887,6 +897,11 @@ got_atom: ;
     last_lex = !gotat || cp == NULL || strchr(cp, '<') != NULL
 	? LX_ATOM : LX_AT;
     return last_lex;
+
+ my_lex_buffull:
+    /* Out of buffer space. *bp is the last byte in the buffer */
+    *bp = 0;
+    return (last_lex = LX_ERR);
 }
 
 
-- 
2.39.5