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.

Raspunde prin e-mail lui