(root)/
strace-6.5/
tests-m32/
ioctl_nsfs.c
       1  /*
       2   * Check decoding of NS_* commands of ioctl syscall.
       3   *
       4   * Copyright (c) 2017 Nikolay Marchuk <marchuk.nikolay.a@gmail.com>
       5   * Copyright (c) 2017-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  
      13  #include <fcntl.h>
      14  #include <sched.h>
      15  #include <stdio.h>
      16  #include <stdlib.h>
      17  #include <sys/ioctl.h>
      18  #include <sys/wait.h>
      19  #include <unistd.h>
      20  #include <linux/nsfs.h>
      21  
      22  #ifndef CLONE_NEWUSER
      23  # define CLONE_NEWUSER 0x10000000
      24  #endif
      25  
      26  static void
      27  test_no_namespace(void)
      28  {
      29  	ioctl(-1, NS_GET_USERNS);
      30  	printf("ioctl(-1, NS_GET_USERNS) = -1 EBADF (%m)\n");
      31  	ioctl(-1, NS_GET_PARENT);
      32  	printf("ioctl(-1, NS_GET_PARENT) = -1 EBADF (%m)\n");
      33  	ioctl(-1, NS_GET_NSTYPE);
      34  	printf("ioctl(-1, NS_GET_NSTYPE) = -1 EBADF (%m)\n");
      35  	ioctl(-1, NS_GET_OWNER_UID, NULL);
      36  	printf("ioctl(-1, NS_GET_OWNER_UID, NULL) = -1 EBADF (%m)\n");
      37  }
      38  
      39  static void
      40  test_clone(pid_t pid)
      41  {
      42  	char path[sizeof("/proc/%d/ns/user") + sizeof(int)*3];
      43  	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
      44  
      45  	int ns_fd = open(path, O_RDONLY);
      46  	if (ns_fd == -1)
      47  		perror_msg_and_skip("open: %s", path);
      48  
      49  	int userns_fd = ioctl(ns_fd, NS_GET_USERNS);
      50  	printf("ioctl(%d, NS_GET_USERNS) = %s\n", ns_fd, sprintrc(userns_fd));
      51  
      52  	int parent_ns_fd = ioctl(userns_fd, NS_GET_PARENT);
      53  	printf("ioctl(%d, NS_GET_PARENT) = %s\n",
      54  	       userns_fd, sprintrc(parent_ns_fd));
      55  
      56  	int nstype = ioctl(userns_fd, NS_GET_NSTYPE);
      57  	if (nstype == -1) {
      58  		printf("ioctl(%d, NS_GET_NSTYPE) = %s\n",
      59  		       userns_fd, sprintrc(nstype));
      60  	} else {
      61  		printf("ioctl(%d, NS_GET_NSTYPE) = %d (CLONE_NEWUSER)\n",
      62  		       userns_fd, nstype);
      63  	}
      64  
      65  	TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, uid);
      66  	int rc = ioctl(userns_fd, NS_GET_OWNER_UID, uid);
      67  	if (rc == -1) {
      68  		printf("ioctl(%d, NS_GET_OWNER_UID, %p) = %s\n",
      69  		       userns_fd, uid, sprintrc(rc));
      70  	} else {
      71  		printf("ioctl(%d, NS_GET_OWNER_UID, [%u]) = %d\n",
      72  		       userns_fd, *uid, rc);
      73  	}
      74  }
      75  
      76  static int
      77  child(void *arg)
      78  {
      79  	int *pipefd = (int *) arg;
      80  	close(pipefd[1]);
      81  	/* Wait for EOF from pipe. */
      82  	if (read(pipefd[0], &pipefd[1], 1))
      83  		perror_msg_and_fail("read");
      84  	return 0;
      85  }
      86  
      87  #ifdef IA64
      88  extern int __clone2(int (*)(void *), void *, size_t, int, void *, ...);
      89  # define do_clone(fn_, stack_, size_, flags_, arg_, ...)	\
      90  	__clone2((fn_), (stack_), (size_), (flags_), (arg_), ## __VA_ARGS__)
      91  #else
      92  # define do_clone(fn_, stack_, size_, flags_, arg_, ...)	\
      93  	clone((fn_), (stack_), (flags_), (arg_), ## __VA_ARGS__)
      94  #endif
      95  
      96  static void
      97  test_user_namespace(void)
      98  {
      99  	int pipefd[2];
     100  	if (pipe(pipefd))
     101  		perror_msg_and_fail("pipe");
     102  
     103  	const unsigned long child_stack_size = get_page_size();
     104  	void *const child_stack =
     105  		tail_alloc(child_stack_size * 2) + child_stack_size;
     106  
     107  	const pid_t pid = do_clone(child, child_stack, child_stack_size,
     108  				   CLONE_NEWUSER | CLONE_UNTRACED | SIGCHLD,
     109  				   pipefd);
     110  	if (pid == -1) {
     111  		perror("clone");
     112  		return;
     113  	}
     114  	close(pipefd[0]);
     115  	test_clone(pid);
     116  	close(pipefd[1]);
     117  
     118  	int status;
     119  	if (wait(&status) != pid) {
     120  		perror_msg_and_fail("wait");
     121  	} else if (status != 0) {
     122  		error_msg_and_fail("unexpected child exit status %d", status);
     123  	}
     124  }
     125  
     126  int
     127  main(void)
     128  {
     129  	test_no_namespace();
     130  	test_user_namespace();
     131  	puts("+++ exited with 0 +++");
     132  	return 0;
     133  }