CernVM-FS  2.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
namespace.cc
Go to the documentation of this file.
1 
5 #include "cvmfs_config.h"
6 #include "namespace.h"
7 
8 #include <fcntl.h>
9 #include <signal.h>
10 #ifndef __APPLE__
11 #include <sched.h>
12 #include <sys/mount.h>
13 #endif
14 #include <sys/wait.h>
15 
16 #include <cstring>
17 
18 #include "util/posix.h"
19 #include "util/string.h"
20 
21 // Might otherwise not compile on older Linux kernels or glibc versions
22 #ifndef CLONE_NEWUSER
23 #define CLONE_NEWUSER 0x10000000
24 #endif
25 #ifndef CLONE_NEWPID
26 #define CLONE_NEWPID 0x20000000
27 #endif
28 #ifndef MS_REC
29 #define MS_REC 0x4000
30 #endif
31 
32 #ifndef __APPLE__
33 #define CVMFS_HAS_UNSHARE 1
34 #ifdef __GLIBC_MINOR__
35 #if __GLIBC_MINOR__ < 4
36 #undef CVMFS_HAS_UNSHARE
37 #endif
38 #endif
39 #endif
40 
41 
43 #ifdef __APPLE__
44  return 0;
45 #else
46  int result = kNsFeatureMount; // available since kernel 2.4
47  if (SymlinkExists("/proc/self/ns/pid")) result |= kNsFeaturePid;
48  int fd = open("/proc/sys/kernel/unprivileged_userns_clone", O_RDONLY);
49  if (fd < 0)
50  return result;
51  result |= kNsFeatureUserAvailable;
52  char enabled = 0;
53  SafeRead(fd, &enabled, 1);
54  close(fd);
55  return (enabled != '1') ? result : (result | kNsFeatureUserEnabled);
56 #endif
57 }
58 
59 
60 NamespaceFailures CreateUserNamespace(uid_t map_uid_to, gid_t map_gid_to) {
61 #ifdef CVMFS_HAS_UNSHARE
62  std::string uid_str = StringifyInt(geteuid());
63  std::string gid_str = StringifyInt(getegid());
64 
65  int rvi = unshare(CLONE_NEWUSER);
66  if (rvi != 0) return kFailNsUnshare;
67 
68  std::string uid_map = StringifyInt(map_uid_to) + " " + uid_str + " 1";
69  std::string gid_map = StringifyInt(map_gid_to) + " " + gid_str + " 1";
70 
71  int fd;
72  ssize_t nbytes;
73  fd = open("/proc/self/setgroups", O_WRONLY);
74  if (fd < 0) return kFailNsSetgroupsOpen;
75  nbytes = write(fd, "deny", 4);
76  close(fd);
77  if (nbytes != 4) return kFailNsSetgroupsWrite;
78 
79  fd = open("/proc/self/uid_map", O_WRONLY);
80  if (fd < 0) return kFailNsMapUidOpen;
81  nbytes = write(fd, uid_map.data(), uid_map.length());
82  close(fd);
83  if (nbytes != static_cast<ssize_t>(uid_map.length()))
84  return kFailNsMapUidWrite;
85 
86  fd = open("/proc/self/gid_map", O_WRONLY);
87  if (fd < 0) return kFailNsMapGidOpen;
88  nbytes = write(fd, gid_map.data(), gid_map.length());
89  close(fd);
90  if (nbytes != static_cast<ssize_t>(gid_map.length()))
91  return kFailNsMapGidWrite;
92 
93  return kFailNsOk;
94 #else
95  return kFailNsUnsuppored;
96 #endif
97 }
98 
99 
100 bool BindMount(const std::string &from, const std::string &to) {
101 #ifdef __APPLE__
102  return false;
103 #else
104  int rvi = mount(from.c_str(), to.c_str(), "", MS_BIND | MS_REC, NULL);
105  return rvi == 0;
106 #endif
107 }
108 
109 
110 bool ProcMount(const std::string &to) {
111 #ifdef __APPLE__
112  return false;
113 #else
114  int rvi = mount("proc", to.c_str(), "proc", 0, NULL);
115  return rvi == 0;
116 #endif
117 }
118 
119 
121 #ifdef CVMFS_HAS_UNSHARE
122  std::string cwd = GetCurrentWorkingDirectory();
123 
124  int rvi = unshare(CLONE_NEWNS);
125  if (rvi != 0) return false;
126 
127  rvi = chdir(cwd.c_str());
128  return rvi == 0;
129 #else
130  return false;
131 #endif
132 }
133 
134 
135 namespace {
136 
137 static void Reaper(int /*sig*/, siginfo_t * /*siginfo*/, void * /*context*/) {
138  while (true) {
139  pid_t retval = waitpid(-1, NULL, WNOHANG);
140  if (retval <= 0)
141  return;
142  }
143 }
144 
145 } // anonymous namespace
146 
147 
153 bool CreatePidNamespace(int *fd_parent) {
154 #ifdef CVMFS_HAS_UNSHARE
155  int rvi = unshare(CLONE_NEWPID);
156  if (rvi != 0) return false;
157 
158  int pipe_parent[2];
159  MakePipe(pipe_parent);
160 
161  int max_fd;
162  int status;
163  pid_t pid = fork();
164  switch (pid) {
165  case -1:
166  abort();
167  case 0:
168  // New init process
169  break;
170  default:
171  // Parent, wait for the namespace to exit
172 
173  // Close all file descriptors
174  max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
175  for (int fd = 0; fd < max_fd; fd++) {
176  if (fd != pipe_parent[1])
177  close(fd);
178  }
179 
180  pid_t parent_pid = getpid();
181  SafeWrite(pipe_parent[1], &parent_pid, sizeof(parent_pid));
182  SafeWrite(pipe_parent[1], &pid, sizeof(pid));
183 
184  rvi = waitpid(pid, &status, 0);
185  if (rvi >= 0) {
186  if (WIFEXITED(status))
187  exit(WEXITSTATUS(status));
188  }
189  exit(127);
190  }
191  close(pipe_parent[1]);
192  if (fd_parent != NULL)
193  *fd_parent = pipe_parent[0];
194 
195  // Note: only signals for which signal handlers are established can be sent
196  // by other processes of this pid namespace to the init process
197  struct sigaction sa;
198  memset(&sa, 0, sizeof(sa));
199  sa.sa_sigaction = Reaper;
200  sa.sa_flags = SA_SIGINFO;
201  sigfillset(&sa.sa_mask);
202  rvi = sigaction(SIGCHLD, &sa, NULL);
203  assert(rvi == 0);
204 
205  rvi = mount("", "/proc", "proc", 0, NULL);
206  return rvi == 0;
207 #else
208  return false;
209 #endif
210 }
bool CreateMountNamespace()
Definition: namespace.cc:120
const int kNsFeatureUserAvailable
Definition: namespace.h:19
const int kNsFeatureMount
Definition: namespace.h:17
const int kNsFeatureUserEnabled
Definition: namespace.h:20
bool SafeWrite(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:1890
assert((mem||(size==0))&&"Out Of Memory")
void MakePipe(int pipe_fd[2])
Definition: posix.cc:487
bool SymlinkExists(const std::string &path)
Definition: posix.cc:810
#define MS_REC
Definition: namespace.cc:29
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:1949
static void Reaper(int, siginfo_t *, void *)
Definition: namespace.cc:137
NamespaceFailures CreateUserNamespace(uid_t map_uid_to, gid_t map_gid_to)
Definition: namespace.cc:60
#define CLONE_NEWPID
Definition: namespace.cc:26
bool ProcMount(const std::string &to)
Definition: namespace.cc:110
string StringifyInt(const int64_t value)
Definition: string.cc:78
const int kNsFeaturePid
Definition: namespace.h:18
int CheckNamespaceFeatures()
Definition: namespace.cc:42
bool CreatePidNamespace(int *fd_parent)
Definition: namespace.cc:153
bool BindMount(const std::string &from, const std::string &to)
Definition: namespace.cc:100
#define CLONE_NEWUSER
Definition: namespace.cc:23
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1047
NamespaceFailures
Definition: namespace.h:22