Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / sel_universal / reverse_emulate.cc
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/secure_service.h"
17 #include "native_client/src/shared/platform/nacl_check.h"
18 #include "native_client/src/shared/platform/nacl_log.h"
19 #include "native_client/src/shared/platform/nacl_sync.h"
20 #include "native_client/src/shared/platform/nacl_sync_checked.h"
21 #include "native_client/src/shared/platform/nacl_sync_raii.h"
22 #include "native_client/src/shared/platform/nacl_threads.h"
23 #include "native_client/src/shared/platform/scoped_ptr_refcount.h"
24 #include "native_client/src/shared/srpc/nacl_srpc.h"
25 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
26 #include "native_client/src/trusted/nonnacl_util/launcher_factory.h"
27 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
28 #include "native_client/src/trusted/reverse_service/reverse_service.h"
29 #include "native_client/src/trusted/sel_universal/rpc_universal.h"
30 #include "native_client/src/trusted/sel_universal/srpc_helper.h"
31 #include "native_client/src/trusted/validator/nacl_file_info.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     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 KeyToFileMap g_key_to_file;
100
101 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 bool ReverseEmulateInit(NaClSrpcChannel* command_channel,
117                         nacl::SelLdrLauncherStandalone* launcher,
118                         nacl::SelLdrLauncherStandaloneFactory* factory,
119                         const std::vector<nacl::string>& prefix,
120                         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   NaClLog(1, "ReverseEmulateInit: launching reverse RPC service\n");
124   NaClDesc* h;
125   NaClSrpcResultCodes rpc_result =
126       NaClSrpcInvokeBySignature(command_channel,
127                                 NACL_SECURE_SERVICE_REVERSE_SETUP,
128                                 &h);
129   if (NACL_SRPC_RESULT_OK != rpc_result) {
130     NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse setup failed\n");
131     return false;
132   }
133   // Make a nacl::DescWrapper* from the NaClDesc*
134   nacl::scoped_ptr<nacl::DescWrapper> conn_cap(launcher->WrapCleanup(h));
135   if (conn_cap == NULL) {
136     NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse desc wrap failed\n");
137     return false;
138   }
139   // The implementation of the ReverseInterface is our emulator class.
140   nacl::scoped_ptr<ReverseEmulate> reverse_interface(new ReverseEmulate(
141         factory, prefix, sel_ldr_argv));
142   // Construct locks guarding exit status.
143   NaClXMutexCtor(&g_exit_mu);
144   NaClXCondVarCtor(&g_exit_cv);
145   g_exited = false;
146   // Create an instance of ReverseService, which connects to the socket
147   // address and exports the services from our emulator.
148   g_reverse_service.reset(new nacl::ReverseService(conn_cap.get(),
149                                                    reverse_interface->Ref()));
150   if (g_reverse_service == NULL) {
151     NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse service ctor failed\n");
152     return false;
153   }
154   // Successful creation of ReverseService took ownership of these.
155   reverse_interface.release();
156   conn_cap.release();
157   // Starts the RPC handler for the reverse interface.
158   if (!g_reverse_service->Start()) {
159     NaClLog(LOG_ERROR, "ReverseEmulateInit: reverse service start failed\n");
160     return false;
161   }
162   return true;
163 }
164
165 void ReverseEmulateFini() {
166   CHECK(g_reverse_service != NULL);
167   NaClLog(1, "Waiting for service threads to exit...\n");
168   g_reverse_service->WaitForServiceThreadsToExit();
169   NaClLog(1, "...service threads done\n");
170   g_reverse_service.reset(NULL);
171   NaClMutexDtor(&g_exit_mu);
172   NaClCondVarDtor(&g_exit_cv);
173 }
174
175 bool HandlerReverseEmuAddManifestMapping(NaClCommandLoop* ncl,
176                                          const std::vector<string>& args) {
177   UNREFERENCED_PARAMETER(ncl);
178   if (args.size() < 3) {
179     NaClLog(LOG_ERROR, "not enough args\n");
180     return false;
181   }
182   NaClLog(1, "HandlerReverseEmulateAddManifestMapping(%s) -> %s\n",
183           args[1].c_str(), args[2].c_str());
184   // Set the mapping for the key.
185   g_key_to_file[args[1]] = args[2];
186   return true;
187 }
188
189 bool HandlerReverseEmuDumpManifestMappings(NaClCommandLoop* ncl,
190                                            const std::vector<string>& args) {
191   UNREFERENCED_PARAMETER(ncl);
192   if (args.size() != 1) {
193     NaClLog(LOG_ERROR, "unexpected args\n");
194     return false;
195   }
196   printf("ReverseEmulate manifest mappings:\n");
197   for (KeyToFileMap::iterator i = g_key_to_file.begin();
198        i != g_key_to_file.end();
199        ++i) {
200     printf("'%s': '%s'\n", i->first.c_str(), i->second.c_str());
201   }
202   return true;
203 }
204
205 bool HandlerWaitForExit(NaClCommandLoop* ncl,
206                         const std::vector<string>& args) {
207   UNREFERENCED_PARAMETER(ncl);
208   UNREFERENCED_PARAMETER(args);
209
210   nacl::MutexLocker take(&g_exit_mu);
211   while (!g_exited) {
212     NaClXCondVarWait(&g_exit_cv, &g_exit_mu);
213   }
214
215   return true;
216 }
217
218 ReverseEmulate::ReverseEmulate(
219     nacl::SelLdrLauncherStandaloneFactory* factory,
220     const vector<nacl::string>& prefix,
221     const vector<nacl::string>& sel_ldr_argv)
222   : factory_(factory),
223     prefix_(prefix),
224     sel_ldr_argv_(sel_ldr_argv) {
225   NaClLog(1, "ReverseEmulate::ReverseEmulate\n");
226   NaClXMutexCtor(&mu_);
227 }
228
229 ReverseEmulate::~ReverseEmulate() {
230   NaClLog(1, "ReverseEmulate::~ReverseEmulate\n");
231   for (size_t ix = 0; ix < subprocesses_.size(); ++ix) {
232     if (subprocesses_[ix].first) {
233       delete subprocesses_[ix].second;
234       subprocesses_[ix].second = NULL;
235       subprocesses_[ix].first = false;
236     }
237   }
238   NaClMutexDtor(&mu_);
239 }
240
241 void ReverseEmulate::StartupInitializationComplete() {
242   NaClLog(1, "ReverseEmulate::StartupInitializationComplete ()\n");
243 }
244
245 bool ReverseEmulate::OpenManifestEntry(nacl::string url_key,
246                                        struct NaClFileInfo* info) {
247   NaClLog(1, "ReverseEmulate::OpenManifestEntry (url_key=%s)\n",
248           url_key.c_str());
249   memset(info, 0, sizeof(*info));
250   info->desc = -1;
251   // Find the pathname for the key.
252   if (g_key_to_file.find(url_key) == g_key_to_file.end()) {
253     NaClLog(1, "ReverseEmulate::OpenManifestEntry: no pathname for key.\n");
254     return false;
255   }
256   nacl::string pathname = g_key_to_file[url_key];
257   NaClLog(1, "ReverseEmulate::OpenManifestEntry: pathname is %s.\n",
258           pathname.c_str());
259   // TODO(ncbray): provide more information so that fast validation caching and
260   // mmaping can be enabled.
261   info->desc = OPEN(pathname.c_str(), O_RDONLY);
262   return info->desc >= 0;
263 }
264
265 void ReverseEmulate::ReportCrash() {
266   NaClLog(1, "ReverseEmulate::ReportCrash\n");
267   nacl::MutexLocker take(&g_exit_mu);
268   g_exited = true;
269   NaClXCondVarBroadcast(&g_exit_cv);
270 }
271
272 void ReverseEmulate::ReportExitStatus(int exit_status) {
273   NaClLog(1, "ReverseEmulate::ReportExitStatus (exit_status=%d)\n",
274           exit_status);
275   nacl::MutexLocker take(&g_exit_mu);
276   g_exited = true;
277   NaClXCondVarBroadcast(&g_exit_cv);
278 }
279
280 void ReverseEmulate::DoPostMessage(nacl::string message) {
281   NaClLog(1, "ReverseEmulate::DoPostMessage (message=%s)\n", message.c_str());
282 }
283
284 class CreateProcessBinder : public nacl::CreateProcessFunctorInterface {
285  public:
286   CreateProcessBinder(nacl::DescWrapper** out_sock_addr,
287                       nacl::DescWrapper** out_app_addr,
288                       int32_t* out_pid)
289       : sock_addr_(out_sock_addr)
290       , app_addr_(out_app_addr)
291       , pid_(out_pid) {}
292   void Results(nacl::DescWrapper* res_sock_addr,
293                nacl::DescWrapper* res_app_addr,
294                int32_t pid) {
295     if (pid >= 0) {
296       *sock_addr_ = res_sock_addr;
297       *app_addr_ = res_app_addr;
298     } else {
299       *sock_addr_ = NULL;
300       *app_addr_ = NULL;
301     }
302     *pid_ = pid;
303   }
304  private:
305   nacl::DescWrapper** sock_addr_;
306   nacl::DescWrapper** app_addr_;
307   int32_t* pid_;
308 };
309
310 // DEPRECATED
311 int ReverseEmulate::CreateProcess(nacl::DescWrapper** out_sock_addr,
312                                   nacl::DescWrapper** out_app_addr) {
313   NaClLog(1, "ReverseEmulate::CreateProcess)\n");
314
315   int32_t pid;
316
317   CreateProcessBinder binder(out_sock_addr, out_app_addr, &pid);
318   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   return (pid < 0) ? pid : 0;
323 }
324
325 void ReverseEmulate::CreateProcessFunctorResult(
326     nacl::CreateProcessFunctorInterface* functor) {
327   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   vector<nacl::string> app_argv;
331
332   nacl::scoped_ptr<nacl::SelLdrLauncherStandalone> launcher(
333       factory_->MakeSelLdrLauncherStandalone());
334   if (!launcher->StartViaCommandLine(prefix_, sel_ldr_argv_, app_argv)) {
335     NaClLog(LOG_FATAL,
336             "ReverseEmulate::CreateProcess: failed to launch sel_ldr\n");
337   }
338   if (!launcher->ConnectBootstrapSocket()) {
339     NaClLog(LOG_ERROR,
340             "ReverseEmulate::CreateProcess:"
341             " failed to connect boostrap socket\n");
342     functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
343     return;
344   }
345
346   if (!launcher->RetrieveSockAddr()) {
347     NaClLog(LOG_ERROR,
348             "ReverseEmulate::CreateProcess: failed to obtain socket addr\n");
349     functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
350     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   int32_t pid = ReserveProcessSlot();
367   if (pid < 0) {
368     functor->Results(NULL, NULL, -NACL_ABI_EAGAIN);
369   }
370
371   functor->Results(launcher->secure_socket_addr(),
372                    launcher->socket_addr(), pid);
373   SaveToProcessSlot(pid, launcher.release());
374 }
375
376 void ReverseEmulate::FinalizeProcess(int32_t pid) {
377   if (!FreeProcessSlot(pid)) {
378     NaClLog(LOG_WARNING, "FinalizeProcess(%d) failed\n", pid);
379   }
380 }
381
382 int64_t ReverseEmulate::RequestQuotaForWrite(nacl::string file_id,
383                                              int64_t offset,
384                                              int64_t length) {
385   NaClLog(1, "ReverseEmulate::RequestQuotaForWrite (file_id=%s, offset=%"
386           NACL_PRId64 ", length=%" NACL_PRId64 ")\n", file_id.c_str(), offset,
387           length);
388   return length;
389 }
390
391 int32_t ReverseEmulate::ReserveProcessSlot() {
392   nacl::MutexLocker take(&mu_);
393
394   if (subprocesses_.size() > INT32_MAX) {
395     return -NACL_ABI_EAGAIN;
396   }
397   int32_t pid;
398   int32_t container_size = static_cast<int32_t>(subprocesses_.size());
399   for (pid = 0; pid < container_size; ++pid) {
400     if (!subprocesses_[pid].first) {
401       break;
402     }
403   }
404   if (pid == container_size) {
405     // need to grow
406     if (pid == INT32_MAX) {
407       // but cannot!
408       return -NACL_ABI_EAGAIN;
409     }
410     subprocesses_.resize(container_size + 1);
411   }
412   subprocesses_[pid].first = true;   // allocated/reserved...
413   subprocesses_[pid].second = NULL;  // ... but still not yet in use
414   return pid;
415 }
416
417 void ReverseEmulate::SaveToProcessSlot(
418     int32_t pid,
419     nacl::SelLdrLauncherStandalone *launcher) {
420   nacl::MutexLocker take(&mu_);
421
422   CHECK(subprocesses_[pid].first);
423   CHECK(subprocesses_[pid].second == NULL);
424
425   subprocesses_[pid].second = launcher;
426 }
427
428 bool ReverseEmulate::FreeProcessSlot(int32_t pid) {
429   if (pid < 0) {
430     return false;
431   }
432   nacl::MutexLocker take(&mu_);
433   CHECK(subprocesses_.size() <= INT32_MAX);
434   int32_t container_size = static_cast<int32_t>(subprocesses_.size());
435   if (pid > container_size) {
436     return false;
437   }
438   if (!subprocesses_[pid].first || subprocesses_[pid].second == NULL) {
439     return false;
440   }
441   subprocesses_[pid].first = false;
442   delete subprocesses_[pid].second;
443   subprocesses_[pid].second = NULL;
444   return true;
445 }