aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--common/gluten.h10
-rw-r--r--operations.c31
-rw-r--r--operations.h3
-rw-r--r--tests/unit/Makefile5
-rw-r--r--tests/unit/test_op_call.c256
-rw-r--r--tests/unit/testutil.h10
-rw-r--r--tests/unit/util.c70
7 files changed, 234 insertions, 151 deletions
diff --git a/common/gluten.h b/common/gluten.h
index 07f4148..9bd4689 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -32,6 +32,8 @@ extern struct seccomp_data anonymous_seccomp_data;
#define OP_EMPTY { .block = { -1 } }
#define NO_FIELD block
+#define NS_NUM sizeof(enum ns_type)
+
enum gluten_offset_type {
OFFSET_RO_DATA = 0,
OFFSET_DATA = 1,
@@ -183,7 +185,7 @@ struct op {
} op;
};
-#ifdef COOKER
+#if defined(COOKER) || defined(SEITAN_TEST)
# define GLUTEN_CONST
#else
# define GLUTEN_CONST const
@@ -269,7 +271,11 @@ static inline const void *gluten_ptr(const struct seccomp_data *s,
static inline bool check_gluten_limits(struct gluten_offset v, size_t size)
{
struct gluten_offset off = { v.type, v.offset + size };
- return is_offset_valid(off);
+ if (is_offset_valid(off))
+ return true;
+
+ err(" offset limits are invalid");
+ return false;
}
static inline int gluten_write(struct gluten *g, struct gluten_offset dst,
diff --git a/operations.c b/operations.c
index 60c8410..8d8b926 100644
--- a/operations.c
+++ b/operations.c
@@ -34,10 +34,10 @@ static bool is_cookie_valid(int notifyFd, uint64_t id)
static int send_target(const struct seccomp_notif_resp *resp, int notifier)
{
if (!is_cookie_valid(notifier, resp->id))
- ret_err(-1, "the response id isn't valid");
+ ret_err(-1, " the response id isn't valid");
if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0)
if (errno != EINPROGRESS)
- ret_err(-1, "sending the response");
+ ret_err(-1, " sending the response");
return 0;
}
@@ -45,10 +45,10 @@ static int send_inject_target(const struct seccomp_notif_addfd *resp,
int notifier)
{
if (!is_cookie_valid(notifier, resp->id))
- ret_err(-1, "the response id isn't valid");
+ ret_err(-1, " the response id isn't valid");
if (ioctl(notifier, SECCOMP_IOCTL_NOTIF_ADDFD, resp) < 0)
if (errno != EINPROGRESS)
- ret_err(-1, "sending the response");
+ ret_err(-1, " sending the response");
return 0;
}
@@ -98,9 +98,8 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
if (gluten_read(NULL, g, &c->nr, op->nr, sizeof(c->nr)) == -1)
return -1;
-
for (i = 0; i < 6; i++)
- if (gluten_read(NULL, g, &c->args[i], op->nr,
+ if (gluten_read(NULL, g, &c->args[i], op->args[i],
sizeof(c->args[i])) == -1)
return -1;
@@ -112,19 +111,19 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
strncpy(c->ns[i].path, "", PATH_MAX);
break;
case NS_SPEC_TARGET:
- snprintf(c->ns[i].path, PATH_MAX, "/proc/%d/ns/%s", req->pid,
- ns_name);
+ snprintf(c->ns[i].path, PATH_MAX, "/proc/%d/ns/%s",
+ req->pid, ns_name);
break;
case NS_SPEC_PID:
if (gluten_read(NULL, g, &pid, ns->id, ns->size) == -1)
return -1;
- snprintf(c->ns[i].path, PATH_MAX , "/proc/%d/ns/%s", pid,
+ snprintf(c->ns[i].path, PATH_MAX, "/proc/%d/ns/%s", pid,
ns_name);
break;
case NS_SPEC_PATH:
if (gluten_read(NULL, g, &p, ns->id, ns->size) == -1)
return -1;
- snprintf(c->ns[i].path, PATH_MAX , "%s", p);
+ snprintf(c->ns[i].path, PATH_MAX, "%s", p);
break;
}
}
@@ -137,7 +136,7 @@ static int set_namespaces(struct arg_clone *c)
int fd;
for (i = 0; i < sizeof(enum ns_type); i++) {
- if(strcmp(c->ns[i].path, "") == 0)
+ if (strcmp(c->ns[i].path, "") == 0)
continue;
if ((fd = open(c->ns[i].path, O_CLOEXEC)) < 0)
ret_err(-1, "open for file %s", c->ns[i].path);
@@ -160,7 +159,7 @@ static int execute_syscall(void *args)
c->args[4], c->args[5]);
c->err = errno;
if (c->ret < 0) {
- perror("syscall");
+ perror(" syscall");
exit(EXIT_FAILURE);
}
exit(0);
@@ -207,10 +206,9 @@ int do_call(struct arg_clone *c)
/* Create a process that will be moved to the namespace */
child = clone(execute_syscall, stack + sizeof(stack),
- CLONE_FILES | CLONE_VM | SIGCHLD, (void *)c);
+ CLONE_FILES | CLONE_VM | CLONE_VFORK | SIGCHLD, (void *)c);
if (child == -1)
ret_err(-1, "clone");
- wait(NULL);
return 0;
}
@@ -225,13 +223,16 @@ int op_call(const struct seccomp_notif *req, int notifier, struct gluten *g,
resp.flags = 0;
resp.error = 0;
- prepare_arg_clone(req, g, op, &c);
+ if (prepare_arg_clone(req, g, op, &c) == -1)
+ return -1;
+ debug(" op_call: execute syscall nr=%ld", c.nr);
if (do_call(&c) == -1) {
resp.error = -1;
if (send_target(&resp, notifier) == -1)
return -1;
}
if (c.err != 0) {
+ err(" failed executing call: %s", strerror(c.err));
resp.error = -1;
if (send_target(&resp, notifier) == -1)
return -1;
diff --git a/operations.h b/operations.h
index b1d0ac2..d942ffa 100644
--- a/operations.h
+++ b/operations.h
@@ -13,7 +13,6 @@
#include "common/util.h"
#define STACK_SIZE (1024 * 1024 / 8)
-#define NS_NUM (sizeof(enum ns_type))
#define HANDLE_OP(code, call, type) \
case code: \
do { \
@@ -34,7 +33,7 @@ struct ns_path {
struct arg_clone {
long nr;
void *args[6];
- struct ns_path ns[sizeof(enum ns_type)];
+ struct ns_path ns[NS_NUM];
long ret;
int err;
};
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 */