DF-0596 / race_harness_fixed.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | /* * 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; } |