Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260805075215.3508837-2-matthias.goergens@gmail.com>
Date: Wed,  5 Aug 2026 15:52:15 +0800
From: Matthias Goergens <matthias.goergens@...il.com>
To: musl@...ts.openwall.com
Cc: Matthias Goergens <matthias.goergens@...il.com>
Subject: [PATCH 2/2] stdio: check allocated scanf buffer sizes

The scanf allocation modifier computes initial and grown buffer sizes
without checking that element counts and byte sizes fit in size_t. On
32-bit targets, %1073741823mlc wraps a wide allocation to zero before
the first input character is stored.

Reject unrepresentable initial wide buffers. Bound all narrow and wide
geometric growth before updating element counts. Report ENOMEM and use
the existing allocation-failure cleanup path.
---
 src/stdio/vfscanf.c  | 13 +++++++++++++
 src/stdio/vfwscanf.c | 16 ++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/src/stdio/vfscanf.c b/src/stdio/vfscanf.c
index 07bb3845..4e06e494 100644
--- a/src/stdio/vfscanf.c
+++ b/src/stdio/vfscanf.c
@@ -6,6 +6,7 @@
 #include <limits.h>
 #include <string.h>
 #include <stdint.h>
+#include <errno.h>
 
 #include "stdio_impl.h"
 #include "shgetc.h"
@@ -228,6 +229,10 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
 			k = t=='c' ? width+1U : 31;
 			if (size == SIZE_l) {
 				if (alloc) {
+					if (k > SIZE_MAX/sizeof(wchar_t)) {
+						errno = ENOMEM;
+						goto alloc_fail;
+					}
 					wcs = malloc(k*sizeof(wchar_t));
 					if (!wcs) goto alloc_fail;
 				} else {
@@ -243,6 +248,10 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
 					}
 					if (wcs) wcs[i++] = wc;
 					if (alloc && i==k) {
+						if (k > (SIZE_MAX/sizeof(wchar_t)-1)/2) {
+							errno = ENOMEM;
+							goto alloc_fail;
+						}
 						k+=k+1;
 						wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
 						if (!tmp) goto alloc_fail;
@@ -256,6 +265,10 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
 				while (scanset[(c=shgetc(f))+1]) {
 					s[i++] = c;
 					if (i==k) {
+						if (k > (SIZE_MAX-1)/2) {
+							errno = ENOMEM;
+							goto alloc_fail;
+						}
 						k+=k+1;
 						char *tmp = realloc(s, k);
 						if (!tmp) goto alloc_fail;
diff --git a/src/stdio/vfwscanf.c b/src/stdio/vfwscanf.c
index 1497aa0d..c1a87b74 100644
--- a/src/stdio/vfwscanf.c
+++ b/src/stdio/vfwscanf.c
@@ -6,6 +6,8 @@
 #include <wctype.h>
 #include <limits.h>
 #include <string.h>
+#include <stdint.h>
+#include <errno.h>
 
 #include "stdio_impl.h"
 #include "shgetc.h"
@@ -245,8 +247,14 @@ int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
 
 			i = 0;
 			if (alloc) {
+				s = 0;
+				wcs = 0;
 				k = t=='c' ? width+1U : 31;
 				if (size == SIZE_l) {
+					if (k > SIZE_MAX/sizeof(wchar_t)) {
+						errno = ENOMEM;
+						goto alloc_fail;
+					}
 					wcs = malloc(k*sizeof(wchar_t));
 					if (!wcs) goto alloc_fail;
 				} else {
@@ -261,6 +269,10 @@ int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
 				if (wcs) {
 					wcs[i++] = c;
 					if (alloc && i==k) {
+						if (k > (SIZE_MAX/sizeof(wchar_t)-1)/2) {
+							errno = ENOMEM;
+							goto alloc_fail;
+						}
 						k += k+1;
 						wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
 						if (!tmp) goto alloc_fail;
@@ -271,6 +283,10 @@ int vfwscanf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
 					if (l<0) goto input_fail;
 					i += l;
 					if (alloc && i > k-4) {
+						if (k > (SIZE_MAX-1)/2) {
+							errno = ENOMEM;
+							goto alloc_fail;
+						}
 						k += k+1;
 						char *tmp = realloc(s, k);
 						if (!tmp) goto alloc_fail;
-- 
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.