1 : /*
2 : * Copyright (c) 2012 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 :
8 : #include <sys/types.h>
9 : #include <sys/wait.h>
10 :
11 : #include <assert.h>
12 : #include <fcntl.h>
13 : #include <libgen.h>
14 : #include <signal.h>
15 : #include <stdio.h>
16 : #include <string.h>
17 : #include <sys/param.h>
18 : #include <unistd.h>
19 :
20 : #include "native_client/src/include/nacl_macros.h"
21 : #include "native_client/src/include/nacl_string.h"
22 : #include "native_client/src/shared/platform/nacl_check.h"
23 : #include "native_client/src/shared/platform/nacl_exit.h"
24 : #include "native_client/src/shared/platform/nacl_log.h"
25 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
26 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
27 :
28 :
29 : using std::vector;
30 :
31 : namespace nacl {
32 :
33 13 : SelLdrLauncherStandalone::~SelLdrLauncherStandalone() {
34 13 : CloseHandlesAfterLaunch();
35 13 : if (NACL_INVALID_HANDLE != child_process_) {
36 13 : int status;
37 : // Ensure child process (service runtime) is kaput. NB: we might
38 : // close the command channel (or use the hard_shutdown RPC) rather
39 : // than killing the process to allow the service runtime to do
40 : // clean up, but the plugin should be responsible for that and we
41 : // shouldn't introduce any timeout wait in a dtor. Currently,
42 : // ServiceRuntime::Shutdown kills the subprocess before closing
43 : // the command channel, so we aren't providing the opportunity for
44 : // a more graceful shutdown.
45 13 : KillChildProcess();
46 13 : waitpid(child_process_, &status, 0);
47 13 : }
48 104 : }
49 :
50 :
51 : nacl::string SelLdrLauncherStandalone::GetSelLdrPathName() {
52 0 : char buffer[FILENAME_MAX];
53 0 : GetPluginDirectory(buffer, sizeof(buffer));
54 0 : return nacl::string(buffer) + "/sel_ldr";
55 0 : }
56 :
57 : nacl::string SelLdrLauncherStandalone::GetSelLdrBootstrapPathName() {
58 : #if NACL_LINUX
59 : char buffer[FILENAME_MAX];
60 : GetPluginDirectory(buffer, sizeof(buffer));
61 : return nacl::string(buffer) + "/nacl_helper_bootstrap";
62 : #else
63 0 : return nacl::string(NACL_NO_FILE_PATH);
64 : #endif
65 0 : }
66 :
67 : NaClHandle SelLdrLauncherStandalone::CreateBootstrapSocket(
68 0 : nacl::string* dest_fd) {
69 0 : NaClHandle pair[2];
70 0 : if (NaClSocketPair(pair) == -1) {
71 0 : return NACL_INVALID_HANDLE;
72 : }
73 :
74 0 : int rc = fcntl(pair[0], F_SETFD, FD_CLOEXEC);
75 0 : CHECK(rc == 0);
76 0 : close_after_launch_.push_back(pair[1]);
77 :
78 0 : *dest_fd = ToString(pair[1]);
79 0 : return pair[0];
80 0 : }
81 :
82 : const size_t kMaxExecArgs = 64;
83 :
84 : bool SelLdrLauncherStandalone::StartViaCommandLine(
85 0 : const vector<nacl::string>& prefix,
86 0 : const vector<nacl::string>& sel_ldr_argv,
87 0 : const vector<nacl::string>& app_argv) {
88 : // Set up the command line.
89 0 : InitCommandLine(prefix, sel_ldr_argv, app_argv);
90 : // complete command line setup
91 0 : vector<nacl::string> command;
92 0 : BuildCommandLine(&command);
93 0 : if (kMaxExecArgs <= command.size()) {
94 : // TODO(robertm): emit error message
95 0 : return false;
96 : }
97 : // Set environment variable to keep the Mac sel_ldr from stealing the focus.
98 : // TODO(sehr): change this to use a command line parameter rather than env.
99 0 : setenv("NACL_LAUNCHED_FROM_BROWSER", "1", 0);
100 : // Fork the sel_ldr process.
101 0 : child_process_ = fork();
102 0 : if (child_process_ == -1) {
103 0 : return false;
104 : }
105 :
106 0 : if (child_process_ == 0) {
107 : // convert vector -> array assuming no more than kMaxArgs
108 : // NOTE: we also check this above so the assert should never fire
109 0 : assert(command.size() < kMaxExecArgs);
110 0 : const char* argv[kMaxExecArgs];
111 0 : for (size_t i = 0; i < command.size(); ++i) {
112 0 : argv[i] = command[i].c_str();
113 0 : }
114 0 : argv[command.size()] = NULL;
115 :
116 0 : execv(argv[0], const_cast<char**>(argv));
117 0 : NaClLog(LOG_ERROR, "execv failed, args were:\n");
118 0 : for (size_t i = 0; i < command.size(); ++i) {
119 0 : NaClLog(LOG_ERROR, "%s\n", argv[i]);
120 0 : }
121 0 : perror("execv");
122 0 : NaClExit(EXIT_FAILURE);
123 0 : }
124 0 : CloseHandlesAfterLaunch();
125 0 : return true;
126 0 : }
127 :
128 : bool SelLdrLauncherStandalone::KillChildProcess() {
129 13 : if (NACL_INVALID_HANDLE == child_process_) {
130 : // It is incorrect to use the kill syscall on NACL_INVALID_HANDLE
131 : // as the pid, since using -1 as pid is defined by POSIX.1-2001 to
132 : // send the signal (SIGKILL) to every process that the calling
133 : // process may send signals to (except for init), which is
134 : // Definitely Not What Was Intended for this.
135 0 : return true;
136 : }
137 13 : return 0 == kill(child_process_, SIGKILL);
138 : // We cannot set child_process_ to NACL_INVALID_HANDLE since we will
139 : // want to wait on its exit status.
140 13 : }
141 :
142 : } // namespace nacl
|