Commit b624871cb for clamav.net

commit b624871cbc9f962870d5018db9cfa73576ddd133
Author: John Humlick <15677335+jhumlick@users.noreply.github.com>
Date:   Wed Jan 21 09:17:14 2026 -0800

    libclamav: Malformed regexes result in misleading memory error messages. (#1635)

    The regex parsing code treated anything that did not return CL_SUCCESS
    as CL_EMEM in several places, resulting in a return code indicative of a
    malformed database returning a memory error instead. This change passes
    the real return code up the chain, and also prevents trying to realloc 0
    bytes when we don't have anything to realloc due to a malformed
    database.

    CLAM-2191

diff --git a/libclamav/regex_list.c b/libclamav/regex_list.c
index 2e1de60f5..2ba0ce046 100644
--- a/libclamav/regex_list.c
+++ b/libclamav/regex_list.c
@@ -833,6 +833,10 @@ static cl_error_t add_pattern_suffix(void *cbdata, const char *suffix, size_t su

         if (CL_SUCCESS != ret) {
             cli_hashtab_delete(&matcher->suffix_hash, suffix, suffix_len);
+            /* Check if there is anything to shrink back to */
+            if (n == 0) {
+                goto done;
+            }
             /*shrink the size back to what it was.*/
             CLI_MAX_REALLOC_OR_GOTO_DONE(matcher->suffix_regexes, n * sizeof(*matcher->suffix_regexes));
         } else {
diff --git a/libclamav/regex_suffix.c b/libclamav/regex_suffix.c
index 076872098..e45b31a5d 100644
--- a/libclamav/regex_suffix.c
+++ b/libclamav/regex_suffix.c
@@ -394,9 +394,7 @@ static cl_error_t build_suffixtree_ascend(struct node *n, struct text_buffer *bu
                         cnt++;
                 if (cnt > 16) {
                     textbuffer_putc(buf, '\0');
-                    if (cb(cbdata, buf->data, buf->pos - 1, regex) != CL_SUCCESS)
-                        return CL_EMEM;
-                    return CL_SUCCESS;
+                    return cb(cbdata, buf->data, buf->pos - 1, regex);
                 }
                 /* handle small classes by expanding */
                 for (i = 0; i < 255; i++) {
@@ -412,11 +410,9 @@ static cl_error_t build_suffixtree_ascend(struct node *n, struct text_buffer *bu
                 return 0;
             case concat:
                 if (prev != n->u.children.left) {
-                    if (build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex) != CL_SUCCESS)
-                        return CL_EMEM;
+                    return build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex);
                     /* we're done here, descend will call
                      * ascend if needed */
-                    return CL_SUCCESS;
                 } else {
                     n = n->parent;
                 }
@@ -438,6 +434,7 @@ static cl_error_t build_suffixtree_ascend(struct node *n, struct text_buffer *bu
 static cl_error_t build_suffixtree_descend(struct node *n, struct text_buffer *buf, suffix_callback cb, void *cbdata, struct regex_list *regex)
 {
     size_t pos;
+    cl_error_t ret = CL_SUCCESS;
     while (n && n->type == concat) {
         n = n->u.children.right;
     }
@@ -449,23 +446,23 @@ static cl_error_t build_suffixtree_descend(struct node *n, struct text_buffer *b
         case alternate:
             /* save pos as restart point */
             pos = buf->pos;
-            if (build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex) != CL_SUCCESS)
-                return CL_EMEM;
+            if ((ret = build_suffixtree_descend(n->u.children.left, buf, cb, cbdata, regex)) != CL_SUCCESS) {
+                return ret;
+            }
             buf->pos = pos;
-            if (build_suffixtree_descend(n->u.children.right, buf, cb, cbdata, regex) != CL_SUCCESS)
-                return CL_EMEM;
+            if ((ret = build_suffixtree_descend(n->u.children.right, buf, cb, cbdata, regex)) != CL_SUCCESS) {
+                return ret;
+            }
             buf->pos = pos;
             break;
         case optional:
             textbuffer_putc(buf, '\0');
-            if (cb(cbdata, buf->data, buf->pos - 1, regex) != CL_SUCCESS)
-                return CL_EMEM;
-            return CL_SUCCESS;
+            if ((ret = cb(cbdata, buf->data, buf->pos - 1, regex)) != CL_SUCCESS) {
+                return ret;
+            }
         case leaf:
         case leaf_class:
-            if (build_suffixtree_ascend(n, buf, NULL, cb, cbdata, regex) != CL_SUCCESS)
-                return CL_EMEM;
-            return CL_SUCCESS;
+            return build_suffixtree_ascend(n, buf, NULL, cb, cbdata, regex);
         default:
             break;
     }