Merge pull request #3226 from uchiha-bug-hunter/pathmatch-wide-bracket-overread

pathmatch: fix wide-char bracket over-read in pm_w
(cherry picked from commit 6c97b0ae54)
This commit is contained in:
Dustin L. Howett authored and Martin Matuska committed 2026-07-26 20:14:47 +02:00
1 parent 7231e54e22
commit c18d2aa7eb
2 files changed
+41 -2

No files matched your search

+1 -1
View File
@@ -337,7 +337,7 @@ pm_w(const wchar_t *p, const wchar_t *s, int flags, int depth)
}
if (*end == L']') {
/* We found [...], try to match it. */
if (!pm_list_w(p + 1, end, *s, flags))
if (*s == L'\0' || !pm_list_w(p + 1, end, *s, flags))
return (0);
p = end; /* Jump to trailing ']' char. */
break;
+40 -1
View File
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
/*
* Regression test: malformed bracket expressions in patterns caused
@@ -37,8 +38,10 @@
* redzones detect overreads.
*/
/* Declare the internal function we want to test. */
/* Declare the internal functions we want to test. */
int __archive_pathmatch(const char *pattern, const char *string, int flags);
int __archive_pathmatch_w(const wchar_t *pattern, const wchar_t *string,
int flags);
/*
* Replay a fuzzer repro file through __archive_pathmatch().
@@ -115,3 +118,39 @@ DEFINE_TEST(test_archive_pathmatch_oob_strchr)
{
replay_pathmatch_repro("test_archive_pathmatch_oob_strchr.bin");
}
/*
* Wide-character twin of the bracket over-read. pm_w() matched a [...]
* class without first checking whether the subject string was already
* exhausted, so a negated class ([!...]/[^...]) at end-of-string reported
* a match and advanced the subject pointer past its terminator. Allocate
* tight wide buffers so ASan's redzones catch the over-read.
*/
static void
check_pathmatch_w_oob(const wchar_t *pat, const wchar_t *str, int flags)
{
size_t plen = wcslen(pat) + 1;
size_t slen = wcslen(str) + 1;
wchar_t *pattern = (wchar_t *)malloc(plen * sizeof(wchar_t));
wchar_t *string = (wchar_t *)malloc(slen * sizeof(wchar_t));
if (assert(pattern != NULL) && assert(string != NULL)) {
wmemcpy(pattern, pat, plen);
wmemcpy(string, str, slen);
/* This must not read past the allocated buffers. */
__archive_pathmatch_w(pattern, string, flags);
}
free(pattern);
free(string);
}
DEFINE_TEST(test_archive_pathmatch_oob_bracket_w)
{
/* PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END, as used by
* archive_match() exclusion patterns. */
int flags = 1 | 2;
check_pathmatch_w_oob(L"abc[!x]", L"abc", flags);
check_pathmatch_w_oob(L"[!a]", L"", flags);
check_pathmatch_w_oob(L"[^a]", L"", flags);
}