Hi!
> 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);

Passing random variable to the write is little confusing. I would rather
do something as:

write(t->pipefd[1], "", 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);

Here as well.

> +             wait4child(t->child_pid);
> +             free(t->child_stack);
> +             close(t->fd);
> +             close(t->pipefd[0]);
> +             close(t->pipefd[1]);
> +     }
>  }

The rest of the code is OK.

-- 
Cyril Hrubis
[email protected]

------------------------------------------------------------------------------
Try New Relic Now & We'll Send You this Cool Shirt
New Relic is the only SaaS-based application performance monitoring service 
that delivers powerful full stack analytics. Optimize and monitor your
browser, app, & servers with just a few lines of code. Try New Relic
and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_apr
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to