mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6246)
__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER containing a long program name failed to update the required buffer size, leading to the allocation and overflow of a too-small buffer on the heap. This commit fixes that. It also adds a new regression test that uses glibc.malloc.check. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> Reviewed-by: Carlos O'Donell <carlos@redhat.com> Tested-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
parent
8aeec0eb5a
commit
6bd0e4efcc
@ -289,7 +289,10 @@ tests-special += $(objpfx)tst-error1-mem.out \
|
||||
$(objpfx)tst-allocate_once-mem.out
|
||||
endif
|
||||
|
||||
tests-container := tst-syslog
|
||||
tests-container := \
|
||||
tst-syslog \
|
||||
tst-syslog-long-progname \
|
||||
# tests-container
|
||||
|
||||
CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
|
||||
CFLAGS-tsearch.c += $(uses-callbacks)
|
||||
@ -351,6 +354,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
|
||||
LD_PRELOAD=libc_malloc_debug.so.0
|
||||
|
||||
$(objpfx)tst-select: $(librt)
|
||||
$(objpfx)tst-select-time64: $(librt)
|
||||
$(objpfx)tst-pselect: $(librt)
|
||||
|
@ -124,8 +124,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||||
{
|
||||
/* Try to use a static buffer as an optimization. */
|
||||
char bufs[1024];
|
||||
char *buf = NULL;
|
||||
size_t bufsize = 0;
|
||||
char *buf = bufs;
|
||||
size_t bufsize;
|
||||
|
||||
int msgoff;
|
||||
int saved_errno = errno;
|
||||
|
||||
@ -177,14 +178,35 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||||
#define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \
|
||||
"<%d>: %n", __pri, __msgoff
|
||||
|
||||
int l;
|
||||
int l, vl;
|
||||
if (has_ts)
|
||||
l = __snprintf (bufs, sizeof bufs,
|
||||
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
||||
else
|
||||
l = __snprintf (bufs, sizeof bufs,
|
||||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||||
|
||||
char *pos;
|
||||
size_t len;
|
||||
|
||||
if (0 <= l && l < sizeof bufs)
|
||||
{
|
||||
/* At this point, there is still a chance that we can print the
|
||||
remaining part of the log into bufs and use that. */
|
||||
pos = bufs + l;
|
||||
len = sizeof (bufs) - l;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = NULL;
|
||||
/* We already know that bufs is too small to use for this log message.
|
||||
The next vsnprintf into bufs is used only to calculate the total
|
||||
required buffer length. We will discard bufs contents and allocate
|
||||
an appropriately sized buffer later instead. */
|
||||
pos = bufs;
|
||||
len = sizeof (bufs);
|
||||
}
|
||||
|
||||
{
|
||||
va_list apc;
|
||||
va_copy (apc, ap);
|
||||
@ -192,12 +214,12 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
||||
/* Restore errno for %m format. */
|
||||
__set_errno (saved_errno);
|
||||
|
||||
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
|
||||
mode_flags);
|
||||
if (0 <= vl && vl < sizeof bufs - l)
|
||||
buf = bufs;
|
||||
bufsize = l + vl;
|
||||
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
|
||||
|
||||
if (!(0 <= vl && vl < len))
|
||||
buf = NULL;
|
||||
|
||||
bufsize = l + vl;
|
||||
va_end (apc);
|
||||
}
|
||||
|
||||
|
39
misc/tst-syslog-long-progname.c
Normal file
39
misc/tst-syslog-long-progname.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246)
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
extern char * __progname;
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
char long_progname[2048];
|
||||
|
||||
memset (long_progname, 'X', sizeof (long_progname) - 1);
|
||||
long_progname[sizeof (long_progname) - 1] = '\0';
|
||||
|
||||
__progname = long_progname;
|
||||
|
||||
syslog (LOG_INFO, "Hello, World!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
0
misc/tst-syslog-long-progname.root/postclean.req
Normal file
0
misc/tst-syslog-long-progname.root/postclean.req
Normal file
Loading…
Reference in New Issue
Block a user