65 lines
2.1 KiB
C
65 lines
2.1 KiB
C
/* 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 <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
|
||
|
|
#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();
|
||
|
|
}
|