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 <carlos@redhat.com>
This commit is contained in:
Arjun Shankar 2024-01-15 17:44:44 +01:00
parent 6bd0e4efcc
commit 7e5a0c286d

View File

@ -185,11 +185,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. */
@ -215,12 +217,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 (!(0 <= vl && vl < len))
if (vl < 0)
goto out;
if (vl >= len)
buf = NULL;
bufsize = l + vl;
va_end (apc);
}
if (buf == NULL)
@ -231,25 +236,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;
}
}