LCOV - code coverage report
Current view: directory - src/trusted/sel_universal - reverse_emulate.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 226 121 53.5 %
Date: 2014-06-18 Functions: 0 0 -

       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 : }

Generated by: LCOV version 1.7