From 3498e9b26a2da46282705791679aa26565a30e99 Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Thu, 30 Dec 2021 20:31:52 +0000 Subject: [PATCH] wip: cloning fs namespace --- assertions/Makefile | 25 +++++-- assertions/namespaces/fs/TestClone.c | 100 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 assertions/namespaces/fs/TestClone.c diff --git a/assertions/Makefile b/assertions/Makefile index f19e21b..4028483 100644 --- a/assertions/Makefile +++ b/assertions/Makefile @@ -8,20 +8,31 @@ CFLAGS = -std=c17 INC_DIRS=-I$(UNITY_ROOT)/src -SRC_NAMESPACES_FS_1=$(UNITY_ROOT)/src/unity.c namespaces/fs/TestUnshare.c test_runners/namespaces_fs_TestUnshare_Runner.c -TARGET_NAMESPACES_FS_1=target/test_namespaces_fs +SRC_NAMESPACES_FS_UNSHARE=$(UNITY_ROOT)/src/unity.c namespaces/fs/TestUnshare.c test_runners/namespaces_fs_TestUnshare_Runner.c +SRC_NAMESPACES_FS_CLONE=$(UNITY_ROOT)/src/unity.c namespaces/fs/TestClone.c test_runners/namespaces_fs_TestClone_Runner.c + +TARGET_NAMESPACES_FS_UNSHARE=target/test_namespaces_fs_unshare +TARGET_NAMESPACES_FS_CLONE=target/test_namespaces_fs_clone all: clean default -default: $(TARGET_NAMESPACES_FS_1) - - ./$(TARGET_NAMESPACES_FS_1) +default: $(SRC_NAMESPACES_FS_UNSHARE) $(SRC_NAMESPACES_FS_CLONE) + $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FS_UNSHARE) -o $(TARGET_NAMESPACES_FS_UNSHARE) + $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FS_CLONE) -o $(TARGET_NAMESPACES_FS_CLONE) -$(TARGET_NAMESPACES_FS_1): $(SRC_NAMESPACES_FS_1) - $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FS_1) -o $(TARGET_NAMESPACES_FS_1) + @echo + @echo Finished preparing tests, running now. + @echo + + - ./$(TARGET_NAMESPACES_FS_UNSHARE) + - ./$(TARGET_NAMESPACES_FS_CLONE) test_runners/namespaces_fs_TestUnshare_Runner.c: namespaces/fs/TestUnshare.c ruby $(UNITY_ROOT)/auto/generate_test_runner.rb namespaces/fs/TestUnshare.c test_runners/namespaces_fs_TestUnshare_Runner.c +test_runners/namespaces_fs_TestClone_Runner.c: namespaces/fs/TestClone.c + ruby $(UNITY_ROOT)/auto/generate_test_runner.rb namespaces/fs/TestClone.c test_runners/namespaces_fs_TestClone_Runner.c + clean: - $(CLEANUP) $(TARGET_NAMESPACES_FS_1) + $(CLEANUP) $(TARGET_NAMESPACES_FS_UNSHARE) $(TARGET_NAMESPACES_FS_CLONE) mkdir -p test_runners/ target/ diff --git a/assertions/namespaces/fs/TestClone.c b/assertions/namespaces/fs/TestClone.c new file mode 100644 index 0000000..40a0e5d --- /dev/null +++ b/assertions/namespaces/fs/TestClone.c @@ -0,0 +1,100 @@ +#define _GNU_SOURCE + +#include "unity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CHILD_STACK_SIZE (8 * 1024 * 1024) + +#define FILE_DEFAULT_NS ("/tmp/file_exists_0148c163-5919-4651") +#define FILE_NEW_NS ("/tmp/file_exists_fd0fd491-9816-442d") + +void createFile(const char *fname) { + int fd = open(fname, O_RDONLY | O_CREAT, 0644); + TEST_ASSERT_GREATER_THAN_MESSAGE(0, fd, "open failed"); + TEST_ASSERT_EQUAL_MESSAGE(0, close(fd), "close failed"); +} + +void deleteFileIfExists(const char *fname) { + if (access(fname, F_OK) == 0) { + TEST_ASSERT_EQUAL_MESSAGE(0, unlink(fname), "unlink failed"); + } +} + +void setUp(void) { createFile(FILE_DEFAULT_NS); } + +void tearDown(void) { deleteFileIfExists(FILE_DEFAULT_NS); } + +long clone3(struct clone_args *cl_args) { + return syscall(SYS_clone3, cl_args, sizeof(struct clone_args)); +} + +void test_cloneFs_findsFileWhenFsCloned_succeeds(void) { + // PREPARE + + // ACT + pid_t forkedChildPid; + + if ((forkedChildPid = fork()) == 0) { + // child process - act but do not assert + // all assertions will be on the return code + int clonedChildPidFd; + + struct clone_args cl_args = { + .flags = CLONE_PIDFD | CLONE_FS, + .pidfd = (uint64_t)(&clonedChildPidFd), + .child_tid = 0, + .parent_tid = 0, + .exit_signal = 0, + .stack = 0, + .stack_size = 0, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + long cloneResult = clone3(&cl_args); + if (cloneResult == 0) { + printf("child\n"); + sleep(30); + + exit(0); + } else if (cloneResult == -1) { + exit(1); // clone failed + } + + sleep(30); + siginfo_t status; + printf("clonedChildPidFd: %d\n", clonedChildPidFd); + if (waitid(P_PIDFD, clonedChildPidFd, &status, WEXITED) == -1) { + perror("waitid"); + exit(2); // wait failed + } + + // MUST exit this process and not return + // else the test runner will be duplicated + + exit(status.si_status); // propogate return status + } + + // ASSERT + TEST_ASSERT_GREATER_THAN_MESSAGE(0, forkedChildPid, "fork failed"); + + int status = 0; + TEST_ASSERT_EQUAL_MESSAGE(forkedChildPid, waitpid(forkedChildPid, &status, 0), + "wait failed"); + TEST_ASSERT_EQUAL_MESSAGE(0, WEXITSTATUS(status), "return status non-zero"); +}