DragonFlyBSD Kernel Audit
DF-1534 / harness.c
← back to finding ↓ download raw
/* DF-1534/DF-1542: atom_op_calltable unbounded recursion harness.
 * Mirrors the source-level recursion structure of atom_execute_table_locked.
 * Original source has NO depth guard, so a self-referential table (table[N]
 * starts with CALL_TABLE N) recurses until stack exhaustion.
 *
 * Real kernel stack is 16KB. Each atom_execute_table_locked frame allocates
 * an atom_exec_context (~48 bytes), callsite state (~50 bytes), plus C frame
 * overhead (~50-150 bytes) -> ~150-250 bytes/frame.
 *
 * 16KB / 200 bytes = ~80 frames until stack overflow -> fatal double fault.
 *
 * This harness does NOT actually overflow (we cap the demo at 200 calls so
 * the shell survives); instead it shows that the unpatched code recurses
 * indefinitely while the patched code aborts at depth 20.
 */
#include <stdio.h>
#include <stdlib.h>

static int fixed = 0;
static int max_depth = 0;
static const int CAP = 500;  /* demo ceiling so harness survives */

static int op_calltable(int idx, int depth);
static int execute_table_locked(int index, int depth);

static int op_calltable(int idx, int depth) {
    /* In real VBIOS, this is reached if U16(cmd_table+4+2*idx) != 0 */
    return execute_table_locked(idx, depth + 1);
}

static int execute_table_locked(int index, int depth) {
    if (depth > max_depth) max_depth = depth;
    if (fixed && depth > 20) {
        return -1;  /* patched: -EINVAL */
    }
    if (depth > CAP) {
        return -1;  /* harness safety cap */
    }
    /* table 3 body: CALL_TABLE 3 (self-recursion) */
    if (index == 3) {
        return op_calltable(3, depth);
    }
    return 0;
}

int main(int argc, char **argv) {
    if (argc > 1 && !strcmp(argv[1], "--fixed")) fixed = 1;

    int r = execute_table_locked(3, 0);

    if (fixed) {
        printf("max_recursion_depth_reached=%d (capped at 20)\n", max_depth);
        printf("RESULT: PATCHED - recursion_depth guard aborts at depth 20 (-EINVAL)\n");
    } else {
        /* In real kernel: would hit 16KB stack limit / fatal double fault
         * long before CAP. We cap at 500 here only so the harness survives. */
        printf("max_recursion_depth_reached=%d (capped by harness at %d)\n", max_depth, CAP);
        printf("RESULT: BUGGY - no depth guard; real kernel stack overflows at ~80 frames\n");
    }
    return 0;
}