Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: sandbox/linux/services/namespace_sandbox.cc

Issue 881733002: Add namespace sandbox class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Nested namespace sandboxes aren't supported. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sandbox/linux/services/namespace_sandbox.h"
6
7 #include <sched.h>
8 #include <stdlib.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <string>
14 #include <utility>
15
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/environment.h"
19 #include "base/files/scoped_file.h"
20 #include "base/logging.h"
21 #include "base/posix/eintr_wrapper.h"
22 #include "base/process/launch.h"
23 #include "base/process/process.h"
24 #include "base/strings/stringprintf.h"
25 #include "sandbox/linux/services/namespace_utils.h"
26
27 namespace sandbox {
28
29 namespace {
30 const char kPipeValue = '\xcc';
31
32 class BlockOnPipeDelegate : public base::LaunchOptions::PreExecDelegate {
33 public:
34 explicit BlockOnPipeDelegate(int fd) : fd_(fd) {}
35
36 ~BlockOnPipeDelegate() override {}
37
38 void RunAsyncSafe() override {
39 char c;
40 RAW_CHECK(HANDLE_EINTR(read(fd_, &c, 1)) == 1);
41 RAW_CHECK(IGNORE_EINTR(close(fd_)) == 0);
42 RAW_CHECK(c == kPipeValue);
43 }
44
45 private:
46 int fd_;
47 DISALLOW_COPY_AND_ASSIGN(BlockOnPipeDelegate);
48 };
49
50 void SetEnvironForNamespaceType(base::EnvironmentMap* environ,
51 base::NativeEnvironmentString env_var,
52 bool value) {
53 // An empty string causes the env var to be unset in the child process.
54 (*environ)[env_var] = value ? "1" : "";
55 }
56
57 const char kSandboxUSERNSEnvironmentVarName[] = "SBX_USER_NS";
58 const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS";
59 const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
60
61 } // namespace
62
63 NamespaceSandbox::NamespaceSandbox() : launch_called_(false) {
64 }
65
66 NamespaceSandbox::~NamespaceSandbox() {
67 }
68
69 void NamespaceSandbox::AddFdMapping(int from_fd, int to_fd) {
70 fds_to_remap_.push_back(std::make_pair(from_fd, to_fd));
71 }
72
73 base::Process NamespaceSandbox::Launch(const base::CommandLine& cmdline) {
74 CHECK(!launch_called_) << "NamespaceSandbox may only be used once.";
75 launch_called_ = true;
76
77 int clone_flags = 0;
78 int ns_types[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
79 for (const int ns_type : ns_types) {
80 if (NamespaceUtils::KernelSupportsUnprivilegedNamespace(ns_type)) {
81 clone_flags |= ns_type;
82 }
83 }
84 CHECK(clone_flags & CLONE_NEWUSER);
85
86 int fds[2];
87 PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
88 PCHECK(shutdown(fds[0], SHUT_WR) == 0);
89 PCHECK(shutdown(fds[1], SHUT_RD) == 0);
90 base::ScopedFD read_fd(fds[0]);
91 base::ScopedFD write_fd(fds[1]);
92
93 fds_to_remap_.push_back(std::make_pair(read_fd.get(), read_fd.get()));
94
95 BlockOnPipeDelegate block_on_pipe_delegate(read_fd.get());
96 launch_options_.pre_exec_delegate = &block_on_pipe_delegate;
97 launch_options_.fds_to_remap = &fds_to_remap_;
98 launch_options_.clone_flags = clone_flags;
99
100 const std::pair<int, const char*> clone_flag_environ[] = {
101 std::make_pair(CLONE_NEWUSER, kSandboxUSERNSEnvironmentVarName),
102 std::make_pair(CLONE_NEWPID, kSandboxPIDNSEnvironmentVarName),
103 std::make_pair(CLONE_NEWNET, kSandboxNETNSEnvironmentVarName),
104 };
105
106 base::EnvironmentMap* environ = &launch_options_.environ;
107 for (const auto& entry : clone_flag_environ) {
108 const int flag = entry.first;
109 const char* environ_name = entry.second;
110 SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag);
111 }
112
113 base::Process process = base::LaunchProcess(cmdline, launch_options_);
114 read_fd.reset();
115
116 if (process.IsValid()) {
117 WriteUidGidMapAndUnblockProcess(process.Pid(), write_fd.Pass());
118 }
119
120 return process.Pass();
121 }
122
123 void NamespaceSandbox::WriteUidGidMapAndUnblockProcess(pid_t pid,
124 base::ScopedFD fd) {
125 const std::string uid_map_path = base::StringPrintf("/proc/%d/uid_map", pid);
126 const std::string gid_map_path = base::StringPrintf("/proc/%d/gid_map", pid);
127 CHECK(NamespaceUtils::WriteToIdMapFile(uid_map_path.c_str(), getuid()));
128 CHECK(NamespaceUtils::WriteToIdMapFile(gid_map_path.c_str(), getgid()));
129 PCHECK(HANDLE_EINTR(send(fd.get(), &kPipeValue, 1, MSG_NOSIGNAL)) == 1);
130 }
131
132 bool NamespaceSandbox::InNewUserNamespace() {
133 return getenv(kSandboxUSERNSEnvironmentVarName) != nullptr;
134 }
135
136 bool NamespaceSandbox::InNewPidNamespace() {
137 return getenv(kSandboxPIDNSEnvironmentVarName) != nullptr;
138 }
139
140 bool NamespaceSandbox::InNewNetNamespace() {
141 return getenv(kSandboxNETNSEnvironmentVarName) != nullptr;
142 }
143
144 } // namespace sandbox
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698