|
| 1 | +From 52a0be690747e3bf89218bf14e62837dfe2d1288 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Rocket Ma <marocketbd@gmail.com> |
| 3 | +Date: Fri, 17 Apr 2026 23:48:41 -0700 |
| 4 | +Subject: [PATCH 3/3] stdio-common: Fix buffer overflow in scanf %mc [BZ |
| 5 | + #34008] |
| 6 | + |
| 7 | +* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with |
| 8 | +format %mc or %mC, glibc allocates one byte less, leading to |
| 9 | +user-controlled one byte overflow. This commit fixes BZ #34008, or |
| 10 | +CVE-2026-5450. |
| 11 | + |
| 12 | +Reviewed-by: Carlos O'Donell <carlos@redhat.com> |
| 13 | +Signed-off-by: Rocket Ma <marocketbd@gmail.com> |
| 14 | +Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@surgut.co.uk> |
| 15 | +--- |
| 16 | + stdio-common/Makefile | 4 +++ |
| 17 | + stdio-common/tst-vfscanf-bz34008.c | 48 ++++++++++++++++++++++++++++++ |
| 18 | + stdio-common/vfscanf-internal.c | 7 ++--- |
| 19 | + 3 files changed, 55 insertions(+), 4 deletions(-) |
| 20 | + create mode 100644 stdio-common/tst-vfscanf-bz34008.c |
| 21 | + |
| 22 | +diff --git a/stdio-common/Makefile b/stdio-common/Makefile |
| 23 | +index 210944837e..0c0085e607 100644 |
| 24 | +--- a/stdio-common/Makefile |
| 25 | ++++ b/stdio-common/Makefile |
| 26 | +@@ -349,6 +349,7 @@ tests := \ |
| 27 | + tst-vfprintf-user-type \ |
| 28 | + tst-vfprintf-width-i18n \ |
| 29 | + tst-vfprintf-width-prec-alloc \ |
| 30 | ++ tst-vfscanf-bz34008 \ |
| 31 | + tst-wc-printf \ |
| 32 | + tstdiomisc \ |
| 33 | + tstgetln \ |
| 34 | +@@ -564,6 +565,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \ |
| 35 | + tst-vfprintf-width-prec-ENV = \ |
| 36 | + MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \ |
| 37 | + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so |
| 38 | ++tst-vfscanf-bz34008-ENV = \ |
| 39 | ++ MALLOC_CHECK_=3 \ |
| 40 | ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so |
| 41 | + tst-printf-bz25691-ENV = \ |
| 42 | + MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \ |
| 43 | + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so |
| 44 | +diff --git a/stdio-common/tst-vfscanf-bz34008.c b/stdio-common/tst-vfscanf-bz34008.c |
| 45 | +new file mode 100644 |
| 46 | +index 0000000000..48371c8a3d |
| 47 | +--- /dev/null |
| 48 | ++++ b/stdio-common/tst-vfscanf-bz34008.c |
| 49 | +@@ -0,0 +1,48 @@ |
| 50 | ++/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008) |
| 51 | ++ Copyright (C) 2026 The GNU Toolchain Authors. |
| 52 | ++ This file is part of the GNU C Library. |
| 53 | ++ |
| 54 | ++ The GNU C Library is free software; you can redistribute it and/or |
| 55 | ++ modify it under the terms of the GNU Lesser General Public |
| 56 | ++ License as published by the Free Software Foundation; either |
| 57 | ++ version 2.1 of the License, or (at your option) any later version. |
| 58 | ++ |
| 59 | ++ The GNU C Library is distributed in the hope that it will be useful, |
| 60 | ++ but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 61 | ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 62 | ++ Lesser General Public License for more details. |
| 63 | ++ |
| 64 | ++ You should have received a copy of the GNU Lesser General Public |
| 65 | ++ License along with the GNU C Library; if not, see |
| 66 | ++ <https://www.gnu.org/licenses/>. */ |
| 67 | ++ |
| 68 | ++#include "malloc/mcheck.h" |
| 69 | ++#include <stddef.h> |
| 70 | ++#include <stdio.h> |
| 71 | ++#include <string.h> |
| 72 | ++#include <wchar.h> |
| 73 | ++#include <stdlib.h> |
| 74 | ++#include <malloc.h> |
| 75 | ++#include <support/check.h> |
| 76 | ++ |
| 77 | ++#define WIDTH 0x410 |
| 78 | ++#define SCANFSTR "%1040mc" |
| 79 | ++static int |
| 80 | ++do_test (void) |
| 81 | ++{ |
| 82 | ++ mcheck_pedantic (NULL); |
| 83 | ++ char *input = malloc (WIDTH + 1); |
| 84 | ++ TEST_VERIFY (input != NULL); |
| 85 | ++ memset (input, 'A', WIDTH); |
| 86 | ++ input[WIDTH] = '\0'; |
| 87 | ++ |
| 88 | ++ char *buf = NULL; |
| 89 | ++ TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1); |
| 90 | ++ TEST_VERIFY (buf != NULL); |
| 91 | ++ |
| 92 | ++ free (buf); |
| 93 | ++ free (input); |
| 94 | ++ return 0; |
| 95 | ++} |
| 96 | ++ |
| 97 | ++#include <support/test-driver.c> |
| 98 | +diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c |
| 99 | +index 63b9246e47..8687150dff 100644 |
| 100 | +--- a/stdio-common/vfscanf-internal.c |
| 101 | ++++ b/stdio-common/vfscanf-internal.c |
| 102 | +@@ -862,8 +862,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, |
| 103 | + { |
| 104 | + /* Enlarge the buffer. */ |
| 105 | + size_t newsize |
| 106 | +- = strsize |
| 107 | +- + (strsize >= width ? width - 1 : strsize); |
| 108 | ++ = strsize + (strsize >= width ? width : strsize); |
| 109 | + |
| 110 | + str = (char *) realloc (*strptr, newsize); |
| 111 | + if (str == NULL) |
| 112 | +@@ -936,7 +935,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, |
| 113 | + && wstr == (wchar_t *) *strptr + strsize) |
| 114 | + { |
| 115 | + size_t newsize |
| 116 | +- = strsize + (strsize > width ? width - 1 : strsize); |
| 117 | ++ = strsize + (strsize >= width ? width : strsize); |
| 118 | + /* Enlarge the buffer. */ |
| 119 | + wstr = (wchar_t *) realloc (*strptr, |
| 120 | + newsize * sizeof (wchar_t)); |
| 121 | +@@ -991,7 +990,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, |
| 122 | + && wstr == (wchar_t *) *strptr + strsize) |
| 123 | + { |
| 124 | + size_t newsize |
| 125 | +- = strsize + (strsize > width ? width - 1 : strsize); |
| 126 | ++ = strsize + (strsize >= width ? width : strsize); |
| 127 | + /* Enlarge the buffer. */ |
| 128 | + wstr = (wchar_t *) realloc (*strptr, |
| 129 | + newsize * sizeof (wchar_t)); |
| 130 | +-- |
| 131 | +2.51.0 |
| 132 | + |
0 commit comments