]>
Commit | Line | Data |
---|---|---|
a61a21ef MT |
1 | From 23514c72b780f3da097ecf33a793b7ba9c2070d2 Mon Sep 17 00:00:00 2001 |
2 | From: Arjun Shankar <arjun@redhat.com> | |
3 | Date: Mon, 15 Jan 2024 17:44:43 +0100 | |
4 | Subject: [PATCH 42/44] syslog: Fix heap buffer overflow in __vsyslog_internal | |
5 | (CVE-2023-6246) | |
6 | ||
7 | __vsyslog_internal did not handle a case where printing a SYSLOG_HEADER | |
8 | containing a long program name failed to update the required buffer | |
9 | size, leading to the allocation and overflow of a too-small buffer on | |
10 | the heap. This commit fixes that. It also adds a new regression test | |
11 | that uses glibc.malloc.check. | |
12 | ||
13 | Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> | |
14 | Reviewed-by: Carlos O'Donell <carlos@redhat.com> | |
15 | Tested-by: Carlos O'Donell <carlos@redhat.com> | |
16 | (cherry picked from commit 6bd0e4efcc78f3c0115e5ea9739a1642807450da) | |
17 | --- | |
18 | misc/Makefile | 8 ++- | |
19 | misc/syslog.c | 50 +++++++++++++------ | |
20 | misc/tst-syslog-long-progname.c | 39 +++++++++++++++ | |
21 | .../postclean.req | 0 | |
22 | 4 files changed, 82 insertions(+), 15 deletions(-) | |
23 | create mode 100644 misc/tst-syslog-long-progname.c | |
24 | create mode 100644 misc/tst-syslog-long-progname.root/postclean.req | |
25 | ||
26 | diff --git a/misc/Makefile b/misc/Makefile | |
27 | index fe0d49c1de..90b31952c5 100644 | |
28 | --- a/misc/Makefile | |
29 | +++ b/misc/Makefile | |
30 | @@ -289,7 +289,10 @@ tests-special += $(objpfx)tst-error1-mem.out \ | |
31 | $(objpfx)tst-allocate_once-mem.out | |
32 | endif | |
33 | ||
34 | -tests-container := tst-syslog | |
35 | +tests-container := \ | |
36 | + tst-syslog \ | |
37 | + tst-syslog-long-progname \ | |
38 | + # tests-container | |
39 | ||
40 | CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables | |
41 | CFLAGS-tsearch.c += $(uses-callbacks) | |
42 | @@ -351,6 +354,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out | |
43 | $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ | |
44 | $(evaluate-test) | |
45 | ||
46 | +tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \ | |
47 | + LD_PRELOAD=libc_malloc_debug.so.0 | |
48 | + | |
49 | $(objpfx)tst-select: $(librt) | |
50 | $(objpfx)tst-select-time64: $(librt) | |
51 | $(objpfx)tst-pselect: $(librt) | |
52 | diff --git a/misc/syslog.c b/misc/syslog.c | |
53 | index 1b8cb722c5..814d224a1e 100644 | |
54 | --- a/misc/syslog.c | |
55 | +++ b/misc/syslog.c | |
56 | @@ -124,8 +124,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, | |
57 | { | |
58 | /* Try to use a static buffer as an optimization. */ | |
59 | char bufs[1024]; | |
60 | - char *buf = NULL; | |
61 | - size_t bufsize = 0; | |
62 | + char *buf = bufs; | |
63 | + size_t bufsize; | |
64 | + | |
65 | int msgoff; | |
66 | int saved_errno = errno; | |
67 | ||
68 | @@ -177,29 +178,50 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, | |
69 | #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \ | |
70 | "<%d>: %n", __pri, __msgoff | |
71 | ||
72 | - int l; | |
73 | + int l, vl; | |
74 | if (has_ts) | |
75 | l = __snprintf (bufs, sizeof bufs, | |
76 | SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); | |
77 | else | |
78 | l = __snprintf (bufs, sizeof bufs, | |
79 | SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); | |
80 | + | |
81 | + char *pos; | |
82 | + size_t len; | |
83 | + | |
84 | if (0 <= l && l < sizeof bufs) | |
85 | { | |
86 | - va_list apc; | |
87 | - va_copy (apc, ap); | |
88 | + /* At this point, there is still a chance that we can print the | |
89 | + remaining part of the log into bufs and use that. */ | |
90 | + pos = bufs + l; | |
91 | + len = sizeof (bufs) - l; | |
92 | + } | |
93 | + else | |
94 | + { | |
95 | + buf = NULL; | |
96 | + /* We already know that bufs is too small to use for this log message. | |
97 | + The next vsnprintf into bufs is used only to calculate the total | |
98 | + required buffer length. We will discard bufs contents and allocate | |
99 | + an appropriately sized buffer later instead. */ | |
100 | + pos = bufs; | |
101 | + len = sizeof (bufs); | |
102 | + } | |
103 | ||
104 | - /* Restore errno for %m format. */ | |
105 | - __set_errno (saved_errno); | |
106 | + { | |
107 | + va_list apc; | |
108 | + va_copy (apc, ap); | |
109 | ||
110 | - int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc, | |
111 | - mode_flags); | |
112 | - if (0 <= vl && vl < sizeof bufs - l) | |
113 | - buf = bufs; | |
114 | - bufsize = l + vl; | |
115 | + /* Restore errno for %m format. */ | |
116 | + __set_errno (saved_errno); | |
117 | ||
118 | - va_end (apc); | |
119 | - } | |
120 | + vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); | |
121 | + | |
122 | + if (!(0 <= vl && vl < len)) | |
123 | + buf = NULL; | |
124 | + | |
125 | + bufsize = l + vl; | |
126 | + va_end (apc); | |
127 | + } | |
128 | ||
129 | if (buf == NULL) | |
130 | { | |
131 | diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c | |
132 | new file mode 100644 | |
133 | index 0000000000..88f37a8a00 | |
134 | --- /dev/null | |
135 | +++ b/misc/tst-syslog-long-progname.c | |
136 | @@ -0,0 +1,39 @@ | |
137 | +/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246) | |
138 | + Copyright (C) 2023 Free Software Foundation, Inc. | |
139 | + This file is part of the GNU C Library. | |
140 | + | |
141 | + The GNU C Library is free software; you can redistribute it and/or | |
142 | + modify it under the terms of the GNU Lesser General Public | |
143 | + License as published by the Free Software Foundation; either | |
144 | + version 2.1 of the License, or (at your option) any later version. | |
145 | + | |
146 | + The GNU C Library is distributed in the hope that it will be useful, | |
147 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
148 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
149 | + Lesser General Public License for more details. | |
150 | + | |
151 | + You should have received a copy of the GNU Lesser General Public | |
152 | + License along with the GNU C Library; if not, see | |
153 | + <https://www.gnu.org/licenses/>. */ | |
154 | + | |
155 | +#include <syslog.h> | |
156 | +#include <string.h> | |
157 | + | |
158 | +extern char * __progname; | |
159 | + | |
160 | +static int | |
161 | +do_test (void) | |
162 | +{ | |
163 | + char long_progname[2048]; | |
164 | + | |
165 | + memset (long_progname, 'X', sizeof (long_progname) - 1); | |
166 | + long_progname[sizeof (long_progname) - 1] = '\0'; | |
167 | + | |
168 | + __progname = long_progname; | |
169 | + | |
170 | + syslog (LOG_INFO, "Hello, World!"); | |
171 | + | |
172 | + return 0; | |
173 | +} | |
174 | + | |
175 | +#include <support/test-driver.c> | |
176 | diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req | |
177 | new file mode 100644 | |
178 | index 0000000000..e69de29bb2 | |
179 | -- | |
180 | 2.39.2 | |
181 |