DragonFlyBSD Kernel Audit
DF-1332 / trigger.c
← back to finding ↓ download raw
/* DF-1332 amdgpu_fill_buffer uint32 truncation skips VRAM clear */
#include <stdio.h>
#include <stdint.h>

#define PAGE_SHIFT 12
#define DIV_ROUND_UP(n,d) (((n)+(d)-1)/(d))

static int num_loops_vuln(uint64_t mm_node_size, uint32_t max_bytes){
    uint32_t byte_count = mm_node_size << PAGE_SHIFT;   /* TRUNCATES if >= 4GiB */
    return DIV_ROUND_UP(byte_count, max_bytes);
}
static int num_loops_fixed(uint64_t mm_node_size, uint32_t max_bytes){
    uint64_t byte_count = mm_node_size << PAGE_SHIFT;
    if (byte_count == 0) return 0;
    /* emulate integer ceil-divide across the full u64 range */
    uint64_t loops = (byte_count + max_bytes - 1) / max_bytes;
    if (loops > 1000000) return 1000000;     /* saturate for test */
    return (int)loops;
}

int main(void){
    /* mm_node->size of 0x100000 = 4 GiB worth of pages */
    uint64_t huge = 0x100000ULL;   /* 2^20 pages = 4 GiB */
    uint32_t max_bytes = 0x400000; /* typical SDMA fill chunk */
    printf("== BEFORE-FIX (vulnerable) ==\n");
    int n = num_loops_vuln(huge, max_bytes);
    printf("BUG: byte_count = mm_node->size<<PAGE_SHIFT truncates to 0x%08x, num_loops=%d -> VRAM clear SKIPPED\n",
           (uint32_t)(huge << PAGE_SHIFT), n);
    printf("       Freshly allocated VRAM contains previous BO contents -> cross-user leak of GPU memory\n");
    printf("== AFTER-FIX ==\n");
    int n2 = num_loops_fixed(huge, max_bytes);
    printf("FIX: byte_count is uint64_t, num_loops=%d -> SDMA fill runs correctly\n", n2);
    return 0;
}