/*
 * 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;
}
