1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <assert.h>
8 :
9 : #include <algorithm>
10 : #include <iterator>
11 : #include <vector>
12 :
13 : #if NACL_OSX
14 : #include <crt_externs.h>
15 : #endif
16 :
17 : #include "native_client/src/include/nacl_macros.h"
18 : #include "native_client/src/include/nacl_scoped_ptr.h"
19 : #include "native_client/src/include/nacl_string.h"
20 : #include "native_client/src/shared/srpc/nacl_srpc.h"
21 : #include "native_client/src/shared/platform/nacl_check.h"
22 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
23 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
24 : #include "native_client/src/trusted/service_runtime/env_cleanser.h"
25 : #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
26 :
27 : using std::vector;
28 :
29 :
30 : namespace nacl {
31 :
32 12 : SelLdrLauncher::SelLdrLauncher()
33 : : child_process_(kInvalidHandle),
34 : channel_(kInvalidHandle),
35 : channel_number_(-1),
36 : command_prefix_(""),
37 : bootstrap_socket_(NULL),
38 : socket_addr_(NULL),
39 12 : sel_ldr_locator_(new PluginSelLdrLocator()) {
40 12 : }
41 :
42 0 : SelLdrLauncher::SelLdrLauncher(SelLdrLocator* sel_ldr_locator)
43 : : child_process_(kInvalidHandle),
44 : channel_(kInvalidHandle),
45 : channel_number_(-1),
46 : bootstrap_socket_(NULL),
47 : socket_addr_(NULL),
48 0 : sel_ldr_locator_(sel_ldr_locator) {
49 0 : CHECK(sel_ldr_locator != NULL);
50 0 : }
51 :
52 0 : void SelLdrLauncher::GetPluginDirectory(char* buffer, size_t len) {
53 0 : sel_ldr_locator_->GetDirectory(buffer, len);
54 0 : }
55 :
56 11 : static DescWrapper* GetSockAddr(DescWrapper* desc) {
57 : DescWrapper::MsgHeader header;
58 : DescWrapper::MsgIoVec iovec[1];
59 : DescWrapper* descs[NACL_ABI_IMC_USER_DESC_MAX];
60 : scoped_array<unsigned char> bytes(
61 11 : new unsigned char[NACL_ABI_IMC_USER_BYTES_MAX]);
62 11 : if (bytes.get() == NULL) {
63 0 : return NULL;
64 : }
65 :
66 : // Set up to receive a message.
67 11 : iovec[0].base = bytes.get();
68 11 : iovec[0].length = NACL_ABI_IMC_USER_BYTES_MAX;
69 11 : header.iov = iovec;
70 11 : header.iov_length = NACL_ARRAY_SIZE(iovec);
71 11 : header.ndescv = descs;
72 11 : header.ndescv_length = NACL_ARRAY_SIZE(descs);
73 11 : header.flags = 0;
74 : // Receive the message.
75 11 : if (0 != desc->RecvMsg(&header, 0,
76 : static_cast<struct NaClDescQuotaInterface*>(NULL))) {
77 0 : return NULL;
78 : }
79 : // Check that there was exactly one descriptor passed.
80 11 : if (1 != header.ndescv_length) {
81 0 : return NULL;
82 : }
83 :
84 11 : return descs[0];
85 : }
86 :
87 11 : bool SelLdrLauncher::LoadModule(NaClSrpcChannel* command, DescWrapper* nexe) {
88 11 : NaClLog(4, "Entered SelLdrLauncher::LoadModule\n");
89 : NaClSrpcResultCodes rpc_result = NaClSrpcInvokeBySignature(command,
90 : "load_module:hs:",
91 : nexe->desc(),
92 11 : "place holder");
93 11 : NaClLog(4, "SelLdrLauncher::LoadModule rpc result %d\n", (int) rpc_result);
94 11 : return NACL_SRPC_RESULT_OK == rpc_result;
95 : }
96 :
97 : bool SelLdrLauncher::StartModule(NaClSrpcChannel* command,
98 11 : NaClErrorCode* code) {
99 : // Start untrusted code module
100 11 : NaClLog(4, "Entered SelLdrLauncher::StartModule\n");
101 : int start_result;
102 : NaClSrpcResultCodes rpc_result = NaClSrpcInvokeBySignature(command,
103 : "start_module::i",
104 11 : &start_result);
105 11 : NaClLog(4, "SelLdrLauncher::StartModule rpc result %d\n", (int) rpc_result);
106 11 : if (NACL_SRPC_RESULT_OK != rpc_result) {
107 0 : NaClSrpcDtor(command);
108 0 : *code = LOAD_INTERNAL;
109 0 : NaClLog(4, "Leaving SelLdrLauncher::StartModule, FAILED\n");
110 0 : return false;
111 : }
112 :
113 11 : *code = (NaClErrorCode) start_result;
114 11 : NaClLog(4, "Leaving SelLdrLauncher::StartModule, success\n");
115 11 : return true;
116 : }
117 :
118 :
119 11 : bool SelLdrLauncher::SetupBootstrapChannel() {
120 : // channel_ is initialized in LaunchFromCommandLine if
121 : // channel_number_ is not -1, and InitCommandLine requires imc_fd to be
122 : // supplied which is used to initialize channel_number_, so channel_ should
123 : // never be invalid.
124 :
125 11 : CHECK(factory_ == NULL);
126 11 : factory_.reset(new DescWrapperFactory);
127 :
128 11 : CHECK(channel_ != kInvalidHandle);
129 11 : bootstrap_socket_.reset(factory_->MakeImcSock(channel_));
130 11 : if (bootstrap_socket_ == NULL) {
131 : NaClLog(4, ("Leaving SelLdrLauncher::SetupBootstrapChannel"
132 0 : " SetupBootstrapChannel failed\n"));
133 0 : return false;
134 : }
135 :
136 : // bootstrap_socket_ now has ownership of channel_, so we get rid of
137 : // our "reference" to it.
138 11 : channel_ = kInvalidHandle;
139 11 : return true;
140 : }
141 :
142 11 : bool SelLdrLauncher::GetLdrSocketAddress() {
143 : // Get the socket address from the descriptor.
144 11 : socket_addr_.reset(GetSockAddr(bootstrap_socket_.get()));
145 11 : if (socket_addr_ == NULL) {
146 0 : NaClLog(4, "SelLdrLauncher::GetLdrSocketAddress: GetSockAddr failed\n");
147 0 : return false;
148 : }
149 11 : return true;
150 : }
151 :
152 11 : bool SelLdrLauncher::SetupCommandChannel(NaClSrpcChannel* command) {
153 : // The first connection goes to the trusted command channel.
154 11 : scoped_ptr<DescWrapper> command_desc(socket_addr_->Connect());
155 11 : if (command_desc == NULL) {
156 0 : NaClLog(4, "SelLdrLauncher::SetupCommandChannel: Connect failed\n");
157 0 : return false;
158 : }
159 : // Start the SRPC client to communicate with the trusted command channel.
160 : // SRPC client takes an additional reference to command_desc.
161 11 : if (!NaClSrpcClientCtor(command, command_desc->desc())) {
162 0 : NaClLog(4, "SelLdrLauncher::SetupCommandChannel: command ctor failed\n");
163 0 : return false;
164 : }
165 11 : return true;
166 : }
167 :
168 11 : bool SelLdrLauncher::SetupApplicationChannel(NaClSrpcChannel* app_channel) {
169 : // The second connection goes to the service itself.
170 11 : scoped_ptr<DescWrapper> untrusted_desc(socket_addr_->Connect());
171 11 : if (untrusted_desc == NULL) {
172 0 : return false;
173 : }
174 : // Start the SRPC client to communicate with the untrusted service
175 : // SRPC client takes an additional reference to untrusted_desc.
176 11 : if (!NaClSrpcClientCtor(app_channel, untrusted_desc->desc())) {
177 : NaClLog(4,
178 1 : "SelLdrLauncher::SetupApplicationChannel: untrusted ctor failed\n");
179 1 : return false;
180 : }
181 10 : return true;
182 : }
183 :
184 : bool SelLdrLauncher::SetupCommandAndLoad(NaClSrpcChannel* command,
185 11 : DescWrapper* nexe) {
186 11 : if (!SetupBootstrapChannel()) {
187 0 : return false;
188 : }
189 11 : if (!GetLdrSocketAddress()) {
190 0 : return false;
191 : }
192 11 : if (!SetupCommandChannel(command)) {
193 0 : return false;
194 : }
195 11 : if (NULL != nexe) {
196 11 : if (!LoadModule(command, nexe)) {
197 0 : NaClSrpcDtor(command);
198 0 : return false;
199 : }
200 : }
201 11 : return true;
202 : }
203 :
204 : bool
205 : SelLdrLauncher::StartModuleAndSetupAppChannel(NaClSrpcChannel* command,
206 11 : NaClSrpcChannel* out_app_chan) {
207 : NaClErrorCode code;
208 11 : if (!StartModule(command, &code)) {
209 : NaClLog(4,
210 : ("SelLdrLauncher::StartModuleAndSetupAppChannel: start module"
211 : " failed %d (%s) \n"),
212 : (int) code,
213 0 : NaClErrorString(code));
214 0 : return false;
215 : }
216 11 : if (!SetupApplicationChannel(out_app_chan)) {
217 1 : return false;
218 : }
219 :
220 10 : return true;
221 : }
222 :
223 : #ifdef NACL_STANDALONE
224 : /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
225 : extern "C" char **environ;
226 :
227 12 : static char **GetEnviron() {
228 : #if NACL_OSX
229 : /* Mac dynamic libraries cannot access the environ variable directly. */
230 12 : return *_NSGetEnviron();
231 : #else
232 : return environ;
233 : #endif
234 : }
235 : #endif
236 :
237 0 : void SelLdrLauncher::SetCommandPrefix(const nacl::string& prefix) {
238 0 : command_prefix_ = prefix;
239 0 : }
240 :
241 12 : void SelLdrLauncher::BuildCommandLine(vector<nacl::string>* command) {
242 12 : assert(sel_ldr_ != NACL_NO_FILE_PATH); // Set by InitCommandLine().
243 12 : if (!command_prefix_.empty())
244 0 : command->push_back(command_prefix_);
245 12 : if (!sel_ldr_bootstrap_.empty())
246 0 : command->push_back(sel_ldr_bootstrap_);
247 12 : command->push_back(sel_ldr_);
248 12 : if (!sel_ldr_bootstrap_.empty())
249 0 : command->push_back("--r_debug=0xXXXXXXXXXXXXXXXX");
250 12 : command->push_back("-R"); // RPC will be used to point to the nexe.
251 :
252 12 : command->insert(command->end(), sel_ldr_argv_.begin(), sel_ldr_argv_.end());
253 :
254 : // Our use of "environ" above fails to link in the "shared" (DLL)
255 : // build of Chromium on Windows. However, we do not use
256 : // BuildCommandLine() when integrated into Chromium anyway -- we use
257 : // sel_main_chrome.c -- so it is safe to disable this code, which is
258 : // largely for debugging.
259 : // TODO(mseaborn): Tidy this up so that we do not need a conditional.
260 : #ifdef NACL_STANDALONE
261 : struct NaClEnvCleanser env_cleanser;
262 12 : NaClEnvCleanserCtor(&env_cleanser, 1);
263 12 : if (!NaClEnvCleanserInit(&env_cleanser, GetEnviron(), NULL)) {
264 0 : NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
265 : }
266 24 : for (const char* const* env = NaClEnvCleanserEnvironment(&env_cleanser);
267 : *env != NULL;
268 : ++env) {
269 0 : command->push_back("-E");
270 0 : command->push_back(*env);
271 : }
272 12 : NaClEnvCleanserDtor(&env_cleanser);
273 : #endif
274 :
275 12 : if (application_argv_.size() > 0) {
276 : // Separator between sel_universal and app args.
277 1 : command->push_back("--");
278 : command->insert(command->end(),
279 1 : application_argv_.begin(), application_argv_.end());
280 : }
281 12 : }
282 :
283 : void SelLdrLauncher::InitCommandLine(int imc_fd,
284 : const vector<nacl::string>& sel_ldr_argv,
285 12 : const vector<nacl::string>& app_argv) {
286 12 : assert(sel_ldr_ == NACL_NO_FILE_PATH); // Make sure we don't call this twice.
287 :
288 12 : char* var = getenv("NACL_SEL_LDR");
289 12 : if (var != NULL) {
290 12 : sel_ldr_ = var;
291 : } else {
292 0 : sel_ldr_ = GetSelLdrPathName();
293 : }
294 12 : char *bootstrap_var = getenv("NACL_SEL_LDR_BOOTSTRAP");
295 12 : if (bootstrap_var != NULL) {
296 0 : sel_ldr_bootstrap_ = bootstrap_var;
297 : } else {
298 12 : sel_ldr_bootstrap_ = GetSelLdrBootstrapPathName();
299 : }
300 12 : copy(sel_ldr_argv.begin(), sel_ldr_argv.end(), back_inserter(sel_ldr_argv_));
301 12 : copy(app_argv.begin(), app_argv.end(), back_inserter(application_argv_));
302 12 : channel_number_ = imc_fd;
303 12 : }
304 :
305 22 : void SelLdrLauncher::CloseHandlesAfterLaunch() {
306 33 : for (size_t i = 0; i < close_after_launch_.size(); i++) {
307 11 : Close(close_after_launch_[i]);
308 : }
309 22 : close_after_launch_.clear();
310 22 : }
311 :
312 0 : DescWrapper* SelLdrLauncher::Wrap(NaClDesc* raw_desc) {
313 0 : CHECK(factory_ != NULL);
314 0 : return factory_->MakeGeneric(raw_desc);
315 : }
316 :
317 2 : DescWrapper* SelLdrLauncher::WrapCleanup(NaClDesc* raw_desc) {
318 2 : CHECK(factory_ != NULL);
319 2 : return factory_->MakeGenericCleanup(raw_desc);
320 : }
321 :
322 : #if defined(NACL_STANDALONE)
323 0 : bool SelLdrLauncher::Start(int socket_count, Handle* result_sockets) {
324 : // Temporary: this interface is highly tailored to use by the browser
325 : // plugin, which currently wants to have exactly three sockets.
326 : // 0 -- the "bootstrap" socket.
327 : // 1 -- the "async receive" socket.
328 : // 2 -- the "async send" socket.
329 : // TODO(sehr): Change this API to return only the bootstrap socket when
330 : // the async support is removed.
331 0 : if (socket_count != 3) {
332 0 : return false;
333 : }
334 : // The arguments we want to pass to the service runtime are
335 : // "-X 5" causes the service runtime to create a bound socket and socket
336 : // address at descriptors 3 and 4 in the untrusted code for the nexe
337 : // or IRT to use. The argument to "-X", 5, is the host-OS descriptor
338 : // over which the internal representation of the sock addr is sent in
339 : // order to bootstrap communications with the untrusted NaCl module.
340 : // (NB: 5 is in a completely different namespace from the 3,4.)
341 0 : const char* kSelLdrArgs[] = { "-X", "5" };
342 0 : const int kSelLdrArgLength = NACL_ARRAY_SIZE(kSelLdrArgs);
343 : vector<nacl::string> args_for_sel_ldr(kSelLdrArgs,
344 0 : kSelLdrArgs + kSelLdrArgLength);
345 0 : vector<nacl::string> args_for_nexe;
346 0 : const char* irt_library_path = getenv("NACL_IRT_LIBRARY");
347 0 : if (NULL != irt_library_path) {
348 0 : args_for_sel_ldr.push_back("-B");
349 0 : args_for_sel_ldr.push_back(irt_library_path);
350 : }
351 : // This "5" matches the "-X 5" argument above.
352 0 : InitCommandLine(5, args_for_sel_ldr, args_for_nexe);
353 :
354 0 : result_sockets[1] = ExportImcFD(6);
355 0 : if (result_sockets[1] == nacl::kInvalidHandle) {
356 0 : return false;
357 : }
358 0 : result_sockets[2] = ExportImcFD(7);
359 0 : if (result_sockets[2] == nacl::kInvalidHandle) {
360 0 : return false;
361 : }
362 0 : if (!LaunchFromCommandLine()) {
363 0 : return false;
364 : }
365 0 : result_sockets[0] = channel_;
366 0 : return true;
367 : }
368 : #endif // defined(NACL_STANDALONE)
369 :
370 : } // namespace nacl
|