CVE-2023-0341: Out-of-bounds Write (CWE-787)
value: A stack buffer overflow exists in the ec_glob function of editorconfig-core-c before v0.12.6 which allowed an attacker to arbitrarily write to the stack and possibly allows remote code execution. editorconfig-core-c v0.12.6 resolved this vulnerability by bound checking all write operations over the p_pcre buffer.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2023-02-01T00:15Z
Repository: https://github.com/editorconfig/editorconfig-core-c
Language: C
Files changed: src/lib/ec_glob.c
Commit date: 2023-01-19 00:21:49 -0800
Commit message: Fix potential buffer overflow in ec_glob (#87)

CVE-2023-0341

Co-authored-by: David Fernandez Gonzalez <david.fernandezgonzalez@canonical.com>
Diff: diff --git a/src/lib/ec_glob.c b/src/lib/ec_glob.c
index 32b3941..ea62aee 100644
--- a/src/lib/ec_glob.c
+++ b/src/lib/ec_glob.c
@@ -55,10 +55,17 @@ static const UT_icd ut_int_pair_icd = {sizeof(int_pair),NULL,NULL,NULL};
         return -1; \
     strcat(p, string); \
     p += string_len; \
 } while(0)
 
+/* safely add a char to a string then move the pointer to the end */
+#define ADD_CHAR(string, new_chr, end)  do {    \
+    if (string + 1 >= end) \
+        return -1; \
+    *(string ++) = new_chr; \
+} while(0)
+
 #define PATTERN_MAX  4097
 /*
  * Whether the string matches the given glob pattern. Return 0 if successful, return -1 if a PCRE
  * error or other regex error occurs, and return -2 if an OOM outside PCRE occurs.
  */
@@ -129,12 +136,12 @@ int ec_glob(const char *pattern, const char *string)
         switch (*c)
         {
         case '\\':      /* also skip the next one */
             if (*(c+1) != '\0')
             {
-                *(p_pcre ++) = *(c++);
-                *(p_pcre ++) = *c;
+                ADD_CHAR(p_pcre, *(c++), pcre_str_end);
+                ADD_CHAR(p_pcre, *c, pcre_str_end);
             }
             else
                 STRING_CAT(p_pcre, "\\\\", pcre_str_end);
 
             break;
@@ -206,22 +213,22 @@ int ec_glob(const char *pattern, const char *string)
             {
                 STRING_CAT(p_pcre, "[^", pcre_str_end);
                 ++ c;
             }
             else
-                *(p_pcre ++) = '[';
+                STRING_CAT(p_pcre, "[", pcre_str_end);
 
             break;
 
         case ']':
             is_in_bracket = 0;
-            *(p_pcre ++) = *c;
+            ADD_CHAR(p_pcre, *c, pcre_str_end);
             break;
 
         case '-':
             if (is_in_bracket)      /* in brackets, - indicates range */
-                *(p_pcre ++) = *c;
+                ADD_CHAR(p_pcre, *c, pcre_str_end);
             else
                 STRING_CAT(p_pcre, "\\-", pcre_str_end);
 
             break;
         case '{':
@@ -300,16 +307,16 @@ int ec_glob(const char *pattern, const char *string)
                 STRING_CAT(p_pcre, "\\}", pcre_str_end);
                 break;
             }
 
             -- brace_level;
-            *(p_pcre ++) = ')';
+            STRING_CAT(p_pcre, ")", pcre_str_end);
             break;
 
         case ',':
             if (brace_level > 0)  /* , inside {...} */
-                *(p_pcre ++) = '|';
+                STRING_CAT(p_pcre, "|", pcre_str_end);
             else
                 STRING_CAT(p_pcre, "\\,", pcre_str_end);
             break;
 
         case '/':
@@ -324,13 +331,13 @@ int ec_glob(const char *pattern, const char *string)
 
             break;
 
         default:
             if (!isalnum(*c))
-                *(p_pcre ++) = '\\';
+                STRING_CAT(p_pcre, "\\", pcre_str_end);
 
-            *(p_pcre ++) = *c;
+            ADD_CHAR(p_pcre, *c, pcre_str_end);
         }
     }
 
     *(p_pcre ++) = '$';
 

Vulnerable code:                 *(p_pcre ++) = *(c++);
                *(p_pcre ++) = *c;
                *(p_pcre ++) = '[';
            *(p_pcre ++) = *c;
                *(p_pcre ++) = *c;
            *(p_pcre ++) = ')';
                *(p_pcre ++) = '|';
                *(p_pcre ++) = '\\';
            *(p_pcre ++) = *c;
Fixed code: /* safely add a char to a string then move the pointer to the end */
#define ADD_CHAR(string, new_chr, end)  do {    \
    if (string + 1 >= end) \
        return -1; \
    *(string ++) = new_chr; \
} while(0)

                ADD_CHAR(p_pcre, *(c++), pcre_str_end);
                ADD_CHAR(p_pcre, *c, pcre_str_end);
                STRING_CAT(p_pcre, "[", pcre_str_end);
            ADD_CHAR(p_pcre, *c, pcre_str_end);
                ADD_CHAR(p_pcre, *c, pcre_str_end);
            STRING_CAT(p_pcre, ")", pcre_str_end);
                STRING_CAT(p_pcre, "|", pcre_str_end);
                STRING_CAT(p_pcre, "\\", pcre_str_end);
            ADD_CHAR(p_pcre, *c, pcre_str_end);