DF-5707 / strike2.c
/* * 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; } |