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

Side by Side Diff: components/nacl/loader/nacl_helper_linux.cc

Issue 196793023: Add seccomp sandbox for non-SFI NaCl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // A mini-zygote specifically for Native Client. 5 // A mini-zygote specifically for Native Client.
6 6
7 #include "components/nacl/loader/nacl_helper_linux.h" 7 #include "components/nacl/loader/nacl_helper_linux.h"
8 8
9 #include <errno.h> 9 #include <errno.h>
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 25 matching lines...) Expand all
36 #include "ipc/ipc_switches.h" 36 #include "ipc/ipc_switches.h"
37 #include "sandbox/linux/services/libc_urandom_override.h" 37 #include "sandbox/linux/services/libc_urandom_override.h"
38 38
39 namespace { 39 namespace {
40 40
41 struct NaClLoaderSystemInfo { 41 struct NaClLoaderSystemInfo {
42 size_t prereserved_sandbox_size; 42 size_t prereserved_sandbox_size;
43 long number_of_cores; 43 long number_of_cores;
44 }; 44 };
45 45
46 // This is a poor man's check on whether we are sandboxed.
47 bool IsSandboxed() {
48 int proc_fd = open("/proc/self/exe", O_RDONLY);
49 if (proc_fd >= 0) {
50 close(proc_fd);
51 return false;
52 }
53 return true;
54 }
55
56 void InitializeSandbox(bool uses_nonsfi) {
57 const bool setuid_sandbox_enabled = IsSandboxed();
58 if (uses_nonsfi) {
59 CHECK(setuid_sandbox_enabled)
60 << "SUID sandbox is mandatory for non-SFI NaCl";
61 }
62 // don't need zygote FD any more
63 if (IGNORE_EINTR(close(kNaClZygoteDescriptor)) != 0)
64 LOG(ERROR) << "close(kNaClZygoteDescriptor) failed.";
65 bool bpf_sandbox_initialized = false;
66 if (uses_nonsfi)
67 bpf_sandbox_initialized = InitializeBPFSandboxForNonSfi();
68 else
69 bpf_sandbox_initialized = InitializeBPFSandbox();
70 if (!bpf_sandbox_initialized) {
71 LOG(ERROR) << "Could not initialize NaCl's second "
72 << "layer sandbox (seccomp-bpf).";
73 // We really depend on seccomp sandbox for non-SFI mode. We do not
74 // run any program without seccomp sandbox.
75 if (uses_nonsfi)
76 _exit(1);
77 }
78 }
79
46 // The child must mimic the behavior of zygote_main_linux.cc on the child 80 // The child must mimic the behavior of zygote_main_linux.cc on the child
47 // side of the fork. See zygote_main_linux.cc:HandleForkRequest from 81 // side of the fork. See zygote_main_linux.cc:HandleForkRequest from
48 // if (!child) { 82 // if (!child) {
49 void BecomeNaClLoader(const std::vector<int>& child_fds, 83 void BecomeNaClLoader(const std::vector<int>& child_fds,
50 const NaClLoaderSystemInfo& system_info) { 84 const NaClLoaderSystemInfo& system_info,
85 bool uses_nonsfi) {
51 VLOG(1) << "NaCl loader: setting up IPC descriptor"; 86 VLOG(1) << "NaCl loader: setting up IPC descriptor";
52 // don't need zygote FD any more 87 InitializeSandbox(uses_nonsfi);
53 if (IGNORE_EINTR(close(kNaClZygoteDescriptor)) != 0)
54 LOG(ERROR) << "close(kNaClZygoteDescriptor) failed.";
55 bool sandbox_initialized = InitializeBPFSandbox();
56 if (!sandbox_initialized) {
57 LOG(ERROR) << "Could not initialize NaCl's second "
58 << "layer sandbox (seccomp-bpf).";
59 }
60 base::GlobalDescriptors::GetInstance()->Set( 88 base::GlobalDescriptors::GetInstance()->Set(
61 kPrimaryIPCChannel, 89 kPrimaryIPCChannel,
62 child_fds[content::ZygoteForkDelegate::kBrowserFDIndex]); 90 child_fds[content::ZygoteForkDelegate::kBrowserFDIndex]);
63 91
64 base::MessageLoopForIO main_message_loop; 92 base::MessageLoopForIO main_message_loop;
65 NaClListener listener; 93 NaClListener listener;
Mark Seaborn 2014/03/28 01:38:25 This could become "listener(uses_nonsfi_mode)" (se
hamaji 2014/03/28 12:06:10 Done, but I added set_uses_nonsfi_mode for consist
66 listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size); 94 listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size);
67 listener.set_number_of_cores(system_info.number_of_cores); 95 listener.set_number_of_cores(system_info.number_of_cores);
68 listener.Listen(); 96 listener.Listen();
69 _exit(0); 97 _exit(0);
70 } 98 }
71 99
72 // Start the NaCl loader in a child created by the NaCl loader Zygote. 100 // Start the NaCl loader in a child created by the NaCl loader Zygote.
73 void ChildNaClLoaderInit(const std::vector<int>& child_fds, 101 void ChildNaClLoaderInit(const std::vector<int>& child_fds,
74 const NaClLoaderSystemInfo& system_info) { 102 const NaClLoaderSystemInfo& system_info,
103 bool uses_nonsfi) {
75 const int parent_fd = child_fds[content::ZygoteForkDelegate::kParentFDIndex]; 104 const int parent_fd = child_fds[content::ZygoteForkDelegate::kParentFDIndex];
76 const int dummy_fd = child_fds[content::ZygoteForkDelegate::kDummyFDIndex]; 105 const int dummy_fd = child_fds[content::ZygoteForkDelegate::kDummyFDIndex];
77 bool validack = false; 106 bool validack = false;
78 const size_t kMaxReadSize = 1024; 107 const size_t kMaxReadSize = 1024;
79 char buffer[kMaxReadSize]; 108 char buffer[kMaxReadSize];
80 // Wait until the parent process has discovered our PID. We 109 // Wait until the parent process has discovered our PID. We
81 // should not fork any child processes (which the seccomp 110 // should not fork any child processes (which the seccomp
82 // sandbox does) until then, because that can interfere with the 111 // sandbox does) until then, because that can interfere with the
83 // parent's discovery of our PID. 112 // parent's discovery of our PID.
84 const int nread = HANDLE_EINTR(read(parent_fd, buffer, kMaxReadSize)); 113 const int nread = HANDLE_EINTR(read(parent_fd, buffer, kMaxReadSize));
(...skipping 11 matching lines...) Expand all
96 switches::kProcessChannelID, 125 switches::kProcessChannelID,
97 std::string(&buffer[len], nread - len)); 126 std::string(&buffer[len], nread - len));
98 validack = true; 127 validack = true;
99 } 128 }
100 } 129 }
101 if (IGNORE_EINTR(close(dummy_fd)) != 0) 130 if (IGNORE_EINTR(close(dummy_fd)) != 0)
102 LOG(ERROR) << "close(dummy_fd) failed"; 131 LOG(ERROR) << "close(dummy_fd) failed";
103 if (IGNORE_EINTR(close(parent_fd)) != 0) 132 if (IGNORE_EINTR(close(parent_fd)) != 0)
104 LOG(ERROR) << "close(parent_fd) failed"; 133 LOG(ERROR) << "close(parent_fd) failed";
105 if (validack) { 134 if (validack) {
106 BecomeNaClLoader(child_fds, system_info); 135 BecomeNaClLoader(child_fds, system_info, uses_nonsfi);
107 } else { 136 } else {
108 LOG(ERROR) << "Failed to synch with zygote"; 137 LOG(ERROR) << "Failed to synch with zygote";
109 } 138 }
110 _exit(1); 139 _exit(1);
111 } 140 }
112 141
113 // Handle a fork request from the Zygote. 142 // Handle a fork request from the Zygote.
114 // Some of this code was lifted from 143 // Some of this code was lifted from
115 // content/browser/zygote_main_linux.cc:ForkWithRealPid() 144 // content/browser/zygote_main_linux.cc:ForkWithRealPid()
116 bool HandleForkRequest(const std::vector<int>& child_fds, 145 bool HandleForkRequest(const std::vector<int>& child_fds,
117 const NaClLoaderSystemInfo& system_info, 146 const NaClLoaderSystemInfo& system_info,
147 PickleIterator* input_iter,
118 Pickle* output_pickle) { 148 Pickle* output_pickle) {
149 bool uses_nonsfi;
150 if (!input_iter->ReadBool(&uses_nonsfi)) {
151 LOG(ERROR) << "Could not read uses_nonsfi status";
152 return false;
153 }
154
119 if (content::ZygoteForkDelegate::kNumPassedFDs != child_fds.size()) { 155 if (content::ZygoteForkDelegate::kNumPassedFDs != child_fds.size()) {
120 LOG(ERROR) << "nacl_helper: unexpected number of fds, got " 156 LOG(ERROR) << "nacl_helper: unexpected number of fds, got "
121 << child_fds.size(); 157 << child_fds.size();
122 return false; 158 return false;
123 } 159 }
124 160
125 VLOG(1) << "nacl_helper: forking"; 161 VLOG(1) << "nacl_helper: forking";
126 pid_t child_pid = fork(); 162 pid_t child_pid = fork();
127 if (child_pid < 0) { 163 if (child_pid < 0) {
128 PLOG(ERROR) << "*** fork() failed."; 164 PLOG(ERROR) << "*** fork() failed.";
129 } 165 }
130 166
131 if (child_pid == 0) { 167 if (child_pid == 0) {
132 ChildNaClLoaderInit(child_fds, system_info); 168 ChildNaClLoaderInit(child_fds, system_info, uses_nonsfi);
133 NOTREACHED(); 169 NOTREACHED();
134 } 170 }
135 171
136 // I am the parent. 172 // I am the parent.
137 // First, close the dummy_fd so the sandbox won't find me when 173 // First, close the dummy_fd so the sandbox won't find me when
138 // looking for the child's pid in /proc. Also close other fds. 174 // looking for the child's pid in /proc. Also close other fds.
139 for (size_t i = 0; i < child_fds.size(); i++) { 175 for (size_t i = 0; i < child_fds.size(); i++) {
140 if (IGNORE_EINTR(close(child_fds[i])) != 0) 176 if (IGNORE_EINTR(close(child_fds[i])) != 0)
141 LOG(ERROR) << "close(child_fds[i]) failed"; 177 LOG(ERROR) << "close(child_fds[i]) failed";
142 } 178 }
(...skipping 26 matching lines...) Expand all
169 base::TerminationStatus status; 205 base::TerminationStatus status;
170 if (known_dead) 206 if (known_dead)
171 status = base::GetKnownDeadTerminationStatus(child_to_wait, &exit_code); 207 status = base::GetKnownDeadTerminationStatus(child_to_wait, &exit_code);
172 else 208 else
173 status = base::GetTerminationStatus(child_to_wait, &exit_code); 209 status = base::GetTerminationStatus(child_to_wait, &exit_code);
174 output_pickle->WriteInt(static_cast<int>(status)); 210 output_pickle->WriteInt(static_cast<int>(status));
175 output_pickle->WriteInt(exit_code); 211 output_pickle->WriteInt(exit_code);
176 return true; 212 return true;
177 } 213 }
178 214
179 // This is a poor man's check on whether we are sandboxed.
180 bool IsSandboxed() {
181 int proc_fd = open("/proc/self/exe", O_RDONLY);
182 if (proc_fd >= 0) {
183 close(proc_fd);
184 return false;
185 }
186 return true;
187 }
188
189 // Honor a command |command_type|. Eventual command parameters are 215 // Honor a command |command_type|. Eventual command parameters are
190 // available in |input_iter| and eventual file descriptors attached to 216 // available in |input_iter| and eventual file descriptors attached to
191 // the command are in |attached_fds|. 217 // the command are in |attached_fds|.
192 // Reply to the command on |reply_fds|. 218 // Reply to the command on |reply_fds|.
193 bool HonorRequestAndReply(int reply_fd, 219 bool HonorRequestAndReply(int reply_fd,
194 int command_type, 220 int command_type,
195 const std::vector<int>& attached_fds, 221 const std::vector<int>& attached_fds,
196 const NaClLoaderSystemInfo& system_info, 222 const NaClLoaderSystemInfo& system_info,
197 PickleIterator* input_iter) { 223 PickleIterator* input_iter) {
198 Pickle write_pickle; 224 Pickle write_pickle;
199 bool have_to_reply = false; 225 bool have_to_reply = false;
200 // Commands must write anything to send back to |write_pickle|. 226 // Commands must write anything to send back to |write_pickle|.
201 switch (command_type) { 227 switch (command_type) {
202 case nacl::kNaClForkRequest: 228 case nacl::kNaClForkRequest:
203 have_to_reply = HandleForkRequest(attached_fds, system_info, 229 have_to_reply = HandleForkRequest(attached_fds, system_info,
230 input_iter,
204 &write_pickle); 231 &write_pickle);
205 break; 232 break;
206 case nacl::kNaClGetTerminationStatusRequest: 233 case nacl::kNaClGetTerminationStatusRequest:
207 have_to_reply = 234 have_to_reply =
208 HandleGetTerminationStatusRequest(input_iter, &write_pickle); 235 HandleGetTerminationStatusRequest(input_iter, &write_pickle);
209 break; 236 break;
210 default: 237 default:
211 LOG(ERROR) << "Unsupported command from Zygote"; 238 LOG(ERROR) << "Unsupported command from Zygote";
212 return false; 239 return false;
213 } 240 }
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 // Now handle requests from the Zygote. 408 // Now handle requests from the Zygote.
382 while (true) { 409 while (true) {
383 bool request_handled = HandleZygoteRequest(kNaClZygoteDescriptor, 410 bool request_handled = HandleZygoteRequest(kNaClZygoteDescriptor,
384 system_info); 411 system_info);
385 // Do not turn this into a CHECK() without thinking about robustness 412 // Do not turn this into a CHECK() without thinking about robustness
386 // against malicious IPC requests. 413 // against malicious IPC requests.
387 DCHECK(request_handled); 414 DCHECK(request_handled);
388 } 415 }
389 NOTREACHED(); 416 NOTREACHED();
390 } 417 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698