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