LCOV - code coverage report
Current view: top level - basic - namespace-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 8 84 9.5 %
Date: 2019-08-22 15:41:25 Functions: 1 3 33.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <fcntl.h>
       4             : #include <linux/magic.h>
       5             : 
       6             : #include "fd-util.h"
       7             : #include "missing.h"
       8             : #include "namespace-util.h"
       9             : #include "process-util.h"
      10             : #include "stat-util.h"
      11             : #include "user-util.h"
      12             : 
      13           0 : int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
      14           0 :         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
      15           0 :         int rfd = -1;
      16             : 
      17           0 :         assert(pid >= 0);
      18             : 
      19           0 :         if (mntns_fd) {
      20             :                 const char *mntns;
      21             : 
      22           0 :                 mntns = procfs_file_alloca(pid, "ns/mnt");
      23           0 :                 mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
      24           0 :                 if (mntnsfd < 0)
      25           0 :                         return -errno;
      26             :         }
      27             : 
      28           0 :         if (pidns_fd) {
      29             :                 const char *pidns;
      30             : 
      31           0 :                 pidns = procfs_file_alloca(pid, "ns/pid");
      32           0 :                 pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
      33           0 :                 if (pidnsfd < 0)
      34           0 :                         return -errno;
      35             :         }
      36             : 
      37           0 :         if (netns_fd) {
      38             :                 const char *netns;
      39             : 
      40           0 :                 netns = procfs_file_alloca(pid, "ns/net");
      41           0 :                 netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
      42           0 :                 if (netnsfd < 0)
      43           0 :                         return -errno;
      44             :         }
      45             : 
      46           0 :         if (userns_fd) {
      47             :                 const char *userns;
      48             : 
      49           0 :                 userns = procfs_file_alloca(pid, "ns/user");
      50           0 :                 usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
      51           0 :                 if (usernsfd < 0 && errno != ENOENT)
      52           0 :                         return -errno;
      53             :         }
      54             : 
      55           0 :         if (root_fd) {
      56             :                 const char *root;
      57             : 
      58           0 :                 root = procfs_file_alloca(pid, "root");
      59           0 :                 rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
      60           0 :                 if (rfd < 0)
      61           0 :                         return -errno;
      62             :         }
      63             : 
      64           0 :         if (pidns_fd)
      65           0 :                 *pidns_fd = TAKE_FD(pidnsfd);
      66             : 
      67           0 :         if (mntns_fd)
      68           0 :                 *mntns_fd = TAKE_FD(mntnsfd);
      69             : 
      70           0 :         if (netns_fd)
      71           0 :                 *netns_fd = TAKE_FD(netnsfd);
      72             : 
      73           0 :         if (userns_fd)
      74           0 :                 *userns_fd = TAKE_FD(usernsfd);
      75             : 
      76           0 :         if (root_fd)
      77           0 :                 *root_fd = TAKE_FD(rfd);
      78             : 
      79           0 :         return 0;
      80             : }
      81             : 
      82           0 : int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
      83           0 :         if (userns_fd >= 0) {
      84             :                 /* Can't setns to your own userns, since then you could
      85             :                  * escalate from non-root to root in your own namespace, so
      86             :                  * check if namespaces equal before attempting to enter. */
      87           0 :                 _cleanup_free_ char *userns_fd_path = NULL;
      88             :                 int r;
      89           0 :                 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
      90           0 :                         return -ENOMEM;
      91             : 
      92           0 :                 r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
      93           0 :                 if (r < 0)
      94           0 :                         return r;
      95           0 :                 if (r)
      96           0 :                         userns_fd = -1;
      97             :         }
      98             : 
      99           0 :         if (pidns_fd >= 0)
     100           0 :                 if (setns(pidns_fd, CLONE_NEWPID) < 0)
     101           0 :                         return -errno;
     102             : 
     103           0 :         if (mntns_fd >= 0)
     104           0 :                 if (setns(mntns_fd, CLONE_NEWNS) < 0)
     105           0 :                         return -errno;
     106             : 
     107           0 :         if (netns_fd >= 0)
     108           0 :                 if (setns(netns_fd, CLONE_NEWNET) < 0)
     109           0 :                         return -errno;
     110             : 
     111           0 :         if (userns_fd >= 0)
     112           0 :                 if (setns(userns_fd, CLONE_NEWUSER) < 0)
     113           0 :                         return -errno;
     114             : 
     115           0 :         if (root_fd >= 0) {
     116           0 :                 if (fchdir(root_fd) < 0)
     117           0 :                         return -errno;
     118             : 
     119           0 :                 if (chroot(".") < 0)
     120           0 :                         return -errno;
     121             :         }
     122             : 
     123           0 :         return reset_uid_gid();
     124             : }
     125             : 
     126           5 : int fd_is_network_ns(int fd) {
     127             :         struct statfs s;
     128             :         int r;
     129             : 
     130             :         /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
     131             :          * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
     132             :          * this somewhat nicely.
     133             :          *
     134             :          * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
     135             :          * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
     136             : 
     137           5 :         if (fstatfs(fd, &s) < 0)
     138           0 :                 return -errno;
     139             : 
     140           5 :         if (!is_fs_type(&s, NSFS_MAGIC)) {
     141             :                 /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
     142             :                  * instead. Handle that in a somewhat smart way. */
     143             : 
     144           3 :                 if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
     145             :                         struct statfs t;
     146             : 
     147             :                         /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
     148             :                          * passed fd might refer to a network namespace, but we can't know for sure. In that case,
     149             :                          * return a recognizable error. */
     150             : 
     151           0 :                         if (statfs("/proc/self/ns/net", &t) < 0)
     152           0 :                                 return -errno;
     153             : 
     154           0 :                         if (s.f_type == t.f_type)
     155           0 :                                 return -EUCLEAN; /* It's possible, we simply don't know */
     156             :                 }
     157             : 
     158           3 :                 return 0; /* No! */
     159             :         }
     160             : 
     161           2 :         r = ioctl(fd, NS_GET_NSTYPE);
     162           2 :         if (r < 0) {
     163           0 :                 if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
     164           0 :                         return -EUCLEAN;
     165             : 
     166           0 :                 return -errno;
     167             :         }
     168             : 
     169           2 :         return r == CLONE_NEWNET;
     170             : }

Generated by: LCOV version 1.14