CernVM-FS  2.12.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 #ifdef CVMFS_HAS_UNSHARE
136 namespace {
137 
138 static void Reaper(int /*sig*/, siginfo_t * /*siginfo*/, void * /*context*/) {
139  while (true) {
140  pid_t retval = waitpid(-1, NULL, WNOHANG);
141  if (retval <= 0)
142  return;
143  }
144 }
145 
146 } // anonymous namespace
147 #endif
148 
149 
155 bool CreatePidNamespace(int *fd_parent) {
156 #ifdef CVMFS_HAS_UNSHARE
157  int rvi = unshare(CLONE_NEWPID);
158  if (rvi != 0) return false;
159 
160  int pipe_parent[2];
161  MakePipe(pipe_parent);
162 
163  int max_fd;
164  int status;
165  pid_t pid = fork();
166  switch (pid) {
167  case -1:
168  abort();
169  case 0:
170  // New init process
171  break;
172  default:
173  // Parent, wait for the namespace to exit
174 
175  // Close all file descriptors
176  max_fd = static_cast<int>(sysconf(_SC_OPEN_MAX));
177  for (int fd = 0; fd < max_fd; fd++) {
178  if (fd != pipe_parent[1])
179  close(fd);
180  }
181 
182  pid_t parent_pid = getpid();
183  SafeWrite(pipe_parent[1], &parent_pid, sizeof(parent_pid));
184  SafeWrite(pipe_parent[1], &pid, sizeof(pid));
185 
186  rvi = waitpid(pid, &status, 0);
187  if (rvi >= 0) {
188  if (WIFEXITED(status))
189  exit(WEXITSTATUS(status));
190  }
191  exit(127);
192  }
193  close(pipe_parent[1]);
194  if (fd_parent != NULL)
195  *fd_parent = pipe_parent[0];
196 
197  // Note: only signals for which signal handlers are established can be sent
198  // by other processes of this pid namespace to the init process
199  struct sigaction sa;
200  memset(&sa, 0, sizeof(sa));
201  sa.sa_sigaction = Reaper;
202  sa.sa_flags = SA_SIGINFO;
203  sigfillset(&sa.sa_mask);
204  rvi = sigaction(SIGCHLD, &sa, NULL);
205  assert(rvi == 0);
206 
207  rvi = mount("", "/proc", "proc", 0, NULL);
208  return rvi == 0;
209 #else
210  return false;
211 #endif
212 }
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:1986
assert((mem||(size==0))&&"Out Of Memory")
void MakePipe(int pipe_fd[2])
Definition: posix.cc:492
bool SymlinkExists(const std::string &path)
Definition: posix.cc:823
#define MS_REC
Definition: namespace.cc:29
ssize_t SafeRead(int fd, void *buf, size_t nbyte)
Definition: posix.cc:2045
static void Reaper(int, siginfo_t *, void *)
Definition: namespace.cc:138
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:155
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:1060
NamespaceFailures
Definition: namespace.h:22