1 : // Copyright (c) 2012 The Native Client 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 :
6 : #include "native_client/src/trusted/sel_universal/reverse_emulate.h"
7 : #include <stdio.h>
8 : #include <cstring>
9 : #include <map>
10 : #include <set>
11 : #include <string>
12 : #include <utility>
13 : #include <vector>
14 :
15 : #include "native_client/src/include/portability_io.h"
16 : #include "native_client/src/public/nacl_file_info.h"
17 : #include "native_client/src/public/secure_service.h"
18 : #include "native_client/src/shared/platform/nacl_check.h"
19 : #include "native_client/src/shared/platform/nacl_log.h"
20 : #include "native_client/src/shared/platform/nacl_sync.h"
21 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
22 : #include "native_client/src/shared/platform/nacl_sync_raii.h"
23 : #include "native_client/src/shared/platform/nacl_threads.h"
24 : #include "native_client/src/shared/platform/scoped_ptr_refcount.h"
25 : #include "native_client/src/shared/srpc/nacl_srpc.h"
26 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
27 : #include "native_client/src/trusted/nonnacl_util/launcher_factory.h"
28 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
29 : #include "native_client/src/trusted/reverse_service/reverse_service.h"
30 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
31 : #include "native_client/src/trusted/sel_universal/srpc_helper.h"
32 :
33 :
34 : // Mock of ReverseInterface for use by nexes.
35 : class ReverseEmulate : public nacl::ReverseInterface {
36 : public:
37 : ReverseEmulate(
38 : nacl::SelLdrLauncherStandaloneFactory* factory,
39 : const vector<nacl::string>& prefix,
40 : const vector<nacl::string>& sel_ldr_argv);
41 : virtual ~ReverseEmulate();
42 :
43 : // Startup handshake
44 : virtual void StartupInitializationComplete();
45 :
46 : // Name service use.
47 : virtual bool OpenManifestEntry(nacl::string url_key,
48 : struct NaClFileInfo* info);
49 : virtual void ReportCrash();
50 :
51 : // The low-order 8 bits of the |exit_status| should be reported to
52 : // any interested parties.
53 : virtual void ReportExitStatus(int exit_status);
54 :
55 : // Send a string as a PostMessage to the browser.
56 : virtual void DoPostMessage(nacl::string message);
57 :
58 : // Create new service runtime process and return secure command
59 : // channel and untrusted application channel socket addresses.
60 : virtual int CreateProcess(nacl::DescWrapper** out_sock_addr,
61 : nacl::DescWrapper** out_app_addr);
62 :
63 : virtual void CreateProcessFunctorResult(
64 : nacl::CreateProcessFunctorInterface* functor);
65 :
66 : virtual void FinalizeProcess(int32_t pid);
67 :
68 : // Request quota for a write to a file.
69 : virtual int64_t RequestQuotaForWrite(nacl::string file_id,
70 : int64_t offset,
71 : int64_t length);
72 :
73 : // covariant impl of Ref()
74 : ReverseEmulate* Ref() { // down_cast
75 5 : return reinterpret_cast<ReverseEmulate*>(RefCountBase::Ref());
76 : }
77 :
78 : private:
79 : int32_t ReserveProcessSlot();
80 : void SaveToProcessSlot(int32_t pid,
81 : nacl::SelLdrLauncherStandalone *launcher);
82 : bool FreeProcessSlot(int32_t pid);
83 :
84 : NaClMutex mu_;
85 : std::vector<std::pair<bool, nacl::SelLdrLauncherStandalone*> > subprocesses_;
86 :
87 : nacl::SelLdrLauncherStandaloneFactory* factory_;
88 :
89 : std::vector<nacl::string> prefix_;
90 : std::vector<nacl::string> sel_ldr_argv_;
91 :
92 : NACL_DISALLOW_COPY_AND_ASSIGN(ReverseEmulate);
93 : };
94 :
95 : namespace {
96 :
97 : typedef std::map<nacl::string, string> KeyToFileMap;
98 :
99 14 : KeyToFileMap g_key_to_file;
100 :
101 14 : nacl::scoped_ptr_refcount<nacl::ReverseService> g_reverse_service;
102 :
103 : /*
104 : * TODO(phosek): These variables should be instance variables of Reverse
105 : * Emulate. However, we cannot make them such at the moment because they're
106 : * also being used by command handlers. This will require more significant
107 : * redesign/refactoring.
108 : */
109 : int g_exited;
110 : NaClMutex g_exit_mu;
111 : NaClCondVar g_exit_cv;
112 :
113 : } // end namespace
114 :
115 :
116 5 : bool ReverseEmulateInit(NaClSrpcChannel* command_channel,
117 5 : nacl::SelLdrLauncherStandalone* launcher,
118 5 : nacl::SelLdrLauncherStandaloneFactory* factory,
119 5 : const std::vector<nacl::string>& prefix,
120 5 : const std::vector<nacl::string>& sel_ldr_argv) {
121 : // Do the SRPC to the command channel to set up the reverse channel.
122 : // This returns a NaClDesc* containing a socket address.
123 5 : NaClLog(1, "ReverseEmulateInit: launching reverse RPC service\n");
124 5 : NaClDesc* h;
125 5 : NaClSrpcResultCodes rpc_result =
126 5 : NaClSrpcInvokeBySignature(command_channel,
127 : NACL_SECURE_SERVICE_REVERSE_SETUP,
128 : &h);
129 5 : if (NACL_SRPC_RESULT_OK != rpc_result) {
130 0 : NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse setup failed\n");
131 0 : return false;
132 : }
133 : // Make a nacl::DescWrapper* from the NaClDesc*
134 5 : nacl::scoped_ptr<nacl::DescWrapper> conn_cap(launcher->WrapCleanup(h));
135 10 : if (conn_cap == NULL) {
136 0 : NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse desc wrap failed\n");
137 0 : return false;
138 : }
139 : // The implementation of the ReverseInterface is our emulator class.
140 15 : nacl::scoped_ptr<ReverseEmulate> reverse_interface(new ReverseEmulate(
141 : factory, prefix, sel_ldr_argv));
142 : // Construct locks guarding exit status.
143 5 : NaClXMutexCtor(&g_exit_mu);
144 5 : NaClXCondVarCtor(&g_exit_cv);
145 5 : g_exited = false;
146 : // Create an instance of ReverseService, which connects to the socket
147 : // address and exports the services from our emulator.
148 20 : g_reverse_service.reset(new nacl::ReverseService(conn_cap.get(),
149 15 : reverse_interface->Ref()));
150 10 : if (g_reverse_service == NULL) {
151 0 : NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse service ctor failed\n");
152 0 : return false;
153 : }
154 : // Successful creation of ReverseService took ownership of these.
155 5 : reverse_interface.release();
156 5 : conn_cap.release();
157 : // Starts the RPC handler for the reverse interface.
158 15 : if (!g_reverse_service->Start()) {
159 0 : NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse service start failed\n");
160 0 : return false;
161 : }
162 5 : return true;
163 15 : }
164 :
165 : void ReverseEmulateFini() {
166 15 : CHECK(g_reverse_service != NULL);
167 5 : NaClLog(1, "Waiting for service threads to exit...\n");
168 5 : g_reverse_service->WaitForServiceThreadsToExit();
169 5 : NaClLog(1, "...service threads done\n");
170 5 : g_reverse_service.reset(NULL);
171 5 : NaClMutexDtor(&g_exit_mu);
172 5 : NaClCondVarDtor(&g_exit_cv);
173 5 : }
174 :
175 2 : bool HandlerReverseEmuAddManifestMapping(NaClCommandLoop* ncl,
176 2 : const std::vector<string>& args) {
177 4 : UNREFERENCED_PARAMETER(ncl);
178 2 : if (args.size() < 3) {
179 0 : NaClLog(LOG_ERROR, "not enough args\n");
180 0 : return false;
181 : }
182 2 : NaClLog(1, "HandlerReverseEmulateAddManifestMapping(%s) -> %s\n",
183 2 : args[1].c_str(), args[2].c_str());
184 : // Set the mapping for the key.
185 2 : g_key_to_file[args[1]] = args[2];
186 2 : return true;
187 2 : }
188 :
189 0 : bool HandlerReverseEmuDumpManifestMappings(NaClCommandLoop* ncl,
190 0 : const std::vector<string>& args) {
191 0 : UNREFERENCED_PARAMETER(ncl);
192 0 : if (args.size() != 1) {
193 0 : NaClLog(LOG_ERROR, "unexpected args\n");
194 0 : return false;
195 : }
196 0 : printf("ReverseEmulate manifest mappings:\n");
197 0 : for (KeyToFileMap::iterator i = g_key_to_file.begin();
198 0 : i != g_key_to_file.end();
199 0 : ++i) {
200 0 : printf("'%s': '%s'\n", i->first.c_str(), i->second.c_str());
201 0 : }
202 0 : return true;
203 0 : }
204 :
205 3 : bool HandlerWaitForExit(NaClCommandLoop* ncl,
206 3 : const std::vector<string>& args) {
207 6 : UNREFERENCED_PARAMETER(ncl);
208 6 : UNREFERENCED_PARAMETER(args);
209 :
210 3 : nacl::MutexLocker take(&g_exit_mu);
211 7 : while (!g_exited) {
212 1 : NaClXCondVarWait(&g_exit_cv, &g_exit_mu);
213 1 : }
214 :
215 3 : return true;
216 3 : }
217 :
218 : ReverseEmulate::ReverseEmulate(
219 10 : nacl::SelLdrLauncherStandaloneFactory* factory,
220 10 : const vector<nacl::string>& prefix,
221 10 : const vector<nacl::string>& sel_ldr_argv)
222 : : factory_(factory),
223 : prefix_(prefix),
224 15 : sel_ldr_argv_(sel_ldr_argv) {
225 5 : NaClLog(1, "ReverseEmulate::ReverseEmulate\n");
226 5 : NaClXMutexCtor(&mu_);
227 10 : }
228 :
229 0 : ReverseEmulate::~ReverseEmulate() {
230 0 : NaClLog(1, "ReverseEmulate::~ReverseEmulate\n");
231 0 : for (size_t ix = 0; ix < subprocesses_.size(); ++ix) {
232 0 : if (subprocesses_[ix].first) {
233 0 : delete subprocesses_[ix].second;
234 0 : subprocesses_[ix].second = NULL;
235 0 : subprocesses_[ix].first = false;
236 0 : }
237 0 : }
238 0 : NaClMutexDtor(&mu_);
239 0 : }
240 :
241 : void ReverseEmulate::StartupInitializationComplete() {
242 1 : NaClLog(1, "ReverseEmulate::StartupInitializationComplete ()\n");
243 1 : }
244 :
245 2 : bool ReverseEmulate::OpenManifestEntry(nacl::string url_key,
246 2 : struct NaClFileInfo* info) {
247 2 : NaClLog(1, "ReverseEmulate::OpenManifestEntry (url_key=%s)\n",
248 2 : url_key.c_str());
249 2 : memset(info, 0, sizeof(*info));
250 2 : info->desc = -1;
251 : // Find the pathname for the key.
252 2 : if (g_key_to_file.find(url_key) == g_key_to_file.end()) {
253 0 : NaClLog(1, "ReverseEmulate::OpenManifestEntry: no pathname for key.\n");
254 0 : return false;
255 : }
256 2 : nacl::string pathname = g_key_to_file[url_key];
257 2 : NaClLog(1, "ReverseEmulate::OpenManifestEntry: pathname is %s.\n",
258 2 : pathname.c_str());
259 : // TODO(ncbray): provide more information so that fast validation caching and
260 : // mmaping can be enabled.
261 6 : info->desc = OPEN(pathname.c_str(), O_RDONLY);
262 2 : return info->desc >= 0;
263 4 : }
264 :
265 : void ReverseEmulate::ReportCrash() {
266 5 : NaClLog(1, "ReverseEmulate::ReportCrash\n");
267 5 : nacl::MutexLocker take(&g_exit_mu);
268 5 : g_exited = true;
269 5 : NaClXCondVarBroadcast(&g_exit_cv);
270 5 : }
271 :
272 2 : void ReverseEmulate::ReportExitStatus(int exit_status) {
273 2 : NaClLog(1, "ReverseEmulate::ReportExitStatus (exit_status=%d)\n",
274 : exit_status);
275 2 : nacl::MutexLocker take(&g_exit_mu);
276 2 : g_exited = true;
277 2 : NaClXCondVarBroadcast(&g_exit_cv);
278 2 : }
279 :
280 0 : void ReverseEmulate::DoPostMessage(nacl::string message) {
281 0 : NaClLog(1, "ReverseEmulate::DoPostMessage (message=%s)\n", message.c_str());
282 0 : }
283 :
284 0 : class CreateProcessBinder : public nacl::CreateProcessFunctorInterface {
285 : public:
286 0 : CreateProcessBinder(nacl::DescWrapper** out_sock_addr,
287 0 : nacl::DescWrapper** out_app_addr,
288 0 : int32_t* out_pid)
289 : : sock_addr_(out_sock_addr)
290 : , app_addr_(out_app_addr)
291 0 : , pid_(out_pid) {}
292 0 : void Results(nacl::DescWrapper* res_sock_addr,
293 0 : nacl::DescWrapper* res_app_addr,
294 0 : int32_t pid) {
295 0 : if (pid >= 0) {
296 0 : *sock_addr_ = res_sock_addr;
297 0 : *app_addr_ = res_app_addr;
298 0 : } else {
299 0 : *sock_addr_ = NULL;
300 0 : *app_addr_ = NULL;
301 : }
302 0 : *pid_ = pid;
303 0 : }
304 : private:
305 : nacl::DescWrapper** sock_addr_;
306 : nacl::DescWrapper** app_addr_;
307 : int32_t* pid_;
308 : };
309 :
310 : // DEPRECATED
311 0 : int ReverseEmulate::CreateProcess(nacl::DescWrapper** out_sock_addr,
312 0 : nacl::DescWrapper** out_app_addr) {
313 0 : NaClLog(1, "ReverseEmulate::CreateProcess)\n");
314 :
315 0 : int32_t pid;
316 :
317 0 : CreateProcessBinder binder(out_sock_addr, out_app_addr, &pid);
318 0 : CreateProcessFunctorResult(&binder);
319 : // race condition here, since we did not take a ref on *out_sock_addr etc
320 : // so until the response is sent, some other thread might unref it.
321 :
322 0 : return (pid < 0) ? pid : 0;
323 0 : }
324 :
325 : void ReverseEmulate::CreateProcessFunctorResult(
326 2 : nacl::CreateProcessFunctorInterface* functor) {
327 2 : NaClLog(1, "ReverseEmulate::CreateProcessFunctorResult)\n");
328 : // We are passing in empty list of application arguments as the real
329 : // arguments should be provided over the command channel.
330 4 : vector<nacl::string> app_argv;
331 :
332 4 : nacl::scoped_ptr<nacl::SelLdrLauncherStandalone> launcher(
333 2 : factory_->MakeSelLdrLauncherStandalone());
334 6 : if (!launcher->StartViaCommandLine(prefix_, sel_ldr_argv_, app_argv)) {
335 0 : NaClLog(LOG_FATAL,
336 : "ReverseEmulate::CreateProcess: failed to launch sel_ldr\n");
337 0 : }
338 6 : if (!launcher->ConnectBootstrapSocket()) {
339 0 : NaClLog(LOG_ERROR,
340 : "ReverseEmulate::CreateProcess:"
341 : " failed to connect boostrap socket\n");
342 0 : functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
343 0 : return;
344 : }
345 :
346 6 : if (!launcher->RetrieveSockAddr()) {
347 0 : NaClLog(LOG_ERROR,
348 : "ReverseEmulate::CreateProcess: failed to obtain socket addr\n");
349 0 : functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
350 0 : return;
351 : }
352 : // We use a 2-phase allocate-then-store scheme so that the process
353 : // slot does not actually hold a copy of the launcher object pointer
354 : // while we might need to use launcher->secure_sock_addr() or
355 : // launcher->socket_addr(). This is because otherwise the untrusted
356 : // code, by guessing pid values, could invoke FinalizeProcess to
357 : // cause the launcher to be deleted, causing the
358 : // launcher->socket_addr() etc expressions to use deallocated
359 : // memory.
360 : //
361 : // This race condition is not currently a real threat. We use
362 : // ReverseEmulate with sel_universal, under which we run tests. All
363 : // tests are written by the NaCl team and are not malicious.
364 : // However, this may change in the future, e.g., use sel_universal
365 : // to analyze in-the-wild NaCl modules.
366 4 : int32_t pid = ReserveProcessSlot();
367 2 : if (pid < 0) {
368 0 : functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
369 0 : }
370 :
371 6 : functor->Results(launcher->secure_socket_addr(),
372 4 : launcher->socket_addr(), pid);
373 4 : SaveToProcessSlot(pid, launcher.release());
374 8 : }
375 :
376 0 : void ReverseEmulate::FinalizeProcess(int32_t pid) {
377 0 : if (!FreeProcessSlot(pid)) {
378 0 : NaClLog(LOG_WARNING, "FinalizeProcess(%d) failed\n", pid);
379 0 : }
380 0 : }
381 :
382 0 : int64_t ReverseEmulate::RequestQuotaForWrite(nacl::string file_id,
383 0 : int64_t offset,
384 0 : int64_t length) {
385 0 : NaClLog(1, "ReverseEmulate::RequestQuotaForWrite (file_id=%s, offset=%"
386 0 : NACL_PRId64 ", length=%" NACL_PRId64 ")\n", file_id.c_str(), offset,
387 : length);
388 0 : return length;
389 : }
390 :
391 : int32_t ReverseEmulate::ReserveProcessSlot() {
392 2 : nacl::MutexLocker take(&mu_);
393 :
394 4 : if (subprocesses_.size() > INT32_MAX) {
395 0 : return -NACL_ABI_EAGAIN;
396 : }
397 2 : int32_t pid;
398 4 : int32_t container_size = static_cast<int32_t>(subprocesses_.size());
399 4 : for (pid = 0; pid < container_size; ++pid) {
400 0 : if (!subprocesses_[pid].first) {
401 0 : break;
402 : }
403 0 : }
404 2 : if (pid == container_size) {
405 : // need to grow
406 2 : if (pid == INT32_MAX) {
407 : // but cannot!
408 0 : return -NACL_ABI_EAGAIN;
409 : }
410 4 : subprocesses_.resize(container_size + 1);
411 2 : }
412 4 : subprocesses_[pid].first = true; // allocated/reserved...
413 4 : subprocesses_[pid].second = NULL; // ... but still not yet in use
414 2 : return pid;
415 2 : }
416 :
417 : void ReverseEmulate::SaveToProcessSlot(
418 2 : int32_t pid,
419 2 : nacl::SelLdrLauncherStandalone *launcher) {
420 2 : nacl::MutexLocker take(&mu_);
421 :
422 10 : CHECK(subprocesses_[pid].first);
423 10 : CHECK(subprocesses_[pid].second == NULL);
424 :
425 4 : subprocesses_[pid].second = launcher;
426 2 : }
427 :
428 0 : bool ReverseEmulate::FreeProcessSlot(int32_t pid) {
429 0 : if (pid < 0) {
430 0 : return false;
431 : }
432 0 : nacl::MutexLocker take(&mu_);
433 0 : CHECK(subprocesses_.size() <= INT32_MAX);
434 0 : int32_t container_size = static_cast<int32_t>(subprocesses_.size());
435 0 : if (pid > container_size) {
436 0 : return false;
437 : }
438 0 : if (!subprocesses_[pid].first || subprocesses_[pid].second == NULL) {
439 0 : return false;
440 : }
441 0 : subprocesses_[pid].first = false;
442 0 : delete subprocesses_[pid].second;
443 0 : subprocesses_[pid].second = NULL;
444 0 : return true;
445 0 : }
|