| 269 | |
| 270 | |
| 271 | Try<pid_t> clone( |
| 272 | pid_t target, |
| 273 | int nstypes, |
| 274 | const lambda::function<int()>& f, |
| 275 | int flags) |
| 276 | { |
| 277 | // NOTE: the order in which we 'setns' is significant, so we use an |
| 278 | // array here rather than something like a map. |
| 279 | // |
| 280 | // The user namespace needs to be entered first if we need to |
| 281 | // increase the privilege and last if we want to decrease the |
| 282 | // privilege. Said another way, entering the user namespace first |
| 283 | // gives an unprivileged user the potential to enter the other |
| 284 | // namespaces. |
| 285 | const size_t NAMESPACES = 7; |
| 286 | const struct |
| 287 | { |
| 288 | int nstype; |
| 289 | string name; |
| 290 | } namespaces[NAMESPACES] = { |
| 291 | {CLONE_NEWUSER, "user"}, |
| 292 | {CLONE_NEWCGROUP, "cgroup"}, |
| 293 | {CLONE_NEWIPC, "ipc"}, |
| 294 | {CLONE_NEWUTS, "uts"}, |
| 295 | {CLONE_NEWNET, "net"}, |
| 296 | {CLONE_NEWPID, "pid"}, |
| 297 | {CLONE_NEWNS, "mnt"} |
| 298 | }; |
| 299 | |
| 300 | // Since we assume below that the parent can deallocate the stack |
| 301 | // after cloning the children, the caller must not pass CLONE_VM. |
| 302 | // That would cause the both processes to share their address space |
| 303 | // so deallocating the stack in the parent would affect the child. |
| 304 | CHECK_EQ(0, flags & CLONE_VM); |
| 305 | |
| 306 | // Support for user namespaces in all filesystems is incomplete |
| 307 | // until version 3.12 (see 'Availability' in man page of |
| 308 | // 'user_namespaces'), so for now we don't support entering them. |
| 309 | // |
| 310 | // TODO(benh): Support user namespaces if the current system can |
| 311 | // support it, e.g., check the kernel version number or try and do a |
| 312 | // clone with CLONE_NEWUSER to see if it works. NOTE: before we can |
| 313 | // fully support user namespaces, however, we must take care to |
| 314 | // either enter the user namespace first or last. We'll want to |
| 315 | // enter it first if we need to increase the privilege and last if |
| 316 | // we want to decrease the privilege. Currently nsenter.c from |
| 317 | // utils-linux does this via doing two passes to make sure we either |
| 318 | // enter first or last. We'll need to do something similar here once |
| 319 | // we support user namespaces as well. |
| 320 | if (nstypes & CLONE_NEWUSER) { |
| 321 | return Error("User namespaces are not supported"); |
| 322 | } |
| 323 | |
| 324 | // File descriptors keyed by the (parent) namespace we are entering. |
| 325 | hashmap<int, int> fds = {}; |
| 326 | |
| 327 | // NOTE: we do all of this ahead of time so we can be async signal |
| 328 | // safe after calling fork below. |