DragonFlyBSD Kernel Audit
DF-0596 / race_harness_fixed.c
← back to finding ↓ download raw
/*
 * DF-0596 — Fixed version of race_harness.c demonstrating the fix.
 * Identical to race_harness.c but with:
 *   1. Bounds check on timeSent index (matching fix.diff hunk 1)
 *   2. Clamp on xmitWin after increment (matching fix.diff hunk 2)
 *
 * Build:  cc -O0 -lpthread -o race_harness_fixed race_harness_fixed.c
 * Run:    ./race_harness_fixed
 *
 * Expected: with the fix, xmitWin is clamped to <=16 and no OOB is detected,
 *           even with -O0 codegen that allows the TOCTOU to fire.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <stddef.h>

#define PPTP_XMIT_WIN       16
typedef uint64_t            pptptime_t;
#define PPTP_SEQ_DIFF(x,y)  ((int32_t)(x) - (int32_t)(y))

struct ng_pptpgre_ackp {
    int32_t         ato;
    int32_t         rtt;
    int32_t         dev;
    uint16_t        xmitWin;
    void           *sackTimerPtr;
    void           *rackTimerPtr;
    uint32_t        winAck;
    pptptime_t      timeSent[PPTP_XMIT_WIN];
};

struct ng_pptpgre_private {
    void                    *upper;
    void                    *lower;
    uint8_t                  conf_pad[16];
    struct ng_pptpgre_ackp   ackp;
    uint32_t                 recvSeq;
    uint32_t                 xmitSeq;
    uint32_t                 recvAck;
};

static struct ng_pptpgre_private priv;
static pthread_barrier_t bar;
static volatile uint32_t cur_ack;
static int nt;
static int max_xw = 0;
static int over_count = 0;

static void *
racer(void *arg)
{
    (void)arg;
    for (;;) {
        pthread_barrier_wait(&bar);
        if (cur_ack == 0xFFFFFFFF) break;
        uint32_t ack = cur_ack;
        struct ng_pptpgre_ackp *a = &priv.ackp;
        /* Growth logic WITH FIX: clamp after increment (fix.diff hunk 2) */
        if (PPTP_SEQ_DIFF(ack, a->winAck) >= 0
            && a->xmitWin < PPTP_XMIT_WIN) {
            a->xmitWin++;
            if (a->xmitWin > PPTP_XMIT_WIN)   /* FIX: clamp */
                a->xmitWin = PPTP_XMIT_WIN;
            a->winAck = ack + a->xmitWin;
        }
        pthread_barrier_wait(&bar);
    }
    return NULL;
}

int
main(void)
{
    printf("DF-0596 FIXED: xmitWin growth with clamp + OOB prevention\n");
    printf("=========================================================\n\n");

    size_t ts16 = offsetof(struct ng_pptpgre_private, ackp.timeSent[PPTP_XMIT_WIN]);
    size_t rs   = offsetof(struct ng_pptpgre_private, recvSeq);
    printf("Layout: &timeSent[16]=offset %zu, &recvSeq=offset %zu -> %s\n\n",
           ts16, rs, ts16 == rs ? "OVERLAP (OOB target)" : "MISMATCH");

    int nts[] = {2, 4, 8};
    for (int ti = 0; ti < 3; ti++) {
        nt = nts[ti];
        pthread_t th[8];
        int round_over = 0;
        int round_max = 0;

        pthread_barrier_init(&bar, NULL, nt + 1);
        for (int i = 0; i < nt; i++)
            pthread_create(&th[i], NULL, racer, NULL);

        for (int r = 0; r < 10000; r++) {
            priv.ackp.xmitWin = 15;
            priv.ackp.winAck  = 15;
            cur_ack = 15;

            pthread_barrier_wait(&bar);
            pthread_barrier_wait(&bar);

            int xw = priv.ackp.xmitWin;
            if (xw > round_max) round_max = xw;
            if (xw > PPTP_XMIT_WIN) round_over++;
        }

        cur_ack = 0xFFFFFFFF;
        pthread_barrier_wait(&bar);
        for (int i = 0; i < nt; i++)
            pthread_join(th[i], NULL);
        pthread_barrier_destroy(&bar);

        over_count += round_over;
        if (round_max > max_xw) max_xw = round_max;
        printf("[threads=%d] 10000 rounds: xmitWin>16 in %d rounds, max_xw=%d\n",
               nt, round_over, round_max);
    }

    printf("\n=== FIXED RESULTS ===\n");
    printf("Total over-16: %d, max_xw=%d (PPTP_XMIT_WIN=%d)\n",
           over_count, max_xw, PPTP_XMIT_WIN);
    if (over_count == 0) {
        printf("*** FIX WORKS: xmitWin clamped to PPTP_XMIT_WIN, no OOB possible ***\n");
        return 0;
    }
    printf("WARNING: xmitWin still exceeded PPTP_XMIT_WIN in %d rounds\n", over_count);
    return 1;
}