CernVM-FS  2.13.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
namespace.cc
Go to the documentation of this file.
1 
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"))
48  result |= kNsFeaturePid;
49  const int fd = open("/proc/sys/kernel/unprivileged_userns_clone", O_RDONLY);
50  if (fd < 0)
51  return result;
52  result |= kNsFeatureUserAvailable;
53  char enabled = 0;
54  SafeRead(fd, &enabled, 1);
55  close(fd);
56  return (enabled != '1') ? result : (result | kNsFeatureUserEnabled);
57 #endif
58 }
59 
60 
61 NamespaceFailures CreateUserNamespace(uid_t map_uid_to, gid_t map_gid_to) {
62 #ifdef CVMFS_HAS_UNSHARE
63  const std::string uid_str = StringifyInt(geteuid());
64  const std::string gid_str = StringifyInt(getegid());
65 
66  const int rvi = unshare(CLONE_NEWUSER);
67  if (rvi != 0)
68  return kFailNsUnshare;
69 
70  std::string uid_map = StringifyInt(map_uid_to) + " " + uid_str + " 1";
71  std::string gid_map = StringifyInt(map_gid_to) + " " + gid_str + " 1";
72 
73  int fd;
74  ssize_t nbytes;
75  fd = open("/proc/self/setgroups", O_WRONLY);
76  if (fd < 0)
77  return kFailNsSetgroupsOpen;
78  nbytes = write(fd, "deny", 4);
79  close(fd);
80  if (nbytes != 4)
81  return kFailNsSetgroupsWrite;
82 
83  fd = open("/proc/self/uid_map", O_WRONLY);
84  if (fd < 0)
85  return kFailNsMapUidOpen;
86  nbytes = write(fd, uid_map.data(), uid_map.length());
87  close(fd);
88  if (nbytes != static_cast<ssize_t>(uid_map.length()))
89  return kFailNsMapUidWrite;
90 
91  fd = open("/proc/self/gid_map", O_WRONLY);
92  if (fd < 0)
93  return kFailNsMapGidOpen;
94  nbytes = write(fd, gid_map.data(), gid_map.length());
95  close(fd);
96  if (nbytes != static_cast<ssize_t>(gid_map.length()))
97  return kFailNsMapGidWrite;
98 
99  return kFailNsOk;
100 #else
101  return kFailNsUnsuppored;
102 #endif
103 }
104 
105 
106 bool BindMount(const std::string &from, const std::string &to) {
107 #ifdef __APPLE__
108  return false;
109 #else
110  const int rvi = mount(from.c_str(), to.c_str(), "", MS_BIND | MS_REC, NULL);
111  return rvi == 0;
112 #endif
113 }
114 
115 
116 bool ProcMount(const std::string &to) {
117 #ifdef __APPLE__
118  return false;
119 #else
120  const int rvi = mount("proc", to.c_str(), "proc", 0, NULL);
121  return rvi == 0;
122 #endif
123 }
124 
125 
127 #ifdef CVMFS_HAS_UNSHARE
128  const std::string cwd = GetCurrentWorkingDirectory();
129 
130  int rvi = unshare(CLONE_NEWNS);
131  if (rvi != 0)
132  return false;
133 
134  rvi = chdir(cwd.c_str());
135  return rvi == 0;
136 #else
137  return false;
138 #endif
139 }
140 
141 
142 #ifdef CVMFS_HAS_UNSHARE
143 namespace {
144 
145 static void Reaper(int /*sig*/, siginfo_t * /*siginfo*/, void * /*context*/) {
146  while (true) {
147  const pid_t retval = waitpid(-1, NULL, WNOHANG);
148  if (retval <= 0)
149  return;
150  }
151 }
152 
153 } // anonymous namespace
154 #endif
155 
156 
162 bool CreatePidNamespace(int *fd_parent) {
163 #ifdef CVMFS_HAS_UNSHARE
164  int rvi = unshare(CLONE_NEWPID);
165  if (rvi != 0)
166  return false;
167 
168  int pipe_parent[2];
169  MakePipe(pipe_parent);
170 
171  int max_fd;
172  int status;
173  pid_t pid = fork();
174  switch (pid) {
175  case -1:
176  abort();
177  case 0:
178  // New init process
179  break;
180  default:
181  // Parent, wait for the namespace to exit
182 
183  // Close all file descriptors
184  max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
185  for (int fd = 0; fd < max_fd; fd++) {
186  if (fd != pipe_parent[1])
187  close(fd);
188  }
189 
190  pid_t parent_pid = getpid();
191  SafeWrite(pipe_parent[1], &parent_pid, sizeof(parent_pid));
192  SafeWrite(pipe_parent[1], &pid, sizeof(pid));
193 
194  rvi = waitpid(pid, &status, 0);
195  if (rvi >= 0) {
196  if (WIFEXITED(status))
197  exit(WEXITSTATUS(status));
198  }
199  exit(127);
200  }
201  close(pipe_parent[1]);
202  if (fd_parent != NULL)
203  *fd_parent = pipe_parent[0];
204 
205  // Note: only signals for which signal handlers are established can be sent
206  // by other processes of this pid namespace to the init process
207  struct sigaction sa;
208  memset(&sa, 0, sizeof(sa));
209  sa.sa_sigaction = Reaper;
210  sa.sa_flags = SA_SIGINFO;
211  sigfillset(&sa.sa_mask);
212  rvi = sigaction(SIGCHLD, &sa, NULL);
213  assert(rvi == 0);
214 
215  rvi = mount("", "/proc", "proc", 0, NULL);
216  return rvi == 0;
217 #else
218  return false;
219 #endif
220 }
bool CreateMountNamespace()
Definition: namespace.cc:126
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:2036
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:833
#define MS_REC
Definition: namespace.cc:29
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:2094
static void Reaper(int, siginfo_t *, void *)
Definition: namespace.cc:145
NamespaceFailures CreateUserNamespace(uid_t map_uid_to, gid_t map_gid_to)
Definition: namespace.cc:61
#define CLONE_NEWPID
Definition: namespace.cc:26
bool ProcMount(const std::string &to)
Definition: namespace.cc:116
string StringifyInt(const int64_t value)
Definition: string.cc:77
const int kNsFeaturePid
Definition: namespace.h:18
int CheckNamespaceFeatures()
Definition: namespace.cc:42
bool CreatePidNamespace(int *fd_parent)
Definition: namespace.cc:162
bool BindMount(const std::string &from, const std::string &to)
Definition: namespace.cc:106
#define CLONE_NEWUSER
Definition: namespace.cc:23
std::string GetCurrentWorkingDirectory()
Definition: posix.cc:1068
NamespaceFailures
Definition: namespace.h:22