⬢ DragonFlyBSD Kernel Audit
DF-5707 / probe.c
← back to finding ↓ download raw
/*
 * probe.c - DF-5707 oracle prover: sends N ICMP echo requests to 127.0.0.1
 * through ipfw rule "prob 0.5 deny icmp from any to any icmptypes 8 via lo0"
 * and classifies each packet:
 *   'D' sendto returned EACCES   (denied at lo0 out-check: 1 draw, d1 <  T)
 *   'T' sent, no reply           (denied at lo0 in-check:  2 draws, d1>=T, d2 <  T)
 *   'R' reply received           (passed both request checks; reply draws never
 *                                 deny: total 4 draws, d1>=T, d2>=T)
 * Prints the obs string plus randseed before/after (read via /dev/mem).
 *
 * usage: probe <n> <delay_ms> <RSstatefile-out>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>

#define KERNBASE 0xFFFFFFFF80000000ULL
#define RSPHYS   0x1120c80            /* randseed phys = va - KERNBASE */

static uint64_t read_rs(int fd)
{
    uint64_t v = 0;
    if (pread(fd, &v, 8, RSPHYS) != 8) { perror("pread rs"); exit(1); }
    return v;
}

static unsigned short cksum(unsigned short *p, int n)
{
    unsigned long s = 0;
    while (n > 1) { s += *p++; n -= 2; }
    if (n) s += *(unsigned char *)p;
    s = (s >> 16) + (s & 0xffff);
    s += (s >> 16);
    return ~s;
}

int main(int argc, char **argv)
{
    int n = argc > 1 ? atoi(argv[1]) : 40;
    int delay_ms = argc > 2 ? atoi(argv[2]) : 20;
    int mfd = open("/dev/mem", O_RDONLY);
    if (mfd < 0) { perror("open /dev/mem"); return 1; }

    int s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (s < 0) { perror("socket"); return 1; }
    struct sockaddr_in dst;
    memset(&dst, 0, sizeof(dst));
    dst.sin_family = AF_INET;
    dst.sin_addr.s_addr = inet_addr("127.0.0.1");

    char *obs = calloc(n + 1, 1);
    uint64_t s0 = read_rs(mfd);

    struct timespec ts = { 0, delay_ms * 1000000 };
    for (int i = 0; i < n; i++) {
        char pkt[64];
        memset(pkt, 0, sizeof(pkt));
        struct icmp *icp = (struct icmp *)pkt;
        icp->icmp_type = ICMP_ECHO;
        icp->icmp_code = 0;
        icp->icmp_id = htons(0x5707);
        icp->icmp_seq = htons(i);
        icp->icmp_cksum = 0;
        icp->icmp_cksum = cksum((unsigned short *)pkt, 64);
        if (sendto(s, pkt, 64, 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) {
            if (errno == EACCES) obs[i] = 'D';
            else { fprintf(stderr, "sendto errno %d\n", errno); obs[i] = 'X'; }
        } else {
            obs[i] = 'T';          /* upgraded to R if reply arrives */
        }
        nanosleep(&ts, NULL);
    }

    /* drain replies: match icmp_id, echo reply type, seq */
    struct timeval tv = { 0, 300000 };
    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
        perror("setsockopt");
    int got = 0;
    for (;;) {
        char buf[128];
        struct sockaddr_in from;
        socklen_t flen = sizeof(from);
        ssize_t r = recvfrom(s, buf, sizeof(buf), 0,
                             (struct sockaddr *)&from, &flen);
        if (r < 0) break;          /* timeout: no more replies */
        struct icmp *icp = (struct icmp *)(buf + 20);  /* skip IP hdr (raw recv w/o IPHDRINCL gives ip header) */
        if ((size_t)r >= 20 + 8 && icp->icmp_type == ICMP_ECHOREPLY &&
            icp->icmp_id == htons(0x5707)) {
            int seq = ntohs(icp->icmp_seq);
            if (seq >= 0 && seq < n && obs[seq] == 'T') {
                obs[seq] = 'R';
                got++;
            }
        }
    }
    uint64_t s1 = read_rs(mfd);
    printf("RS0=%llx\n", (unsigned long long)s0);
    printf("RS1=%llx\n", (unsigned long long)s1);
    printf("OBS=%s\n", obs);
    fprintf(stderr, "sent=%d replies=%d D=%zd T=%zd R=%zd\n", n, got,
            (size_t)strchr(obs,'D') ? 0 : 0, (size_t)0, (size_t)0);
    int cD=0,cT=0,cR=0;
    for (char *p = obs; *p; p++) { if(*p=='D')cD++; else if(*p=='T')cT++; else if(*p=='R')cR++; }
    fprintf(stderr, "counts D=%d T=%d R=%d\n", cD, cT, cR);
    return 0;
}