/*
 * strike2.c - DF-5707: adjacent-inode i_gen chain demonstration.
 *
 * Attacker-visible fact (what an NFS client sees in file handles):
 *   i_gen(new inode) = krandom()/2 + 1        [ffs_alloc.c:642]
 * Since krandom() output == its state, each file's i_gen reveals the PRNG
 * draw that produced it, which predicts the next file's i_gen exactly:
 *   GEN_{i+1} = (16807 * (2*(GEN_i - 1))) mod (2^31-1) / 2 + 1
 *
 * This binary creates N files back-to-back (single process, no forks),
 * prints their inode numbers, and the kernel randseed before/after (control).
 * Verification of the printed GENs against the prediction is done from the
 * on-disk inodes (fsdb) afterwards.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define RSPHYS 0x1120c80
#define M 2147483647ULL
#define A 16807ULL

static uint64_t rrs(int fd)
{
    uint64_t v = 0;
    if (pread(fd, &v, 8, RSPHYS) != 8) { perror("pread"); exit(1); }
    return v;
}

int main(int argc, char **argv)
{
    int n = argc > 1 ? atoi(argv[1]) : 10;
    int mfd = open("/dev/mem", O_RDONLY);
    if (mfd < 0) { perror("/dev/mem"); return 1; }

    uint64_t rs0 = rrs(mfd);
    printf("RS-before=%llu\n", (unsigned long long)rs0);
    for (int i = 0; i < n; i++) {
        char path[64];
        snprintf(path, sizeof(path), "/mnt/chain_%02d", i);
        int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0644);
        if (fd < 0) { perror(path); return 1; }
        write(fd, "x", 1);
        close(fd);
    }
    uint64_t rs1 = rrs(mfd);
    printf("RS-after=%llu\n", (unsigned long long)rs1);
    for (int i = 0; i < n; i++) {
        struct stat st;
        char path[64];
        snprintf(path, sizeof(path), "/mnt/chain_%02d", i);
        stat(path, &st);
        printf("CHAIN %02d ino=%llu\n", i, (unsigned long long)st.st_ino);
    }
    return 0;
}
