From 2bc9d7c002bdac38b5c2a3f11b78e309d7765b83 Mon Sep 17 00:00:00 2001 From: Arjun Shankar Date: Mon, 15 Jan 2024 17:44:44 +0100 Subject: syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6779) __vsyslog_internal used the return value of snprintf/vsnprintf to calculate buffer sizes for memory allocation. If these functions (for any reason) failed and returned -1, the resulting buffer would be too small to hold output. This commit fixes that. All snprintf/vsnprintf calls are checked for negative return values and the function silently returns upon encountering them. Reviewed-by: Carlos O'Donell (cherry picked from commit 7e5a0c286da33159d47d0122007aac016f3e02cd) --- misc/syslog.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/misc/syslog.c b/misc/syslog.c index fe1daf988b..3108ae9134 100644 --- a/misc/syslog.c +++ b/misc/syslog.c @@ -183,11 +183,13 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, else l = __snprintf (bufs, sizeof bufs, SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + if (l < 0) + goto out; char *pos; size_t len; - if (0 <= l && l < sizeof bufs) + if (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. */ @@ -213,12 +215,15 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, __set_errno (saved_errno); vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); + va_end (apc); + + if (vl < 0) + goto out; - if (!(0 <= vl && vl < len)) + if (vl >= len) buf = NULL; bufsize = l + vl; - va_end (apc); } if (buf == NULL) @@ -229,25 +234,37 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, /* Tell the cancellation handler to free this buffer. */ clarg.buf = buf; + int cl; if (has_ts) - __snprintf (buf, l + 1, - SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + cl = __snprintf (buf, l + 1, + SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); else - __snprintf (buf, l + 1, - SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + cl = __snprintf (buf, l + 1, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); + if (cl != l) + goto out; va_list apc; va_copy (apc, ap); - __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, - mode_flags); + cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, + mode_flags); va_end (apc); + + if (cl != vl) + goto out; } else { + int bl; /* Nothing much to do but emit an error message. */ - bufsize = __snprintf (bufs, sizeof bufs, - "out of memory[%d]", __getpid ()); + bl = __snprintf (bufs, sizeof bufs, + "out of memory[%d]", __getpid ()); + if (bl < 0 || bl >= sizeof bufs) + goto out; + + bufsize = bl; buf = bufs; + msgoff = 0; } } -- cgit v1.2.3