diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/unit/Makefile | 5 | ||||
-rw-r--r-- | tests/unit/test_op_call.c | 256 | ||||
-rw-r--r-- | tests/unit/testutil.h | 10 | ||||
-rw-r--r-- | tests/unit/util.c | 70 |
4 files changed, 209 insertions, 132 deletions
diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 966ae7d..6b8738a 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -16,8 +16,9 @@ SRCS_FILTER := $(COOKER_DIR)/filter.c $(COMMON_DIR)/common.c util.c \ HEADERS_FILTER := $(COOKER_DIR)/filter.h $(COMMON_DIR)/common.h \ $(DBG_DIR)/disasm.h testutil.h -HEADERS_OP_CALL := $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h -SRCS_OP_CALL := $(OP_DIR)/operations.c +HEADERS_OP_CALL := testutil.h $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h \ + $(COMMON_DIR)/common.h $(COMMON_DIR)/util.h +SRCS_OP_CALL := $(COMMON_DIR)/common.c $(OP_DIR)/operations.c util.c $(COMMON_DIR)/util.c HEADERS_OP := $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h \ $(COMMON_DIR)/common.h testutil.h $(COMMON_DIR)/util.h diff --git a/tests/unit/test_op_call.c b/tests/unit/test_op_call.c index 7f4b367..ea6f442 100644 --- a/tests/unit/test_op_call.c +++ b/tests/unit/test_op_call.c @@ -14,11 +14,13 @@ #include <sched.h> #include <sys/wait.h> #include <sys/syscall.h> +#include <sys/mman.h> #include <check.h> #include "common/gluten.h" #include "operations.h" +#include "testutil.h" struct args_write_file { char *file; @@ -26,6 +28,13 @@ struct args_write_file { ssize_t size; }; +static long nr; + +static void write_arg(struct op_call *call, int i, long v) +{ + ck_write_gluten(gluten, call->args[i], v); +} + static void write_file(char *file, char *t, ssize_t size) { int fd; @@ -50,159 +59,174 @@ static int write_file_clone(void *a) { struct args_write_file *args = (struct args_write_file *)a; write_file(args->file, args->t, args->size); - pause(); + install_single_syscall(SYS_getpid); + getpid(); return 0; } -static pid_t create_func_ns(int (*fn)(void *), void *arg, struct ns_spec ns[]) +static void set_ns_to_none(struct op_call *call) { - char stack[STACK_SIZE]; - pid_t child; - int flags = SIGCHLD; - unsigned int i; - - for (i = 0; i < sizeof(sizeof(enum ns_type)); i++) { - if (ns[i].type == NS_NONE) - continue; - switch (i) { - case NS_CGROUP: - flags |= CLONE_NEWCGROUP; - break; - case NS_IPC: - flags |= CLONE_NEWIPC; - break; - case NS_NET: - flags |= CLONE_NEWNET; - break; - case NS_MOUNT: - flags |= CLONE_NEWNS; - break; - case NS_PID: - flags |= CLONE_NEWPID; - break; - case NS_USER: - flags |= CLONE_NEWUSER; - break; - case NS_UTS: - flags |= CLONE_NEWUTS; - break; - case NS_TIME: - fprintf(stderr, - "option NS_TIME not suppoted by clone\n"); - break; - default: - fprintf(stderr, "unrecognized option %d\n", i); - } - } - child = clone(fn, stack + sizeof(stack), flags, arg); - if (child == -1) { - perror("clone"); - exit(EXIT_FAILURE); - } - return child; + for (unsigned int i = 0; i < NS_NUM; i++) + call->context.ns[i].type = NS_NONE; } -START_TEST(test_with_open_read_ns) +static void setup_ns(struct args_write_file *args) { - char test_file[] = "/tmp/test.txt"; - char t[PATH_MAX] = "Hello Test"; - struct args_write_file args = { test_file, t, sizeof(t) }; - struct op_call call; - int flags = O_RDWR; - struct arg_clone c; - char buf[PATH_MAX]; - unsigned i; - long count; - pid_t pid; - int ret; - - c.args = &call; - count = sizeof(buf); - for (i = 0; i < sizeof(enum ns_type); i++) - call.context.ns[i].type = NS_NONE; - call.context.ns[NS_MOUNT].type = NS_SPEC_PID; - pid = create_func_ns(write_file_clone, (void *)&args, call.context.ns); - call.context.ns[NS_MOUNT].id.pid = pid; - call.nr = SYS_open; - call.args[0] = (void *)&test_file; - call.args[1] = (void *)(long)flags; - ret = do_call(&c); - ck_assert_int_eq(ret, 0); - ck_assert_msg(c.ret >= 0, "expect ret %ld should be nonegative", c.ret); - - call.nr = SYS_read; - call.args[0] = (void *)(long)c.ret; - call.args[1] = (void *)&buf; - call.args[2] = (void *)count; - ret = do_call(&c); - kill(pid, SIGCONT); - - ck_assert_int_eq(ret, 0); - ck_assert_msg(c.ret == count, "expect ret %ld to be %ld", c.ret, count); - ck_assert_str_eq(t, buf); + at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + at->nr = __NR_getpid; + at->target = write_file_clone; + at->tclone = (void *)args; + at->ns[NS_MOUNT] = true; + setup(); } -END_TEST START_TEST(test_with_read) { char test_file[] = "/tmp/test.txt"; char t[PATH_MAX] = "Hello Test"; - struct op_call call; - struct arg_clone c; + struct op_call call = { + { OFFSET_RO_DATA, 0 }, + { + { OFFSET_DATA, 0 }, + { OFFSET_DATA, sizeof(long) }, + { OFFSET_DATA, sizeof(long) * 2 }, + }, + .has_ret = true, + .ret = { OFFSET_DATA, sizeof(long) * 3 }, + }; char buf[PATH_MAX]; - unsigned i; - long count; - int fd, ret; + long count, ret; + int fd; - c.args = &call; fd = write_file_get_fd(test_file, t, sizeof(t)); count = sizeof(buf); - for (i = 0; i < sizeof(enum ns_type); i++) + for (unsigned int i = 0; i < NS_NUM; i++) call.context.ns[i].type = NS_NONE; - call.nr = SYS_read; - call.args[0] = (void *)(long)fd; - call.args[1] = (void *)&buf; - call.args[2] = (void *)count; - ret = do_call(&c); - - ck_assert_int_eq(ret, 0); - ck_assert_msg(c.ret == count, "expect ret %ld to be %ld", c.ret, count); + + nr = SYS_read; + ck_write_gluten(gluten, call.nr, nr); + write_arg(&call, 0, (long)fd); + write_arg(&call, 1, (long)&buf); + write_arg(&call, 2, (long)count); + nr = SYS_read; + + ck_assert_int_eq(op_call(&req, notifyfd, &gluten, &call), 0); + + ck_read_gluten(gluten, call.ret, ret); + ck_assert_msg(ret == count, "expect ret %ld to be %ld", ret, count); ck_assert_str_eq(t, buf); } END_TEST START_TEST(test_with_getppid) { - struct op_call call; - struct arg_clone c; - unsigned i; + struct op_call call = { + .nr = { OFFSET_RO_DATA, 0 }, + .has_ret = true, + .ret = { OFFSET_DATA, 0 }, + }; long pid = (long)getpid(); - int ret; + int ret = -1; - for (i = 0; i < sizeof(enum ns_type); i++) + for (unsigned int i = 0; i < NS_NUM; i++) call.context.ns[i].type = NS_NONE; - call.nr = SYS_getppid; - c.args = &call; - ret = do_call(&c); - ck_assert_int_eq(ret, 0); - ck_assert_msg(c.ret == pid, "expect ret %ld to be equal to %ld", c.ret, - pid); + + nr = SYS_getppid; + ck_write_gluten(gluten, call.nr, nr); + + ck_assert_int_eq(op_call(&req, notifyfd, &gluten, &call), 0); + + ck_read_gluten(gluten, call.ret, ret); + ck_assert_msg(ret == pid, "expect ret %d to be equal to %ld", ret, pid); } END_TEST +START_TEST(test_with_open_read_ns) +{ + char test_file[] = "/tmp/test.txt"; + char t[PATH_MAX] = "Hello Test"; + struct args_write_file args = { test_file, t, sizeof(t) }; + struct op_call *call; + struct op ops[] = { + { OP_CALL, + { .call = { { OFFSET_RO_DATA, 0 }, /* open */ + { + { OFFSET_DATA, 0 }, + { OFFSET_DATA, sizeof(long) }, + { OFFSET_DATA, sizeof(long) * 2 }, + }, + .has_ret = true, + .ret = { OFFSET_DATA, sizeof(long) * 3 } } } }, + { OP_CALL, + { .call = { { OFFSET_RO_DATA, sizeof(long) }, /* read */ + { + { OFFSET_DATA, sizeof(long) * 3 }, /* ret of the previous call*/ + { OFFSET_DATA, sizeof(long) * 5 }, + { OFFSET_DATA, sizeof(long) * 6 }, + }, + .has_ret = true, + .ret = { OFFSET_DATA, sizeof(long) * 7 } } } }, + { OP_END, OP_EMPTY }, + + }; + int flags = O_RDWR; + char buf[PATH_MAX]; + long count, rcount; + + setup_ns(&args); + + /* Copy and configure op_calls */ + set_ns_to_none(&ops[0].op.call); + set_ns_to_none(&ops[1].op.call); + + nr = SYS_open; + call = &ops[0].op.call; + ck_write_gluten(gluten, call->nr, nr); + write_arg(call, 0, (long)&test_file); + write_arg(call, 1, (long)flags); + call->context.ns[NS_MOUNT].type = NS_SPEC_TARGET; + + nr = SYS_read; + call = &ops[1].op.call; + count = sizeof(buf); + ck_write_gluten(gluten, call->nr, nr); + write_arg(call, 1, (long)&buf); + write_arg(call, 2, (long)count); + call->context.ns[NS_MOUNT].type = NS_SPEC_TARGET; + + write_instr(gluten, ops); + + ck_assert_int_eq(eval(&gluten, &req, notifyfd), 0); + ck_read_gluten(gluten, ops[1].op.call.ret, rcount); + ck_assert_msg(rcount == count, "expect ret %ld to be %ld", rcount, count); + ck_assert_str_eq(t, buf); +} +END_TEST + + Suite *op_call_suite(void) { Suite *s; - TCase *tops; + TCase *tsimple, *tread, *treadns; + int timeout = 30; s = suite_create("Perform ops call"); - tops = tcase_create("op calls"); - tcase_add_test(tops, test_with_getppid); - tcase_add_test(tops, test_with_read); - tcase_add_test(tops, test_with_open_read_ns); + tsimple = tcase_create("getppid"); + tcase_add_test(tsimple, test_with_getppid); + suite_add_tcase(s, tsimple); + + tread = tcase_create("read"); + tcase_add_test(tread, test_with_read); + suite_add_tcase(s, tread); + + treadns = tcase_create("read ns"); - suite_add_tcase(s, tops); + tcase_add_checked_fixture(treadns, NULL, teardown); + tcase_set_timeout(treadns, timeout); + tcase_add_test(treadns, test_with_open_read_ns); + suite_add_tcase(s, treadns); return s; } diff --git a/tests/unit/testutil.h b/tests/unit/testutil.h index 4f104ac..b63d467 100644 --- a/tests/unit/testutil.h +++ b/tests/unit/testutil.h @@ -34,6 +34,12 @@ static inline void *test_gluten_write_ptr(struct gluten *g, } } +#define write_instr(gluten, ops) \ + do { \ + struct gluten_offset x = { OFFSET_INSTRUCTION, 0 }; \ + memcpy(test_gluten_write_ptr(&gluten, x), &ops, sizeof(ops)); \ + } while (0) + #define ck_write_gluten(gluten, value, ref) \ do { \ void *p = test_gluten_write_ptr(&gluten, value); \ @@ -58,6 +64,8 @@ struct args_target { bool filter_args[6]; struct bpf_arg args[6]; void *targs[6]; + void *tclone; + bool ns[NS_NUM]; int (*install_filter)(struct args_target *at); int (*target)(void *); }; @@ -74,7 +82,6 @@ extern char stdout_buff[BUFSIZ]; extern struct gluten gluten; int target(); -pid_t do_clone(int (*fn)(void *), void *arg); int create_test_fd(); int get_fd_notifier(pid_t pid); void target_exit(); @@ -91,4 +98,5 @@ void check_target_result_nonegative(); void ck_error_msg(char *s); void ck_stderr(); void ck_stdout(); +int install_single_syscall(long nr); #endif /* TESTUTIL_H */ diff --git a/tests/unit/util.c b/tests/unit/util.c index 5c36c54..66448bb 100644 --- a/tests/unit/util.c +++ b/tests/unit/util.c @@ -33,7 +33,7 @@ struct gluten gluten; char stderr_buff[BUFSIZ]; char stdout_buff[BUFSIZ]; -int install_notification_filter(struct args_target *at) +int install_single_syscall(long nr) { /* filter a single syscall for the tests */ struct sock_filter filter[] = { @@ -42,12 +42,17 @@ int install_notification_filter(struct args_target *at) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 0, 3), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, at->nr, 0, 1), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF), BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW), }; return install_filter( filter, (unsigned short)(sizeof(filter) / sizeof(filter[0]))); + +} +int install_notification_filter(struct args_target *at) +{ + return install_single_syscall(at->nr); } int target() @@ -76,18 +81,17 @@ int target() exit(0); } -pid_t do_clone(int (*fn)(void *), void *arg) +pid_t do_clone(int (*fn)(void *), void *arg, int flags) { - char stack[STACK_SIZE]; - pid_t child; - int flags = SIGCHLD; + char stack[STACK_SIZE]; + pid_t child; - child = clone(fn, stack + sizeof(stack), flags, arg); - if (child == -1) { - perror("clone"); - return -1; - } - return child; + child = clone(fn, stack + sizeof(stack), flags, arg); + if (child == -1) { + perror("clone"); + return -1; + } + return child; } int create_test_fd() @@ -203,6 +207,46 @@ void set_args_no_check(struct args_target *at) at->args[i].cmp = NO_CHECK; } +static int set_ns_flags(bool ns[], int flags) +{ + unsigned int i; + + for (i = 0; i < NS_NUM; i++) { + if (!ns[i] || i == NS_NONE) + continue; + switch (i) { + case NS_CGROUP: + flags |= CLONE_NEWCGROUP; + break; + case NS_IPC: + flags |= CLONE_NEWIPC; + break; + case NS_NET: + flags |= CLONE_NEWNET; + break; + case NS_MOUNT: + flags |= CLONE_NEWNS; + break; + case NS_PID: + flags |= CLONE_NEWPID; + break; + case NS_USER: + flags |= CLONE_NEWUSER; + break; + case NS_UTS: + flags |= CLONE_NEWUTS; + break; + case NS_TIME: + fprintf(stderr, + "option NS_TIME not suppoted by clone\n"); + break; + default: + fprintf(stderr, "unrecognized option %d\n", i); + } + } + return flags; +} + void setup() { int ret; @@ -211,7 +255,7 @@ void setup() ck_assert_int_ne(pipe(pipefd), -1); if (at->target == NULL) at->target = target; - pid = do_clone(at->target, NULL); + pid = do_clone(at->target, at->tclone, set_ns_flags(at->ns, SIGCHLD)); ck_assert_int_ge(pid, 0); /* Use write pipe to sync the target for checking the existance of the fd */ |