LCOV - code coverage report
Current view: top level - basic - namespace-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 8 84 9.5 %
Date: 2019-08-23 13:36:53 Functions: 1 3 33.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 5 110 4.5 %

           Branch data     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                 :         20 : 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         [ -  + ]:         20 :         if (fstatfs(fd, &s) < 0)
     138                 :          0 :                 return -errno;
     139                 :            : 
     140         [ +  + ]:         20 :         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         [ -  + ]:         12 :                 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                 :         12 :                 return 0; /* No! */
     159                 :            :         }
     160                 :            : 
     161                 :          8 :         r = ioctl(fd, NS_GET_NSTYPE);
     162         [ -  + ]:          8 :         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                 :          8 :         return r == CLONE_NEWNET;
     170                 :            : }

Generated by: LCOV version 1.14