From: Hirohito Higashi Date: Thu, 18 Jun 2026 20:12:48 +0000 (+0000) Subject: ccfilter: buffer overflow in ccfilter.c with crafted compiler output X-Git-Tag: v9.2.0678~1 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=a092d249b6066401dda0964ceeb213062785bbc8;p=thirdparty%2Fvim.git 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) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/runtime/tools/ccfilter.c b/runtime/tools/ccfilter.c index 269e4ee662..5fe6307bf8 100644 --- a/runtime/tools/ccfilter.c +++ b/runtime/tools/ccfilter.c @@ -18,15 +18,24 @@ #include #include -#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: %[^\n]", + if ((rv = sscanf( Line, "%" STR(PATHWIDTH) "[^:]:%lu: warning: %" STR(LINEWIDTH) "[^\n]", FileName, &Row, Reason ))==3) { Severity = 'w'; } else { - rv = sscanf( Line, "%[^:]:%lu: %[^\n]", + rv = sscanf( Line, "%" STR(PATHWIDTH) "[^:]:%lu: %" STR(LINEWIDTH) "[^\n]", 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) %[^\n]", + rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu.%lu: %*s (%c) %" STR(LINEWIDTH) "[^\n]", FileName, &Row, &Col, &Severity, Reason ); ok = ( rv == 5 ); break; case COMPILER_HPUX: - rv = sscanf( Line, "cc: \"%[^\"]\", line %lu: %c%*[^:]: %[^\n]", + rv = sscanf( Line, "cc: \"%" STR(PATHWIDTH) "[^\"]\", line %lu: %c%*[^:]: %" STR(LINEWIDTH) "[^\n]", FileName, &Row, &Severity, Reason ); ok = ( rv == 4 ); Col = (dec_col ? 1 : 0 ); break; case COMPILER_SOLARIS: - rv = sscanf( Line, "\"%[^\"]\", line %lu: warning: %[^\n]", + rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu: warning: %" STR(LINEWIDTH) "[^\n]", FileName, &Row, Reason ); Severity = 'w'; ok = ( rv == 3 ); if ( rv != 3 ) { - rv = sscanf( Line, "\"%[^\"]\", line %lu: %[^\n]", + rv = sscanf( Line, "\"%" STR(PATHWIDTH) "[^\"]\", line %lu: %" STR(LINEWIDTH) "[^\n]", 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%*[^:]:%[^\n]", + rv = sscanf( Line, "%c \"%" STR(PATHWIDTH) "[^\"]\",L%lu/C%lu%*[^:]:%" STR(LINEWIDTH) "[^\n]", &Severity, FileName, &Row, &Col, Reason ); ok = ( rv == 5 ); if (rv != 5) - { rv = sscanf( Line, "%c \"%[^\"]\",L%lu/C%lu: %[^\n]", + { rv = sscanf( Line, "%c \"%" STR(PATHWIDTH) "[^\"]\",L%lu/C%lu: %" STR(LINEWIDTH) "[^\n]", &Severity, FileName, &Row, &Col, Reason ); ok = ( rv == 5 ); } if (rv != 5) - { rv = sscanf( Line, "%c \"%[^\"]\",L%lu: %[^\n]", + { rv = sscanf( Line, "%c \"%" STR(PATHWIDTH) "[^\"]\",L%lu: %" STR(LINEWIDTH) "[^\n]", &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: %[^\n]", + rv = sscanf( p+2, "%" STR(PATHWIDTH) "[^:]: %lu: %" STR(LINEWIDTH) "[^\n]", FileName, &Row, Reason ); if (rv != 3) - rv = sscanf( p+2, "%[^,], line %lu: %[^\n]", + rv = sscanf( p+2, "%" STR(PATHWIDTH) "[^,], line %lu: %" STR(LINEWIDTH) "[^\n]", 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\n", (unsigned)ok, Line ); diff --git a/runtime/tools/ccfilter_README.txt b/runtime/tools/ccfilter_README.txt index ea989f2574..70d8f3f4d2 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: