ccfilter: buffer overflow in ccfilter.c with crafted compiler output
Commit:
https://github.com/vim/vim/commit/a092d249b6066401dda0964ceeb213062785bbc8
Author: Hirohito Higashi <[email protected]>
Date: Thu Jun 18 20:12:48 2026 +0000
ccfilter: buffer overflow in ccfilter.c with crafted compiler output
Problem: ccfilter: can overflow fixed-size buffers (FileName, BasePath,
Reason) when parsing crafted compiler output, because the
sscanf() calls read "%[" fields without a width limit (DDugs)
Solution: Give every sscanf() "%[" conversion a width limit derived from
the buffer size (Hirohito Higashi).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Hirohito Higashi <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
diff --git a/runtime/tools/ccfilter.c b/runtime/tools/ccfilter.c
index 269e4ee66..5fe6307bf 100644
--- a/runtime/tools/ccfilter.c
+++ b/runtime/tools/ccfilter.c
@@ -18,15 +18,24 @@
#include <string.h>
#include <unistd.h>
-#define LINELENGTH 2048
+/*
+ * sscanf() needs a literal field width on each "%[", so define the widths
+ * once and derive the buffer sizes (width + 1) and format widths (via STR()).
+ */
+#define STR_(x) #x
+#define STR(x) STR_(x)
+#define LINEWIDTH 2047
+#define LINELENGTH (LINEWIDTH + 1)
+#define PATHWIDTH 1023
+#define PATHLENGTH (PATHWIDTH + 1)
/* Collector(s) */
char Line[LINELENGTH];
char Line2[LINELENGTH];
/* Components */
-char FileName[1024];
-char BasePath[1024];
-char CWD[1024];
+char FileName[PATHLENGTH];
+char BasePath[PATHLENGTH];
+char CWD[PATHLENGTH];
unsigned long Row;
unsigned long Col;
char Severity;
@@ -184,7 +193,7 @@ int main( int argc, char *argv[] )
case COMPILER_GCC:
Severity = 'e';
#ifdef GOTO_FROM_WHERE_INCLUDED
- rv = sscanf( Line, "In file included from %[^:]:%lu:",
+ rv = sscanf( Line, "In file included from %" STR(PATHWIDTH)
"[^:]:%lu:",
FileName, &Row );
if ( rv == 2 )
{
@@ -193,11 +202,11 @@ int main( int argc, char *argv[] )
else
#endif
{
- if ((rv = sscanf( Line, "%[^:]:%lu: warning: %[^
]",
+ if ((rv = sscanf( Line, "%" STR(PATHWIDTH) "[^:]:%lu: warning:
%" STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason ))==3) {
Severity = 'w';
} else {
- rv = sscanf( Line, "%[^:]:%lu: %[^
]",
+ rv = sscanf( Line, "%" STR(PATHWIDTH) "[^:]:%lu: %"
STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason );
}
ok = ( rv == 3 );
@@ -205,24 +214,24 @@ int main( int argc, char *argv[] )
Col = (dec_col ? 1 : 0 );
break;
case COMPILER_AIX:
- rv = sscanf( Line, "\"%[^\"]\", line %lu.%lu: %*s (%c) %[^
]",
+ rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu.%lu: %*s
(%c) %" STR(LINEWIDTH) "[^
]",
FileName, &Row, &Col, &Severity, Reason );
ok = ( rv == 5 );
break;
case COMPILER_HPUX:
- rv = sscanf( Line, "cc: \"%[^\"]\", line %lu: %c%*[^:]: %[^
]",
+ rv = sscanf( Line, "cc: \"%" STR(PATHWIDTH) "[^\"]\", line %lu:
%c%*[^:]: %" STR(LINEWIDTH) "[^
]",
FileName, &Row, &Severity, Reason );
ok = ( rv == 4 );
Col = (dec_col ? 1 : 0 );
break;
case COMPILER_SOLARIS:
- rv = sscanf( Line, "\"%[^\"]\", line %lu: warning: %[^
]",
+ rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu:
warning: %" STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason );
Severity = 'w';
ok = ( rv == 3 );
if ( rv != 3 )
{
- rv = sscanf( Line, "\"%[^\"]\", line %lu: %[^
]",
+ rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu: %"
STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason );
Severity = 'e';
ok = ( rv == 3 );
@@ -230,18 +239,18 @@ int main( int argc, char *argv[] )
Col = (dec_col ? 1 : 0 );
break;
case COMPILER_ATT:
- rv = sscanf( Line, "%c \"%[^\"]\",L%lu/C%lu%*[^:]:%[^
]",
+ rv = sscanf( Line, "%c \"%" STR(PATHWIDTH)
"[^\"]\",L%lu/C%lu%*[^:]:%" STR(LINEWIDTH) "[^
]",
&Severity, FileName, &Row, &Col, Reason );
ok = ( rv == 5 );
if (rv != 5)
- { rv = sscanf( Line, "%c \"%[^\"]\",L%lu/C%lu: %[^
]",
+ { rv = sscanf( Line, "%c \"%" STR(PATHWIDTH)
"[^\"]\",L%lu/C%lu: %" STR(LINEWIDTH) "[^
]",
&Severity, FileName, &Row, &Col, Reason );
ok = ( rv == 5 );
}
if (rv != 5)
- { rv = sscanf( Line, "%c \"%[^\"]\",L%lu: %[^
]",
+ { rv = sscanf( Line, "%c \"%" STR(PATHWIDTH) "[^\"]\",L%lu: %"
STR(LINEWIDTH) "[^
]",
&Severity, FileName, &Row, Reason );
ok = ( rv == 4 );
Col = (dec_col ? 1 : 0 );
@@ -273,10 +282,10 @@ int main( int argc, char *argv[] )
}
else
{
- rv = sscanf( p+2, "%[^:]: %lu: %[^
]",
+ rv = sscanf( p+2, "%" STR(PATHWIDTH) "[^:]: %lu: %"
STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason );
if (rv != 3)
- rv = sscanf( p+2, "%[^,], line %lu: %[^
]",
+ rv = sscanf( p+2, "%" STR(PATHWIDTH) "[^,], line %lu: %"
STR(LINEWIDTH) "[^
]",
FileName, &Row, Reason );
ok = ( rv == 3 );
}
@@ -307,7 +316,7 @@ int main( int argc, char *argv[] )
p = &Line[1];
else
p = &Line[0];
- ok = sscanf( p, "make[%*d]: Entering directory `%[^']",
+ ok = sscanf( p, "make[%*d]: Entering directory `%" STR(PATHWIDTH)
"[^']",
BasePath );
if (verbose)
printf( "[%u]?%s
", (unsigned)ok, Line );
diff --git a/runtime/tools/ccfilter_README.txt
b/runtime/tools/ccfilter_README.txt
index ea989f257..70d8f3f4d 100644
--- a/runtime/tools/ccfilter_README.txt
+++ b/runtime/tools/ccfilter_README.txt
@@ -5,7 +5,8 @@ ccfilter is a C program to filter the output of a few compilers
to a common
QuickFix format. It is provided with Vim to make quickfix useful for more
compilers.
-ccfilter WILL FAIL with long lines (more than 2047 bytes).
+ccfilter handles input lines up to 2047 bytes; longer lines are split and
+may not be parsed correctly.
COMPILING AND INSTALLING:
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1wawhw-007PT0-A4%40256bit.org.