1 : /*
2 : * Copyright (c) 2011 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 11 : SelLdrLauncher::~SelLdrLauncher() {
34 11 : CloseHandlesAfterLaunch();
35 11 : if (kInvalidHandle != child_process_) {
36 : 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 10 : KillChildProcess();
46 10 : waitpid(child_process_, &status, 0);
47 : }
48 11 : if (kInvalidHandle != channel_) {
49 0 : Close(channel_);
50 : }
51 11 : }
52 :
53 :
54 0 : nacl::string SelLdrLauncher::GetSelLdrPathName() {
55 : char buffer[FILENAME_MAX];
56 0 : GetPluginDirectory(buffer, sizeof(buffer));
57 0 : return nacl::string(buffer) + "/sel_ldr";
58 : }
59 :
60 12 : nacl::string SelLdrLauncher::GetSelLdrBootstrapPathName() {
61 : #if NACL_LINUX
62 : char buffer[FILENAME_MAX];
63 : GetPluginDirectory(buffer, sizeof(buffer));
64 : return nacl::string(buffer) + "/nacl_helper_bootstrap";
65 : #else
66 12 : return nacl::string(NACL_NO_FILE_PATH);
67 : #endif
68 : }
69 :
70 11 : Handle SelLdrLauncher::ExportImcFD(int dest_fd) {
71 : Handle pair[2];
72 11 : if (SocketPair(pair) == -1) {
73 0 : return kInvalidHandle;
74 : }
75 :
76 11 : int rc = fcntl(pair[0], F_SETFD, FD_CLOEXEC);
77 11 : CHECK(rc == 0);
78 11 : close_after_launch_.push_back(pair[1]);
79 :
80 11 : sel_ldr_argv_.push_back("-i");
81 22 : sel_ldr_argv_.push_back(ToString(dest_fd) + ":" + ToString(pair[1]));
82 11 : return pair[0];
83 : }
84 :
85 : const size_t kMaxExecArgs = 64;
86 :
87 11 : bool SelLdrLauncher::LaunchFromCommandLine() {
88 11 : if (channel_number_ != -1) {
89 11 : channel_ = ExportImcFD(channel_number_);
90 : }
91 :
92 : // complete command line setup
93 11 : vector<nacl::string> command;
94 11 : BuildCommandLine(&command);
95 11 : if (kMaxExecArgs <= command.size()) {
96 : // TODO(robertm): emit error message
97 0 : return false;
98 : }
99 : // Set environment variable to keep the Mac sel_ldr from stealing the focus.
100 : // TODO(sehr): change this to use a command line parameter rather than env.
101 11 : setenv("NACL_LAUNCHED_FROM_BROWSER", "1", 0);
102 : // Fork the sel_ldr process.
103 11 : child_process_ = fork();
104 11 : if (child_process_ == -1) {
105 0 : return false;
106 : }
107 :
108 11 : if (child_process_ == 0) {
109 : // convert vector -> array assuming no more than kMaxArgs
110 : // NOTE: we also check this above so the assert should never fire
111 0 : assert(command.size() < kMaxExecArgs);
112 : const char* argv[kMaxExecArgs];
113 0 : for (size_t i = 0; i < command.size(); ++i) {
114 0 : argv[i] = command[i].c_str();
115 : }
116 0 : argv[command.size()] = NULL;
117 :
118 0 : execv(argv[0], const_cast<char**>(argv));
119 0 : NaClLog(LOG_ERROR, "execv failed, args were:\n");
120 0 : for (size_t i = 0; i < command.size(); ++i) {
121 0 : NaClLog(LOG_ERROR, "%s\n", argv[i]);
122 : }
123 0 : perror("execv");
124 0 : NaClExit(EXIT_FAILURE);
125 : }
126 11 : CloseHandlesAfterLaunch();
127 11 : return true;
128 : }
129 :
130 10 : bool SelLdrLauncher::KillChildProcess() {
131 10 : if (kInvalidHandle == child_process_) {
132 : // It is incorrect to use the kill syscall on kInvalidHandle as
133 : // the pid, since using -1 as pid is defined by POSIX.1-2001 to
134 : // send the signal (SIGKILL) to every process that the calling
135 : // process may send signals to (except for init), which is
136 : // Definitely Not What Was Intended for this.
137 0 : return true;
138 : }
139 10 : return 0 == kill(child_process_, SIGKILL);
140 : // We cannot set child_process_ to kInvalidHandle since we will want to wait
141 : // on its exit status.
142 : }
143 :
144 : } // namespace nacl
|