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

Side by Side Diff: src/trusted/plugin/srpc/service_runtime.cc

Issue 2981011: Move plugin/srpc contents to the more appropriately named plugin/common.... (Closed) Base URL: http://nativeclient.googlecode.com/svn/trunk/src/native_client/
Patch Set: '' Created 10 years, 5 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
« no previous file with comments | « src/trusted/plugin/srpc/service_runtime.h ('k') | src/trusted/plugin/srpc/shared_memory.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2008 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can
4 * be found in the LICENSE file.
5 */
6
7 #include "native_client/src/trusted/plugin/srpc/service_runtime.h"
8
9 #include <map>
10 #include <vector>
11
12 #include "native_client/src/include/nacl_string.h"
13 #include "native_client/src/include/nacl_macros.h"
14 #include "native_client/src/shared/imc/nacl_imc.h"
15 #include "native_client/src/shared/platform/nacl_log.h"
16 #include "native_client/src/trusted/desc/nacl_desc_imc.h"
17 #include "native_client/src/trusted/desc/nrd_xfer.h"
18 #include "native_client/src/trusted/desc/nrd_xfer_effector.h"
19 #include "native_client/src/trusted/handle_pass/browser_handle.h"
20 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
21
22 #include "native_client/src/trusted/plugin/npapi/multimedia_socket.h"
23 #include "native_client/src/trusted/plugin/srpc/browser_interface.h"
24 #include "native_client/src/trusted/plugin/srpc/connected_socket.h"
25 #include "native_client/src/trusted/plugin/srpc/plugin.h"
26 #include "native_client/src/trusted/plugin/srpc/shared_memory.h"
27 #include "native_client/src/trusted/plugin/srpc/socket_address.h"
28 #include "native_client/src/trusted/plugin/srpc/srt_socket.h"
29 #include "native_client/src/trusted/plugin/srpc/scriptable_handle.h"
30 #include "native_client/src/trusted/plugin/srpc/utility.h"
31
32 #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h"
34
35 using std::vector;
36
37 namespace plugin {
38
39 ServiceRuntime::ServiceRuntime(
40 BrowserInterface* browser_interface,
41 Plugin* plugin) :
42 async_receive_desc(NULL),
43 async_send_desc(NULL),
44 browser_interface_(browser_interface),
45 default_socket_address_(NULL),
46 default_socket_(NULL),
47 plugin_(plugin),
48 runtime_channel_(NULL),
49 subprocess_(NULL) {
50 }
51
52 // shm is consumed (Delete invoked).
53 bool ServiceRuntime::InitCommunication(nacl::DescWrapper* shm) {
54 // TODO(sehr): this should use the new
55 // SelLdrLauncher::OpenSrpcChannels interface, which should be free
56 // of resource leaks.
57 // Channel5 was opened to communicate with the sel_ldr instance.
58 // Get the first IMC message and create a socket address from it.
59 nacl::Handle channel5 = subprocess_->channel();
60 PLUGIN_PRINTF(("ServiceRuntime(%p): opened %p 0x%p\n",
61 static_cast<void*>(this), static_cast<void*>(subprocess_),
62 reinterpret_cast<void*>(channel5)));
63 // GetSocketAddress implicitly invokes Close(channel5).
64 default_socket_address_ = GetSocketAddress(plugin_, channel5);
65 PLUGIN_PRINTF(("ServiceRuntime::Start: "
66 "Got service channel descriptor %p\n",
67 static_cast<void*>(default_socket_address_)));
68
69 if (NULL == default_socket_address_) {
70 PLUGIN_PRINTF(("ServiceRuntime::InitCommunication "
71 "no valid socket address\n"));
72 browser_interface_->Alert(plugin()->instance_id(),
73 "service runtime: no valid socket address");
74 return false;
75 }
76 ScriptableHandle* raw_channel;
77 // The first connect on the socket address returns the service
78 // runtime command channel. This channel is created before the NaCl
79 // module runs, and is private to the service runtime. This channel
80 // is used for a secure plugin<->service runtime communication path
81
82
83 // that can be used to forcibly shut down the sel_ldr.
84 PLUGIN_PRINTF((" connecting for SrtSocket\n"));
85 PortableHandle* portable_socket_address = default_socket_address_->handle();
86 raw_channel = portable_socket_address->Connect();
87 if (NULL == raw_channel) {
88 PLUGIN_PRINTF(("ServiceRuntime::Start: "
89 "service runtime Connect failed.\n"));
90 browser_interface_->Alert(plugin()->instance_id(),
91 "service runtime Connect failed");
92 return false;
93 }
94 PLUGIN_PRINTF((" constructing SrtSocket\n"));
95 runtime_channel_ = new(std::nothrow) SrtSocket(raw_channel,
96 browser_interface_);
97 if (NULL == runtime_channel_) {
98 // TODO(sehr): leaking raw_channel.
99 return false;
100 }
101
102 // Set module's origin at the service runtime. NB: we may end up
103 // enforcing restrictions for network access to the origin of the
104 // module only in the plugin. Here's why:
105 //
106 // When a plugin using NPAPI invokes NPP_GetURLNotify (on the behalf
107 // of a NaCl module), it may provide a relative URL; even if it is
108 // not a relative URL, 3xx redirects may change the source domain of
109 // the actual web content as a side effect -- the 3xx redirects
110 // cause the browser to make new HTTP connections, and the browser
111 // does not notify the plugin as this is occurring. However, when
112 // the browser invokes NPN_NewStream and then either
113 // NPN_StreamAsFile or NPP_WriteReady/NPP_Write to deliver the
114 // content, the NPStream object contains the fully-qualified URL of
115 // the web content, after redirections (if any). This means that we
116 // should parse the FQ-URL at NPN_NewStream or NPN_StreamAsFile,
117 // rather than try to canonicalize the URL before passing it to
118 // NPP_GetURLNotify, since we won't know the final FQ-URL at that
119 // point.
120 //
121 // This strategy also implies that we might allow any URL, e.g., a
122 // tinyurl.com redirecting URL, to be used with NPP_GetURLNotify,
123 // and allow the access if the final FQ-URL is the same domain.
124 // This has the hazard that we still are doing fetches to other
125 // domains (including sending cookies specific to those domains),
126 // just not making the results available to the NaCl module; the
127 // same thing occurs if IMG SRC tags were scripted.
128 //
129 // A perhaps more important downside is that this is an easy way for
130 // NaCl modules to leak information: the target web server is always
131 // contacted, since we don't know if
132 // http://evil.org/leak?s3kr1t_inf0 might result in a 3xx redirect
133 // to an acceptable origin. If we want to prevent this, we could
134 // require that all URLs given to NPP_GetURLNotify are either
135 // relative or are absolute with the same origin as the module; this
136 // would prevent the scenario where an evil module is hosted (e.g.,
137 // in temporary upload directory that's visible, or as a gmail
138 // attachment URL) at an innocent server to extract confidential
139 // info and send it to third party servers. An explict network ACL
140 // a la /robots.txt might be useful to serve as an ingress filter.z
141
142 PLUGIN_PRINTF(("invoking set_origin\n"));
143 if (!runtime_channel_->SetOrigin(plugin_->nacl_module_origin())) {
144 PLUGIN_PRINTF(("ServiceRuntime::Start: "
145 "set_origin RPC failed.\n"));
146 browser_interface_->Alert(plugin()->instance_id(), "Could not set origin");
147 // TODO(sehr): leaking raw_channel and runtime_channel_.
148 return false;
149 }
150
151 if (shm != NULL) {
152 // This code is executed only if NaCl is running as a built-in plugin
153 // in Chrome.
154 // We now have an open communication channel to the sel_ldr process,
155 // so we can send the nexe bits over
156 if (!runtime_channel_->LoadModule(shm->desc())) {
157 PLUGIN_PRINTF(("ServiceRuntime::Start failed to send nexe\n"));
158 browser_interface_->Alert(plugin()->instance_id(), "failed to send nexe");
159 shm->Delete();
160 // TODO(gregoryd): close communication channels
161 delete subprocess_;
162 subprocess_ = NULL;
163 return false;
164 }
165 /* LoadModule succeeded, proceed normally */
166 shm->Delete();
167 #if NACL_WINDOWS && !defined(NACL_STANDALONE)
168 // Establish the communication for handle passing protocol
169 struct NaClDesc* desc = NaClHandlePassBrowserGetSocketAddress();
170 if (!runtime_channel_->InitHandlePassing(desc, subprocess_->child())) {
171 delete subprocess_;
172 subprocess_ = NULL;
173 return false;
174 }
175 #endif
176 }
177
178 // start the module. otherwise we cannot connect for multimedia
179 // subsystem since that is handled by user-level code (not secure!)
180 // in libsrpc.
181 int load_status;
182
183 PLUGIN_PRINTF((" invoking start_module RPC\n"));
184 if (!runtime_channel_->StartModule(&load_status)) {
185 PLUGIN_PRINTF(("ServiceRuntime::Start: "
186 "module_start RPC failed.\n"));
187 browser_interface_->Alert(plugin()->instance_id(),
188 "Could not start nacl module");
189
190 // TODO(sehr): leaking raw_channel and runtime_channel_.
191 return false;
192 }
193 PLUGIN_PRINTF((" start_module returned %d\n", load_status));
194 if (LOAD_OK != load_status) {
195 PLUGIN_PRINTF(("ServiceRuntime::Start: "
196 "module load status %d",
197 load_status));
198 nacl::stringstream ss;
199 ss << "Loading of module failed with status " << load_status;
200 browser_interface_->Alert(plugin()->instance_id(), ss.str());
201 // TODO(sehr): leaking raw_channel and runtime_channel_.
202 return false;
203 }
204
205 // The second connect on the socket address is to the untrusted side
206 // of sel_ldr.
207 default_socket_ = portable_socket_address->Connect();
208 if (NULL == default_socket_) {
209 PLUGIN_PRINTF(("ServiceRuntime::Start: "
210 "SRPC channel Connect failed.\n"));
211 // TODO(sehr): leaking raw_channel and runtime_channel_.
212 return false;
213 }
214 default_socket_->handle()->StartJSObjectProxy(plugin_);
215 plugin_->EnableVideo();
216 // Create the listener thread and initialize the nacl module.
217 if (!plugin_->InitializeModuleMultimedia(default_socket_, this)) {
218 // TODO(sehr): leaking raw_channel, runtime_channel_, and default_socket_.
219 return false;
220 }
221 return true;
222 }
223
224 bool ServiceRuntime::Start(const char* nacl_file) {
225 // The arguments we want to pass to the service runtime are
226 // "-P 5" sets the default SRPC channel to be over descriptor 5. The 5 needs
227 // to match the 5 in the Launcher invocation below.
228 // "-X 5" causes the service runtime to create a bound socket and socket
229 // address at descriptors 3 and 4. The socket address is transferred as
230 // the first IMC message on descriptor 5. This is used when connecting
231 // to socket addresses.
232 // "-d" (not default) invokes the service runtime in debug mode.
233 // const char* kSelLdrArgs[] = { "-P", "5", "-X", "5" };
234 const char* kSelLdrArgs[] = { "-P", "5", "-X", "5" };
235 // TODO(sehr): remove -P support and default channels.
236 const int kSelLdrArgLength = NACL_ARRAY_SIZE(kSelLdrArgs);
237 vector<nacl::string> kArgv(kSelLdrArgs, kSelLdrArgs + kSelLdrArgLength);
238 vector<nacl::string> kEmpty;
239
240 PLUGIN_PRINTF(("ServiceRuntime::ServiceRuntime"
241 "(%p, %p, %s)\n",
242 static_cast<void*>(this),
243 static_cast<void*>(plugin()),
244 nacl_file));
245
246 subprocess_ = new(std::nothrow) nacl::SelLdrLauncher();
247 if (NULL == subprocess_) {
248 PLUGIN_PRINTF(("ServiceRuntime: Could not create SelLdrLauncher"));
249 browser_interface_->Alert(plugin()->instance_id(),
250 "Could not create SelLdrLauncher");
251 return false;
252 }
253 subprocess_->Init(nacl_file, 5, kArgv, kEmpty);
254
255 nacl::Handle receive_handle = subprocess_->ExportImcFD(6);
256 if (receive_handle == nacl::kInvalidHandle) {
257 browser_interface_->Alert(plugin()->instance_id(),
258 "Failed to create async receive handle");
259 return false;
260 }
261 async_receive_desc = plugin()->wrapper_factory()->MakeImcSock(receive_handle);
262
263 nacl::Handle send_handle = subprocess_->ExportImcFD(7);
264 if (send_handle == nacl::kInvalidHandle) {
265 browser_interface_->Alert(plugin()->instance_id(),
266 "Failed to create async send handle");
267 return false;
268 }
269 async_send_desc = plugin()->wrapper_factory()->MakeImcSock(send_handle);
270
271 if (!subprocess_->Launch()) {
272 PLUGIN_PRINTF(("ServiceRuntime: Could not start SelLdrLauncher"));
273 browser_interface_->Alert(plugin()->instance_id(),
274 "Could not start SelLdrLauncher");
275 delete subprocess_;
276 subprocess_ = NULL;
277 return false;
278 }
279
280 // TODO(gregoryd) - this should deal with buffer and size correctly
281 // - do we need to send the load command from here?
282 if (!InitCommunication(NULL)) {
283 return false;
284 }
285
286 PLUGIN_PRINTF(("ServiceRuntime::Start was successful\n"));
287 return true;
288 }
289
290 // Chromium version.
291 bool ServiceRuntime::Start(const char* url, nacl::DescWrapper* shm) {
292 subprocess_ = new(std::nothrow) nacl::SelLdrLauncher();
293 if (NULL == subprocess_) {
294 return false;
295 }
296 if (!subprocess_->Start(url, 5)) {
297 delete subprocess_;
298 subprocess_ = NULL;
299 return false;
300 }
301
302 if (!InitCommunication(shm)) {
303 return false;
304 }
305
306 PLUGIN_PRINTF(("ServiceRuntime::Start was successful\n"));
307 return true;
308 }
309
310 bool ServiceRuntime::Kill() {
311 return subprocess_->KillChild();
312 }
313
314 bool ServiceRuntime::Log(int severity, nacl::string msg) {
315 return runtime_channel_->Log(severity, msg);
316 }
317
318 void ServiceRuntime::Shutdown() {
319 if (subprocess_ != NULL) {
320 Kill();
321 }
322 // This waits for the upcall thread to exit so it must come after we
323 // terminate the subprocess.
324 plugin_->ShutdownMultimedia();
325
326 // Note that this does waitpid() to get rid of any zombie subprocess.
327 delete subprocess_;
328 subprocess_ = NULL;
329
330 delete runtime_channel_;
331 runtime_channel_ = NULL;
332 }
333
334 ServiceRuntime::~ServiceRuntime() {
335 PLUGIN_PRINTF(("ServiceRuntime::~ServiceRuntime(%p)\n",
336 static_cast<void*>(this)));
337
338 // We do this just in case Terminate() was not called.
339 delete subprocess_;
340 delete runtime_channel_;
341
342 if (async_receive_desc != NULL) {
343 async_receive_desc->Delete();
344 }
345 if (async_send_desc != NULL) {
346 async_send_desc->Delete();
347 }
348 }
349
350 ScriptableHandle* ServiceRuntime::default_socket_address() const {
351 PLUGIN_PRINTF(("ServiceRuntime::default_socket_address(%p) = %p\n",
352 static_cast<void*>(const_cast<ServiceRuntime*>(this)),
353 static_cast<void*>(const_cast<ScriptableHandle*>(
354 default_socket_address_))));
355
356 return default_socket_address_;
357 }
358
359 ScriptableHandle* ServiceRuntime::default_socket() const {
360 PLUGIN_PRINTF(("ServiceRuntime::default_socket(%p) = %p\n",
361 static_cast<void*>(const_cast<ServiceRuntime*>(this)),
362 static_cast<void*>(const_cast<ScriptableHandle*>(
363 default_socket_))));
364
365 return default_socket_;
366 }
367
368 ScriptableHandle* ServiceRuntime::GetSocketAddress(
369 Plugin* plugin,
370 nacl::Handle channel) {
371 nacl::DescWrapper::MsgHeader header;
372 nacl::DescWrapper::MsgIoVec iovec[1];
373 unsigned char bytes[NACL_ABI_IMC_USER_BYTES_MAX];
374 nacl::DescWrapper* descs[NACL_ABI_IMC_USER_DESC_MAX];
375
376 PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress(%p, %p)\n",
377 static_cast<void*>(plugin),
378 reinterpret_cast<void*>(channel)));
379
380 ScriptableHandle* retval = NULL;
381 nacl::DescWrapper* imc_desc = plugin->wrapper_factory()->MakeImcSock(channel);
382 // Set up to receive a message.
383 iovec[0].base = bytes;
384 iovec[0].length = NACL_ABI_IMC_USER_BYTES_MAX;
385 header.iov = iovec;
386 header.iov_length = NACL_ARRAY_SIZE(iovec);
387 header.ndescv = descs;
388 header.ndescv_length = NACL_ARRAY_SIZE(descs);
389 header.flags = 0;
390 // Receive the message.
391 ssize_t ret = imc_desc->RecvMsg(&header, 0);
392 // Check that there was exactly one descriptor passed.
393 if (0 > ret || 1 != header.ndescv_length) {
394 PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress: "
395 "message receive failed %" NACL_PRIdS " %" NACL_PRIdNACL_SIZE
396 " %" NACL_PRIdNACL_SIZE "\n", ret,
397 header.ndescv_length,
398 header.iov_length));
399 goto cleanup;
400 }
401 PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress: "
402 "-X result descriptor (DescWrapper*) = %p\n",
403 static_cast<void*>(descs[0])));
404 retval = browser_interface_->NewScriptableHandle(
405 SocketAddress::New(plugin, descs[0]));
406 cleanup:
407 imc_desc->Delete();
408 PLUGIN_PRINTF((" returning %p\n", static_cast<void*>(retval)));
409 return retval;
410 }
411
412 } // namespace plugin
OLDNEW
« no previous file with comments | « src/trusted/plugin/srpc/service_runtime.h ('k') | src/trusted/plugin/srpc/shared_memory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698