/* test_dir.c — dir backend: host passthrough + path containment * (Section 6.2): a normalized ".." can't reach it (blocked in the * virtual namespace, Section 6.1), and an absolute symlink planted * inside the mount cannot be used to read outside it. */ #include #include #include #include #include "packfs.h" #include "test_harness.h" int main(void) { char root[] = "/tmp/packfs_test_dir_XXXXXX"; CHECK(mkdtemp(root) != NULL); char outside_dir[480]; snprintf(outside_dir, sizeof(outside_dir), "/tmp/packfs_secret_%d", (int)getpid()); mkdir(outside_dir, 0755); char secret_file[512]; snprintf(secret_file, sizeof(secret_file), "%s/secret.txt", outside_dir); FILE *sf = fopen(secret_file, "w"); CHECK(sf != NULL); fputs("top secret", sf); fclose(sf); /* a symlink INSIDE root pointing OUTSIDE it */ char link_path[512]; snprintf(link_path, sizeof(link_path), "%s/escape", root); CHECK(symlink(outside_dir, link_path) == 0); Vfs *v = vfs_new(); int derr = 0; Backend *dir = backend_dir_new(root, &derr); CHECK(dir != NULL); CHECK_EQ_INT(vfs_mount(v, "/", dir), VFS_OK); int err = 0; VfsFile *f = vfs_open(v, "/a.txt", VFS_O_WRONLY | VFS_O_CREAT, &err); CHECK(f != NULL); CHECK_EQ_INT(vfs_write(f, "abc", 3), 3); CHECK_EQ_INT(vfs_close(f), VFS_OK); f = vfs_open(v, "/a.txt", VFS_O_RDONLY, &err); char buf[8] = {0}; CHECK_EQ_INT(vfs_read(f, buf, sizeof(buf)), 3); CHECK_STR_EQ(buf, "abc"); CHECK_EQ_INT(vfs_close(f), VFS_OK); /* virtual-namespace ".." escape: rejected before any backend is reached */ f = vfs_open(v, "/../etc/shadow", VFS_O_RDONLY, &err); CHECK(f == NULL); CHECK_EQ_INT(err, VFS_ERR_INVAL); /* symlink escape through the dir backend itself: openat2/O_NOFOLLOW * containment (Section 6.2) must refuse to follow it. */ f = vfs_open(v, "/escape/secret.txt", VFS_O_RDONLY, &err); CHECK(f == NULL); vfs_unmount(v, "/"); backend_free(dir); vfs_free(v); TEST_MAIN_END(); }