mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +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
|
$(objpfx)tst-allocate_once-mem.out
|
||||||
endif
|
endif
|
||||||
|
|
||||||
tests-container := tst-syslog
|
tests-container := \
|
||||||
|
tst-syslog \
|
||||||
|
tst-syslog-long-progname \
|
||||||
|
# tests-container
|
||||||
|
|
||||||
CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
|
CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
|
||||||
CFLAGS-tsearch.c += $(uses-callbacks)
|
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 > $@; \
|
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
|
||||||
$(evaluate-test)
|
$(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: $(librt)
|
||||||
$(objpfx)tst-select-time64: $(librt)
|
$(objpfx)tst-select-time64: $(librt)
|
||||||
$(objpfx)tst-pselect: $(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. */
|
/* Try to use a static buffer as an optimization. */
|
||||||
char bufs[1024];
|
char bufs[1024];
|
||||||
char *buf = NULL;
|
char *buf = bufs;
|
||||||
size_t bufsize = 0;
|
size_t bufsize;
|
||||||
|
|
||||||
int msgoff;
|
int msgoff;
|
||||||
int saved_errno = errno;
|
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) \
|
#define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \
|
||||||
"<%d>: %n", __pri, __msgoff
|
"<%d>: %n", __pri, __msgoff
|
||||||
|
|
||||||
int l;
|
int l, vl;
|
||||||
if (has_ts)
|
if (has_ts)
|
||||||
l = __snprintf (bufs, sizeof bufs,
|
l = __snprintf (bufs, sizeof bufs,
|
||||||
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
||||||
else
|
else
|
||||||
l = __snprintf (bufs, sizeof bufs,
|
l = __snprintf (bufs, sizeof bufs,
|
||||||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||||||
|
|
||||||
|
char *pos;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (0 <= l && l < sizeof bufs)
|
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_list apc;
|
||||||
va_copy (apc, ap);
|
va_copy (apc, ap);
|
||||||
@ -192,12 +214,12 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
|||||||
/* Restore errno for %m format. */
|
/* Restore errno for %m format. */
|
||||||
__set_errno (saved_errno);
|
__set_errno (saved_errno);
|
||||||
|
|
||||||
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
|
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
|
||||||
mode_flags);
|
|
||||||
if (0 <= vl && vl < sizeof bufs - l)
|
|
||||||
buf = bufs;
|
|
||||||
bufsize = l + vl;
|
|
||||||
|
|
||||||
|
if (!(0 <= vl && vl < len))
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
bufsize = l + vl;
|
||||||
va_end (apc);
|
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