Baron Samedit — sudo (CVE-2021-3156)

Baron Samedit — sudo (CVE-2021-3156)

TL;DR: A decade-old off-by-one in sudo’s command-line unescaping lets any local user overflow the heap and gain root, with no sudoers entry required.

What it is

Qualys disclosed this in January 2021 after auditing sudo’s argv handling. The bug lives in set_cmnd(): when sudo is invoked as sudoedit with the -s or -i flag, it enters a code path that copies argv into a heap buffer while unescaping backslashes. The loop terminates on \0, but a trailing single backslash makes the parser read past the end and write a NUL into adjacent heap metadata. Because the user controls the size and content of the surrounding user_args and nargv allocations, the overflow is shapeable into a full heap corruption that overwrites function pointers reached during sudo’s later cleanup, giving execution as root.

Preconditions / where it applies

  • sudo 1.8.2 through 1.8.31p2 and 1.9.0 through 1.9.5p1 (introduced July 2011 in commit 8255ed69)
  • Local UID with shell access; sudoers membership not required — the bug fires before authentication
  • Default installs of Ubuntu 16.04–20.10, Debian 9–10, Fedora 33, RHEL/CentOS 7–8
  • Patched in sudo 1.9.5p2 and distro updates from 2021-01-26

Technique

The invocation pattern that triggers the parser path is sudoedit -s plus a payload ending in a lone backslash:

1
2
# Crash check — vulnerable hosts segfault, patched hosts print usage
sudoedit -s '\' `python3 -c 'print("A"*65536)'`

A weaponised PoC primes the heap with nss_load_library structures via locale env vars, then chooses payload length so the overflowed NUL clobbers the service_user->library pointer to point at attacker data:

1
2
3
4
5
6
7
8
9
char *argv[] = {"sudoedit", "-s", payload, NULL};
char *envp[] = {
    "LC_ALL=C.UTF-8@",           // forces nss/libc locale load post-overflow
    "TZ=:",                      // primes another heap slab
    "SUDO_EDITOR=B",
    NULL
};
// payload = "\\" + repeated 'A' sized to land NUL on service_user metadata
execve("/usr/bin/sudoedit", argv, envp);

When sudo aborts and unwinds, glibc’s NSS calls dlopen() on the corrupted library pointer, loading a rogue .so that runs as root before sudo ever consults /etc/sudoers.

Detection and defence

  • Upgrade sudo to 1.9.5p2 or later; check with sudo --version
  • Quick vuln test: sudoedit -s / — patched binaries print usage:, vulnerable ones print sudoedit: /: not a regular file
  • auditd: -w /usr/bin/sudoedit -p x and alert on segfaults or unexpected dlopen from sudo’s PID
  • AppArmor profile for sudo (Ubuntu 21.04+) blocks the secondary dlopen path
  • Compile-time -D_FORTIFY_SOURCE=2 and glibc’s heap pointer mangling raise the cost of weaponisation but do not block exploitation
  • File integrity monitoring on /usr/bin/sudo and /etc/sudoers.d/ does not help — the bug needs no on-disk changes

References

See also: sudo-misconfig, linux-privesc-vectors, suid-sgid-binaries.