From 2c820c1dd737f1036733aedef4d2e6d43cd7df3e Mon Sep 17 00:00:00 2001 From: Jake Hillion Date: Fri, 31 Dec 2021 17:17:53 +0000 Subject: [PATCH] added unshare tests for clone_fs --- assertions/namespaces/fs/TestClone.c | 6 +- assertions/namespaces/fs/TestUnshare.c | 314 ++++++++++++++++++++++++- 2 files changed, 314 insertions(+), 6 deletions(-) diff --git a/assertions/namespaces/fs/TestClone.c b/assertions/namespaces/fs/TestClone.c index d18df39..4ede922 100644 --- a/assertions/namespaces/fs/TestClone.c +++ b/assertions/namespaces/fs/TestClone.c @@ -35,7 +35,7 @@ long clone3(struct clone_args *cl_args) { return syscall(SYS_clone3, cl_args, sizeof(struct clone_args)); } -void test_cloneFs_chdir_propagates(void) { +void test_cloneFs_chdir_doesPropagate(void) { // PREPARE char tmpDir[] = "/tmp/tmpdir-XXXXXX"; TEST_ASSERT_NOT_EQUAL_MESSAGE(NULL, mkdtemp(tmpDir), "tmpdir failed"); @@ -65,7 +65,7 @@ void test_cloneFs_chdir_propagates(void) { long cloneResult = clone3(&cl_args); if (cloneResult == 0) { if (chdir(tmpDir) != 0) { - exit(1); + exit(1); // chdir failed } exit(0); @@ -132,7 +132,7 @@ void test_cloneNoFs_chdir_doesNotPropagate(void) { long cloneResult = clone3(&cl_args); if (cloneResult == 0) { if (chdir(tmpDir) != 0) { - exit(1); + exit(1); // chdir failed } exit(0); diff --git a/assertions/namespaces/fs/TestUnshare.c b/assertions/namespaces/fs/TestUnshare.c index 57ae58c..6669bca 100644 --- a/assertions/namespaces/fs/TestUnshare.c +++ b/assertions/namespaces/fs/TestUnshare.c @@ -1,6 +1,314 @@ +#define _GNU_SOURCE + #include "unity.h" -void setUp() {} -void tearDown() {} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -void test_alwaysSucceeds_succeeds() { TEST_ASSERT_EQUAL(1, 1); } +#include + +void setUp(void) { + static char *initialDir = NULL; + if (initialDir == NULL) { + initialDir = get_current_dir_name(); + } + + TEST_ASSERT_NOT_EQUAL_MESSAGE(NULL, initialDir, + "get working directory failed"); + TEST_ASSERT_EQUAL_MESSAGE(0, chdir(initialDir), + "returning to working directory failed"); +} + +void tearDown(void) {} + +long clone3(struct clone_args *cl_args) { + return syscall(SYS_clone3, cl_args, sizeof(struct clone_args)); +} + +void test_unshareNoFsFromFork_chdir_doesNotPropagate(void) { + // PREPARE + char tmpDir[] = "/tmp/tmpdir-XXXXXX"; + TEST_ASSERT_NOT_EQUAL_MESSAGE(NULL, mkdtemp(tmpDir), "tmpdir failed"); + + // ACT + pid_t forkedChildPid; + + if ((forkedChildPid = fork()) == 0) { + // child process - act but do not assert + // all assertions will be on the return code + pid_t clonedChildPid; + + if ((clonedChildPid = fork()) == 0) { + if (unshare(0) == -1) { + exit(1); // unshare failed + } + + if (chdir(tmpDir) != 0) { + exit(2); // chdir failed + } + + exit(0); + } else if (clonedChildPid == -1) { + exit(3); // fork failed + } + + siginfo_t status; + if (waitid(P_PID, clonedChildPid, &status, WEXITED) == -1) { + exit(4); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + char *cwd = get_current_dir_name(); + int directory_moved = strcmp(cwd, tmpDir); + free(cwd); + + if (directory_moved == 0) { + exit(5); // chdir did propagate + } + + exit(0); + } + + // 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"); +} + +void test_unshareFsFromFork_chdir_doesNotPropagate(void) { + // PREPARE + char tmpDir[] = "/tmp/tmpdir-XXXXXX"; + TEST_ASSERT_NOT_EQUAL_MESSAGE(NULL, mkdtemp(tmpDir), "tmpdir failed"); + + // ACT + pid_t forkedChildPid; + + if ((forkedChildPid = fork()) == 0) { + // child process - act but do not assert + // all assertions will be on the return code + pid_t clonedChildPid; + + if ((clonedChildPid = fork()) == 0) { + if (unshare(CLONE_FS) == -1) { + exit(1); // unshare failed + } + + if (chdir(tmpDir) != 0) { + exit(2); // chdir failed + } + + exit(0); + } else if (clonedChildPid == -1) { + exit(3); // fork failed + } + + siginfo_t status; + if (waitid(P_PID, clonedChildPid, &status, WEXITED) == -1) { + exit(4); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + char *cwd = get_current_dir_name(); + int directory_moved = strcmp(cwd, tmpDir); + free(cwd); + + if (directory_moved == 0) { + exit(5); // chdir did propagate + } + + exit(0); + } + + // 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"); +} + +void test_unshareNoFsFromClone_chdir_doesPropagate(void) { + // PREPARE + char tmpDir[] = "/tmp/tmpdir-XXXXXX"; + TEST_ASSERT_NOT_EQUAL(NULL, mkdtemp(tmpDir)); + + char subDirA[21]; + TEST_ASSERT_GREATER_THAN(0, sprintf(subDirA, "%s/a", tmpDir)); + TEST_ASSERT_EQUAL(0, mkdir(subDirA, 0700)); + + char subDirB[21]; + TEST_ASSERT_GREATER_THAN(0, sprintf(subDirB, "%s/b", tmpDir)); + TEST_ASSERT_EQUAL(0, mkdir(subDirB, 0700)); + + // 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 = SIGCHLD, + .stack = 0, + .stack_size = 0, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + long cloneResult = clone3(&cl_args); + if (cloneResult == 0) { + if (chdir(subDirA) != 0) { + exit(1); // chdir failed + } + + if (unshare(0) == -1) { + exit(1); // unshare failed + } + + if (chdir(subDirB) != 0) { + exit(1); // chdir failed + } + + exit(0); + } else if (cloneResult == -1) { + exit(2); // clone failed + } + + siginfo_t status; + if (waitid(P_PIDFD, clonedChildPidFd, &status, WEXITED) == -1) { + exit(3); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + char *cwd = get_current_dir_name(); + int directory_moved = strcmp(cwd, subDirB); + free(cwd); + + if (directory_moved != 0) { + exit(4); // chdir propagated unexpectedly + } + + exit(0); + } + + // 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"); +} + +void test_unshareFsFromClone_chdir_doesNotPropagate(void) { + // PREPARE + char tmpDir[] = "/tmp/tmpdir-XXXXXX"; + TEST_ASSERT_NOT_EQUAL(NULL, mkdtemp(tmpDir)); + + char subDirA[21]; + TEST_ASSERT_GREATER_THAN(0, sprintf(subDirA, "%s/a", tmpDir)); + TEST_ASSERT_EQUAL(0, mkdir(subDirA, 0700)); + + char subDirB[21]; + TEST_ASSERT_GREATER_THAN(0, sprintf(subDirB, "%s/b", tmpDir)); + TEST_ASSERT_EQUAL(0, mkdir(subDirB, 0700)); + + // 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 = SIGCHLD, + .stack = 0, + .stack_size = 0, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + long cloneResult = clone3(&cl_args); + if (cloneResult == 0) { + if (chdir(subDirA) != 0) { + exit(1); // chdir failed + } + + if (unshare(CLONE_FS) == -1) { + exit(1); // unshare failed + } + + if (chdir(subDirB) != 0) { + exit(1); // chdir failed + } + + exit(0); + } else if (cloneResult == -1) { + exit(2); // clone failed + } + + siginfo_t status; + if (waitid(P_PIDFD, clonedChildPidFd, &status, WEXITED) == -1) { + exit(3); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + char *cwd = get_current_dir_name(); + int directory_moved = strcmp(cwd, subDirA); + free(cwd); + + if (directory_moved != 0) { + exit(4); // chdir propagated unexpectedly + } + + exit(0); + } + + // 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"); +}