DF-0621 / check.c
/* * DF-0621 verification: rip6_output (raw_ip6.c:297-299) gates the * per-send cmsg path (IPV6_NEXTHOP, IPV6_HOPOPTS, ...) with: * * priv = 0; * if (so->so_cred->cr_uid == 0) * priv = 1; * * whereas the setsockopt path (ip6_output.c:1156-1158) correctly uses * caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT). * * The "privilege bypass" is in the wrong direction for unpriv users: * the cmsg path can only *fail to deny* a root-equivalent credential * whose capabilities have been reduced (capsicum). An unprivileged user * (cr_uid != 0) gets priv=0 either way -- and they cannot reach this * path at all because rip6_attach() at raw_ip6.c:530 requires * SYSCAP_NONET_RAW. So this is a defense-in-depth / hardening gap, NOT * an unpriv->root escalation. * * This PoC verifies the reachability ceiling: * - unpriv user CANNOT open AF_INET6/SOCK_RAW (EPERM expected) * - the code path therefore cannot be exercised by an unpriv user */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> int main(void) { int s; printf("[*] DF-0621 reachability check\n"); printf("[*] trying to open AF_INET6 SOCK_RAW as uid=%d\n", getuid()); s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); if (s < 0) { printf("[+] socket(AF_INET6, SOCK_RAW) FAILED: %s (errno=%d)\n", strerror(errno), errno); printf("[+] expected: SYSCAP_NONET_RAW required (rip6_attach raw_ip6.c:530)\n"); printf("[+] => unprivileged user CANNOT reach rip6_output\n"); printf("[+] => DF-0621 is a root-only hardening gap, not unpriv->root\n"); return 0; } printf("[!] socket succeeded -- privilege boundary broken?\n"); close(s); return 1; } |