/*
 * DF-0521 — ng_ksocket_sockaddr_unparse() PF_LOCAL sun_len<pathoff underflow
 *
 * Bug (sys/netgraph/ksocket/ng_ksocket.c:321-339):
 *   const int pathoff = OFFSETOF(struct sockaddr_un, sun_path);  // = 2
 *   const int pathlen = sun->sun_len - pathoff;     // signed underflow
 *   char pathbuf[SOCK_MAXADDRLEN + 1];
 *   bcopy(sun->sun_path, pathbuf, pathlen);          // size_t ~2^64
 *   pathbuf[pathlen] = '\0';                         // neg-index stack write
 *
 * If `sun->sun_len < 2`, `pathlen` becomes negative; bcopy interprets it
 * as `size_t` and copies ~2^64 bytes into the 256-byte stack buffer.
 * `pathbuf[pathlen]` writes at a negative stack offset.  Stack OOB
 * write + stack info leak → kernel panic or worse.
 *
 * TRIGGER REALITY (per the finding summary): the only path that calls
 * `unparse` is the netgraph subsystem's serialization of a sockaddr to
 * ASCII (e.g. ngctl msg GETNAME/GETPEERNAME).  The sockaddr comes from
 * `so_pru_peeraddr` / `so_pru_sockaddr`, which the kernel always fills
 * with a valid `sun_len`.  An unprivileged user cannot reach unparse:
 * `ngctl` itself requires `socket(AF_NETGRAPH)` which is root-only.
 *
 * Therefore this is a **defense-in-depth** bug: it would become
 * exploitable only if some other kernel path (a) produced a sockaddr_un
 * with sun_len < 2, or (b) let user-supplied data reach unparse
 * directly.  The identical twin in netgraph7 (DF-0509) has the same
 * property.  Generic helper `ng_parse_generic_sockdata_getLength`
 * (line 169-177) DOES guard this case — the PF_LOCAL special-case
 * unparse omits the guard.
 *
 * This PoC is a static demonstration of the math; the actual kernel
 * trigger requires root + a kernel-side malformed-sockaddr source.
 *
 * Build:  cc -O2 -o df0521 df0521.c
 * Run:    ./df0521
 */
#include <stdio.h>
#include <string.h>
#include <stddef.h>

/* Mirror OFFSETOF(struct sockaddr_un, sun_path) */
struct sockaddr_un_min {
    unsigned char sun_len;
    unsigned char sun_family;
    char sun_path[1];
};
#define PATHOFF (int)offsetof(struct sockaddr_un_min, sun_path)
#define SOCK_MAXADDRLEN 255

int main(void)
{
    /* Case 1: well-formed sockaddr_un (pathoff=2, sun_len=14, pathlen=12) */
    unsigned char well_formed[] = {14, /*PF_LOCAL*/1, '/','t','m','p','/','f','o','o','.','s','o','c','k'};
    int plen_ok = well_formed[0] - PATHOFF;
    printf("well-formed: sun_len=%u, pathoff=%d -> pathlen=%d (OK)\n",
           well_formed[0], PATHOFF, plen_ok);

    /* Case 2: malformed sun_len=1 (< pathoff=2).  SIGNED subtraction
     * yields -1; (size_t)-1 = 18446744073709551615.  bcopy would copy
     * ~2^64 bytes. */
    unsigned char malformed[] = {1, /*PF_LOCAL*/1, 'X'};
    int pathlen = (int)malformed[0] - PATHOFF;
    unsigned long as_size_t = (unsigned long)pathlen;
    printf("malformed:  sun_len=%u, pathoff=%d -> pathlen=%d\n",
           malformed[0], PATHOFF, pathlen);
    printf("            (size_t)pathlen = %lu bytes\n", as_size_t);
    printf("            target buffer:   pathbuf[%d+1] (stack)\n", SOCK_MAXADDRLEN);
    printf("            pathbuf[pathlen] = '\\0' writes at stack offset %d\n",
           pathlen);
    printf("            => stack OOB write of ~%lu bytes + neg-index write\n",
           as_size_t);
    printf("\nConclusion: code-path is genuinely vulnerable to sun_len<pathoff;\n");
    printf("            reachable only via a kernel-produced malformed sockaddr.\n");
    printf("            Fix: clamp pathlen to 0 when sun_len<pathoff (see fix.diff).\n");
    return 0;
}
