FlawOpen

flawopen.com/Teardowns/cve-2023-6246-glibc-syslog-heap-buffer-overflow

● CVE-2023-6246 · CVSS 7.8 · High
FlawOpen Security Research

CVE-2023-6246: glibc syslog Heap Overflow

CVE-2023-6246 is a glibc syslog heap overflow triggered by a long log header. Update to your distribution’s fixed glibc package.

💡 Plain English Explainer (ELI5)

Imagine a clerk measuring a parcel and its shipping label with a short ruler. The label is too long to fit, so the clerk’s size calculation never records how much space it needs. The clerk then orders a tiny box and tries to print the full label and contents into it. In glibc, a long syslog header could leave the required size unset, causing the logger to allocate too little heap memory before writing the message.

Core Concepts & Subsystem Terms

glibc
The GNU C Library, which provides core C runtime functions used by most Linux programs.
__vsyslog_internal()
glibc’s internal implementation used by syslog() and vsyslog() to format a message and its SYSLOG_HEADER before sending it to the system logger.
SYSLOG_HEADER
The priority and identifying prefix formatted before a syslog message. It can include a program name or a caller-supplied openlog() ident.
Heap-based buffer overflow (CWE-122)
A write extends beyond a buffer allocated in heap memory. Here, the buffer-size calculation failed when the header containing a long program name did not fit in the initial fixed-size buffer.

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-122

Root Cause Analysis

The glibc advisory says __vsyslog_internal() failed to update the required buffer size when formatting a SYSLOG_HEADER containing a long program name. In the vulnerable code, the header length l could be at least the 1,024-byte stack buffer size, so the branch that formatted the message body and set bufsize was skipped. The later heap-allocation path therefore used an unset/zero size, then wrote the header and message into an undersized allocation. Qualys reports that the long name can come from the basename of a caller-controlled argv[0], or from an openlog() ident longer than 1,024 bytes; a vulnerable setuid program that logs through this path can make the bug security-sensitive. Qualys demonstrated local privilege escalation through su on Fedora 38. This is a local, configuration- and call-path-dependent issue, not a generic remote syslog exploit.

Step-by-Step Attack Flow

Step 1

Reach a vulnerable local logging call

A local process must reach syslog() or vsyslog() through a program using affected glibc. A security impact requires a privileged caller and a path where the caller does not replace the program-name prefix with a safe, bounded ident.

Step 2

The log header exceeds the initial buffer

The SYSLOG_HEADER includes a long program name (__progname, derived from the basename of argv[0]) or a long openlog() ident. Qualys reports that the triggering value must exceed 1,024 bytes.

Step 3

The required-size branch is skipped

When the header length does not fit in the 1,024-byte stack buffer, the vulnerable code skips the branch that computes bufsize. The heap-allocation path then has an insufficient size for the header and formatted message.

Step 4

Heap write exceeds the allocation

The logger writes the header and message into the undersized buffer, corrupting heap memory. Qualys demonstrated local privilege escalation through su on Fedora 38; do not infer the same reachability or impact for every application or distribution.

Source Code: Flaw vs. Secure Implementation

The old branch left bufsize at zero when the header did not fit the stack buffer, so the heap fallback could allocate too little space. The fix marks the stack buffer unusable in that case, formats into it to measure the body length, records l + vl, and uses the existing allocation path with the required size. These are focused upstream excerpts, not complete standalone functions.

Source excerpt: misc/syslog.c — __vsyslog_internal()

UNPATCHED FLAW
/* Focused excerpt from misc/syslog.c before commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = NULL;
size_t bufsize = 0;
...
if (0 <= l && l < sizeof bufs)
  {
    va_list apc;
    va_copy (apc, ap);
    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;
    va_end (apc);
  }
/* A long header skips the size-setting branch above. */
HARDENED SECURE PATCH
/* Focused excerpt from misc/syslog.c after commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = bufs;
size_t bufsize;
...
if (0 <= l && l < sizeof bufs)
  {
    pos = bufs + l;
    len = sizeof (bufs) - l;
  }
else
  {
    buf = NULL;
    pos = bufs;
    len = sizeof (bufs);
  }
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
if (!(0 <= vl && vl < len))
  buf = NULL;
bufsize = l + vl;

Engineering & System Hardening Checklist

Sources