Bug in regexp library may lead to out-of-bounds read
Closed, ResolvedPublic

Assigned To
Authored By
Guldrelokk
Apr 18 2023, 12:20 PM

Description

The compiler in the bundled regular expression library allows any character to end a POSIX character class expression. Besides incorrect parsing, this can involve skipping the string terminator in the face of a malformed expression.
Test case:

#include "jimregexp.h"

int
main (void)
{
  regex_t r;
  return !regcomp (&r, "[[:digit:\0]", 0);
}

Trivial fix:

diff --git a/regexp/jimregexp.c b/regexp/jimregexp.c
index 7fd6d473e..1a8b8aae6 100644
--- a/regexp/jimregexp.c
+++ b/regexp/jimregexp.c
@@ -795,7 +795,8 @@ static int regatom(regex_t *preg, int *flagp)
 
                                        for (cc = 0; cc < CC_NUM; cc++) {
                                                n = strlen(character_class[cc]);
-                                               if (strncmp(pattern, character_class[cc], n) == 0) {
+                                               if (strncmp(pattern, character_class[cc], n) == 0
+                                                    && pattern[n] == ']') {
                                                        /* Found a character class */
                                                        pattern += n + 1;
                                                        break;

I have not investigated whether this has any impact on current versions of GnuPG.

Event Timeline

Another miscellaneous correction for jimregexp. A condition was copy-pasted from another section without the necessary changes, resulting in incorrect logic. This seems harmless apart from inconsistent error reporting.

diff --git a/regexp/jimregexp.c b/regexp/jimregexp.c
index 1a8b8aae6..1b6e1b49c 100644
--- a/regexp/jimregexp.c
+++ b/regexp/jimregexp.c
@@ -778,7 +778,7 @@ static int regatom(regex_t *preg, int *flagp)
                                                        preg->err = REG_ERR_NULL_CHAR;
                                                        return 0;
                                                }
-                                               if (start == '\\' && *pattern == 0) {
+                                               if (end == '\\' && *pattern == 0) {
                                                        preg->err = REG_ERR_INVALID_ESCAPE;
                                                        return 0;
                                                }
• werner triaged this task as High priority.
• werner edited projects, added gnupg22, gnupg24; removed gnupg.
• werner added subscribers: • gniibe, • werner.

@gniibe, will you be so kind an check the provided patches

• werner moved this task from Backlog to QA on the gnupg22 board.

Okay, that was easy to check.

• werner moved this task from QA to gnupg-2.4.1 on the gnupg24 board.
• werner edited projects, added gnupg24 (gnupg-2.4.1); removed gnupg24.
• werner moved this task from QA to gnupg-2.2.42 on the gnupg22 board.
• werner edited projects, added gnupg22 (gnupg-2.2.42); removed gnupg22.

I checked the upstream. For the reported issue, upstream version raises an error with REG_ERR_UNMATCHED_BRACKET.
That behavior is better (as we don't have particular reason to maintain different behavior from upstream version).
Also, I found another change from upstream for end of word check.

I'm going to incorporate those change.