This adds user type namespaces to errno test. Noteworthy difference is in testcase 4, because re-entering this type of namespace is not allowed. Test spawns a child, which will have different user ID than parent calling setns().
CLONE_NEWUSER flag will be used in test only if kernel is compiled with CONFIG_USER_NS=y and provides /proc/<pid>/ns/user. Signed-off-by: Jan Stancek <[email protected]> --- testcases/kernel/syscalls/setns/setns.h | 3 + testcases/kernel/syscalls/setns/setns01.c | 77 ++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/testcases/kernel/syscalls/setns/setns.h b/testcases/kernel/syscalls/setns/setns.h index 23bdb2e..df64013 100644 --- a/testcases/kernel/syscalls/setns/setns.h +++ b/testcases/kernel/syscalls/setns/setns.h @@ -76,6 +76,9 @@ static void init_available_ns(void) #if defined(CLONE_NEWUTS) init_ns_type(CLONE_NEWUTS, "uts"); #endif +#if defined(CLONE_NEWUSER) + init_ns_type(CLONE_NEWUSER, "user"); +#endif } static void close_ns_fds(void) diff --git a/testcases/kernel/syscalls/setns/setns01.c b/testcases/kernel/syscalls/setns/setns01.c index 74525b9..179f574 100644 --- a/testcases/kernel/syscalls/setns/setns01.c +++ b/testcases/kernel/syscalls/setns/setns01.c @@ -28,6 +28,7 @@ #include <sys/stat.h> #include <sys/syscall.h> #include <sys/types.h> +#include <sys/wait.h> #include <errno.h> #include <sched.h> #include <pwd.h> @@ -42,6 +43,7 @@ char *TCID = "setns01"; #if defined(__NR_setns) #include "setns.h" +#define CHILD_STACK_SIZE (1024*1024) struct testcase_t { const char *msg; @@ -50,6 +52,9 @@ struct testcase_t { int exp_ret; int exp_errno; int skip; + int child_pid; + void *child_stack; + int pipefd[2]; void (*setup) (struct testcase_t *, int i); void (*cleanup) (struct testcase_t *); }; @@ -105,6 +110,17 @@ static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); static const char nobody_uid[] = "nobody"; static struct passwd *ltpuser; +static void wait4child(int child_pid) +{ + int status; + if (waitpid(child_pid, &status, 0) == -1) + tst_brkm(TBROK|TERRNO, cleanup, "waitpid"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_resm(TFAIL, "child returns %d", status); + else + tst_resm(TPASS, "child finished succesfully"); +} + static void setup0(struct testcase_t *t, int i) { t->ns_type = ns_types[i]; @@ -140,19 +156,76 @@ static void setup3(struct testcase_t *t, int i) t->ns_type = ns_types[(i+1) % ns_total]; } +static int do_child04(void *arg) +{ + int dummy; + struct testcase_t *t = (struct testcase_t *) arg; + + read(t->pipefd[0], &dummy, 1); + return 0; +} + static void setup4(struct testcase_t *t, int i) { - if (seteuid(ltpuser->pw_uid) == -1) - tst_brkm(TBROK | TERRNO, NULL, "seteuid failed"); + int tmp, ns_user_fd; t->fd = ns_fds[i]; t->ns_type = ns_types[i]; + t->child_stack = NULL; + t->child_pid = 0; + +#if defined(CLONE_NEWUSER) + /* re-entering same user ns is not allowed, we need new one */ + ns_user_fd = get_ns_fd(getpid(), "user"); + if (t->ns_type == CLONE_NEWUSER && ns_user_fd != -1) { + t->child_stack = malloc(CHILD_STACK_SIZE); + if (t->child_stack == NULL) + tst_brkm(TBROK, cleanup, "Cannot allocate stack"); + + if (pipe(t->pipefd) == -1) + tst_brkm(TBROK|TERRNO, cleanup, "pipe"); + + tmp = ltp_clone(SIGCHLD|CLONE_NEWUSER, do_child04, t, + CHILD_STACK_SIZE, t->child_stack); + if (tmp == -1) + tst_brkm(TBROK|TERRNO, cleanup, "ltp_clone"); + t->child_pid = tmp; + + t->fd = get_ns_fd(t->child_pid, "user"); + tst_resm(TINFO, "child's ns/user fd %d", t->fd); + if (t->fd == -1) { + write(t->pipefd[1], &tmp, 1); + wait4child(t->child_pid); + tst_brkm(TBROK, cleanup, "could not open child's" + "/proc/pid/ns/user"); + } + } + close(ns_user_fd); +#endif + if (seteuid(ltpuser->pw_uid) == -1) { + if (t->child_pid) { + tmp = errno; + write(t->pipefd[1], &tmp, 1); + wait4child(t->child_pid); + errno = tmp; + } + tst_brkm(TBROK | TERRNO, cleanup, "seteuid failed"); + } } static void cleanup4(struct testcase_t *t) { if (seteuid(0) == -1) tst_brkm(TBROK | TERRNO, NULL, "seteuid restore failed"); + if (t->child_pid) { + /* signal child to exit */ + write(t->pipefd[1], t, 1); + wait4child(t->child_pid); + free(t->child_stack); + close(t->fd); + close(t->pipefd[0]); + close(t->pipefd[1]); + } } static void test_setns(struct testcase_t *t) -- 1.7.1 ------------------------------------------------------------------------------ Precog is a next-generation analytics platform capable of advanced analytics on semi-structured data. The platform includes APIs for building apps and a phenomenal toolset for data science. Developers can use our toolset for easy data analysis & visualization. Get a free account! http://www2.precog.com/precogplatform/slashdotnewsletter _______________________________________________ Ltp-list mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ltp-list
