|
|
Message-ID: <20260805141033.841558-5-matthias.goergens@gmail.com>
Date: Wed, 5 Aug 2026 22:10:27 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 04/10] regression: test allocated scanf buffer size overflow
On 32-bit targets %1073741823mlc wraps the wide-buffer allocation
to zero bytes unless the element count is checked. The conversion
must instead fail with ENOMEM before any allocation or store. The
test is a no-op where size_t is wider than 32 bits.
Covered by the musl patch "stdio: check allocated scanf buffer
sizes".
---
src/regression/scanf-alloc-size-overflow.c | 102 +++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 src/regression/scanf-alloc-size-overflow.c
diff --git a/src/regression/scanf-alloc-size-overflow.c b/src/regression/scanf-alloc-size-overflow.c
new file mode 100644
index 0000000..472fc11
--- /dev/null
+++ b/src/regression/scanf-alloc-size-overflow.c
@@ -0,0 +1,102 @@
+// The scanf allocation modifier computed wide-buffer byte sizes as
+// k * sizeof(wchar_t) without checking for size_t overflow. On 32-bit
+// targets %1073741823mlc wraps the allocation to zero bytes and the
+// first matching wide character is stored through the zero-size
+// object. The overlarge element count must be rejected with ENOMEM
+// before any allocation or store.
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <wchar.h>
+#include "test.h"
+
+#if ULONG_MAX == 0xffffffffUL
+
+static union {
+ long double align;
+ unsigned char bytes[64];
+} arena;
+static size_t requested;
+
+void *malloc(size_t size)
+{
+ requested = size;
+ return arena.bytes;
+}
+
+void free(void *ptr)
+{
+ (void)ptr;
+}
+
+void *realloc(void *ptr, size_t size)
+{
+ (void)ptr;
+ requested = size;
+ return arena.bytes;
+}
+
+static int canary_changed(void)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(wchar_t); i++)
+ if (arena.bytes[i] != 0xa5)
+ return 1;
+ return 0;
+}
+
+static void reset(void)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof arena.bytes; i++)
+ arena.bytes[i] = 0xa5;
+ requested = SIZE_MAX;
+ errno = 0;
+}
+
+static void check(const char *what, int r, wchar_t *out)
+{
+ if (r != EOF)
+ t_error("%s returned %d, want EOF\n", what, r);
+ if (errno != ENOMEM)
+ t_error("%s left errno %d, want ENOMEM\n", what, errno);
+ if (requested != SIZE_MAX)
+ t_error("%s requested %zu bytes from the allocator, want none\n",
+ what, requested);
+ if (canary_changed())
+ t_error("%s stored through the overlarge buffer\n", what);
+ if (out)
+ t_error("%s stored a result pointer\n", what);
+}
+
+int main(void)
+{
+ wchar_t *out = 0;
+ int r;
+
+ reset();
+ r = sscanf("x", "%1073741823mlc", &out);
+ check("sscanf(\"x\", \"%%1073741823mlc\")", r, out);
+
+ out = 0;
+ reset();
+ r = swscanf(L"x", L"%1073741823mlc", &out);
+ check("swscanf(L\"x\", L\"%%1073741823mlc\")", r, out);
+
+ return t_status;
+}
+
+#else
+
+/* the widest scanf field width (INT_MAX wide characters) cannot
+ overflow the byte count when size_t is wider than 32 bits */
+int main(void)
+{
+ return t_status;
+}
+
+#endif
--
2.55.0
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.