mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
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:
parent
6bd0e4efcc
commit
7e5a0c286d
@ -185,11 +185,13 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap,
|
|||||||
else
|
else
|
||||||
l = __snprintf (bufs, sizeof bufs,
|
l = __snprintf (bufs, sizeof bufs,
|
||||||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||||||
|
if (l < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
char *pos;
|
char *pos;
|
||||||
size_t len;
|
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
|
/* At this point, there is still a chance that we can print the
|
||||||
remaining part of the log into bufs and use that. */
|
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);
|
__set_errno (saved_errno);
|
||||||
|
|
||||||
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
|
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;
|
buf = NULL;
|
||||||
|
|
||||||
bufsize = l + vl;
|
bufsize = l + vl;
|
||||||
va_end (apc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf == NULL)
|
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. */
|
/* Tell the cancellation handler to free this buffer. */
|
||||||
clarg.buf = buf;
|
clarg.buf = buf;
|
||||||
|
|
||||||
|
int cl;
|
||||||
if (has_ts)
|
if (has_ts)
|
||||||
__snprintf (buf, l + 1,
|
cl = __snprintf (buf, l + 1,
|
||||||
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
SYSLOG_HEADER (pri, timestamp, &msgoff, pid));
|
||||||
else
|
else
|
||||||
__snprintf (buf, l + 1,
|
cl = __snprintf (buf, l + 1,
|
||||||
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff));
|
||||||
|
if (cl != l)
|
||||||
|
goto out;
|
||||||
|
|
||||||
va_list apc;
|
va_list apc;
|
||||||
va_copy (apc, ap);
|
va_copy (apc, ap);
|
||||||
__vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
|
cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc,
|
||||||
mode_flags);
|
mode_flags);
|
||||||
va_end (apc);
|
va_end (apc);
|
||||||
|
|
||||||
|
if (cl != vl)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int bl;
|
||||||
/* Nothing much to do but emit an error message. */
|
/* Nothing much to do but emit an error message. */
|
||||||
bufsize = __snprintf (bufs, sizeof bufs,
|
bl = __snprintf (bufs, sizeof bufs,
|
||||||
"out of memory[%d]", __getpid ());
|
"out of memory[%d]", __getpid ());
|
||||||
|
if (bl < 0 || bl >= sizeof bufs)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
bufsize = bl;
|
||||||
buf = bufs;
|
buf = bufs;
|
||||||
|
msgoff = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user