CVE-2014-1236: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: Stack-based buffer overflow in the chkNum function in lib/cgraph/scan.l in Graphviz 2.34.0 allows remote attackers to have unspecified impact via vectors related to a "badly formed number" and a "long digit list."
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2014-01-10T15:55Z
Repository: https://github.com/ellson/graphviz
Language: Other
Files changed: lib/cgraph/scan.l
Commit date: 2014-01-08 11:31:04 -0500
Commit message: Fix possible buffer overflow problem in chkNum of scanner.

Diff: diff --git a/lib/cgraph/scan.l b/lib/cgraph/scan.l
index 212967c70..d065b61fb 100644
--- a/lib/cgraph/scan.l
+++ b/lib/cgraph/scan.l
@@ -127,19 +127,36 @@ static void ppDirective (void)
  * The regexp for NUMBER allows a terminating letter.
  * This way we can catch a number immediately followed by a name
  * and report this to the user.
  */
 static int chkNum(void) {
-  unsigned char	c = (unsigned char)yytext[yyleng-1];   /* last character */
-  if (!isdigit(c) && (c != '.')) {  /* c is letter */
-	char	buf[BUFSIZ];
-	sprintf(buf,"syntax error - badly formed number '%s' in line %d of %s\n",yytext,line_num, InputFile);
-    strcat (buf, "splits into two name tokens\n");
-	agerr(AGWARN,buf);
-    return 1;
-  }
-  else return 0;
+    unsigned char c = (unsigned char)yytext[yyleng-1];   /* last character */
+    if (!isdigit(c) && (c != '.')) {  /* c is letter */
+	unsigned char xbuf[BUFSIZ];
+	char buf[BUFSIZ];
+	agxbuf  xb;
+	char* fname;
+
+	if (InputFile)
+	    fname = InputFile;
+	else
+	    fname = "input";
+
+	agxbinit(&xb, BUFSIZ, xbuf);
+
+	agxbput(&xb,"syntax ambiguity - badly delimited number '");
+	agxbput(&xb,yytext);
+	sprintf(buf,"' in line %d of ", line_num);
+	agxbput(&xb,buf);
+	agxbput(&xb,fname);
+	agxbput(&xb, " splits into two tokens\n");
+	agerr(AGWARN,agxbuse(&xb));
+
+	agxbfree(&xb);
+	return 1;
+    }
+    else return 0;
 }
 
 /* The LETTER class below consists of ascii letters, underscore, all non-ascii
  * characters. This allows identifiers to have characters from any
  * character set independent of locale. The downside is that, for certain

Vulnerable code:   unsigned char	c = (unsigned char)yytext[yyleng-1];   /* last character */
  if (!isdigit(c) && (c != '.')) {  /* c is letter */
	char	buf[BUFSIZ];
	sprintf(buf,"syntax error - badly formed number '%s' in line %d of %s\n",yytext,line_num, InputFile);
    strcat (buf, "splits into two name tokens\n");
	agerr(AGWARN,buf);
    return 1;
  }
  else return 0;
Fixed code:     unsigned char c = (unsigned char)yytext[yyleng-1];   /* last character */
    if (!isdigit(c) && (c != '.')) {  /* c is letter */
	unsigned char xbuf[BUFSIZ];
	char buf[BUFSIZ];
	agxbuf  xb;
	char* fname;

	if (InputFile)
	    fname = InputFile;
	else
	    fname = "input";

	agxbinit(&xb, BUFSIZ, xbuf);

	agxbput(&xb,"syntax ambiguity - badly delimited number '");
	agxbput(&xb,yytext);
	sprintf(buf,"' in line %d of ", line_num);
	agxbput(&xb,buf);
	agxbput(&xb,fname);
	agxbput(&xb, " splits into two tokens\n");
	agerr(AGWARN,agxbuse(&xb));

	agxbfree(&xb);
	return 1;
    }
    else return 0;