DragonFlyBSD Kernel Audit
DF-1585 / harness.c
← back to finding ↓ download raw
/* DF-1585: intel_fbc compressed_llb UAF harness.
 * __intel_fbc_cleanup_cfb frees compressed_llb but does NOT NULL it.
 * Second call re-enters the if() with dangling pointer ->
 * i915_gem_stolen_remove_node(dev_priv, fbc->compressed_llb) UAF.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int fixed = 0;

struct llb { int x; };  /* mock */
struct dev_priv { struct llb *compressed_llb; int freed_already; };

static void stolen_remove(struct llb *p) {
    if (!p) return;
    if (p->x == 0xdead) printf("UAF: reused freed memory at %p\n", (void*)p);
}

static void cleanup_cfb(struct dev_priv *dp) {
    if (dp->compressed_llb) {
        stolen_remove(dp->compressed_llb);
        free(dp->compressed_llb);
        if (fixed) dp->compressed_llb = NULL;
    }
}

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

    struct dev_priv dp = {0};
    dp.compressed_llb = malloc(sizeof(struct llb));
    dp.compressed_llb->x = 42;

    /* first cleanup (suspend/CRTC teardown) */
    cleanup_cfb(&dp);

    if (!fixed) {
        /* simulate the dangling-pointer case: alloc something else that
         * reoccupies the freed slab slot, marked with canary */
        struct llb *interloper = malloc(sizeof(struct llb));
        interloper->x = 0xdead;
        /* second cleanup (driver unload): re-enters if(), UAF */
        cleanup_cfb(&dp);
        free(interloper);
        printf("RESULT: BUGGY - 2nd cleanup re-entered with dangling ptr\n");
    } else {
        cleanup_cfb(&dp);
        printf("RESULT: PATCHED - 2nd cleanup no-op (compressed_llb=NULL)\n");
    }
    return 0;
}