LLDB  mainline
ProcessLauncherPosixFork.cpp
Go to the documentation of this file.
1 //===-- ProcessLauncherPosixFork.cpp --------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "lldb/Host/Host.h"
11 #include "lldb/Host/HostProcess.h"
12 #include "lldb/Host/Pipe.h"
14 #include "lldb/Utility/FileSpec.h"
15 #include "lldb/Utility/Log.h"
16 #include "llvm/Support/Errno.h"
17 #include "llvm/Support/FileSystem.h"
18 
19 #include <climits>
20 #include <sys/ptrace.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
23 
24 #include <sstream>
25 #include <csignal>
26 
27 #ifdef __ANDROID__
28 #include <android/api-level.h>
29 #define PT_TRACE_ME PTRACE_TRACEME
30 #endif
31 
32 #if defined(__ANDROID_API__) && __ANDROID_API__ < 15
33 #include <linux/personality.h>
34 #elif defined(__linux__)
35 #include <sys/personality.h>
36 #endif
37 
38 using namespace lldb;
39 using namespace lldb_private;
40 
41 // Begin code running in the child process
42 // NB: This code needs to be async-signal safe, since we're invoking fork from
43 // multithreaded contexts.
44 
45 static void write_string(int error_fd, const char *str) {
46  int r = write(error_fd, str, strlen(str));
47  (void)r;
48 }
49 
50 [[noreturn]] static void ExitWithError(int error_fd,
51  const char *operation) {
52  int err = errno;
53  write_string(error_fd, operation);
54  write_string(error_fd, " failed: ");
55  // strerror is not guaranteed to be async-signal safe, but it usually is.
56  write_string(error_fd, strerror(err));
57  _exit(1);
58 }
59 
60 static void DisableASLR(int error_fd) {
61 #if defined(__linux__)
62  const unsigned long personality_get_current = 0xffffffff;
63  int value = personality(personality_get_current);
64  if (value == -1)
65  ExitWithError(error_fd, "personality get");
66 
67  value = personality(ADDR_NO_RANDOMIZE | value);
68  if (value == -1)
69  ExitWithError(error_fd, "personality set");
70 #endif
71 }
72 
73 static void DupDescriptor(int error_fd, const char *file, int fd, int flags) {
74  int target_fd = llvm::sys::RetryAfterSignal(-1, ::open, file, flags, 0666);
75 
76  if (target_fd == -1)
77  ExitWithError(error_fd, "DupDescriptor-open");
78 
79  if (target_fd == fd)
80  return;
81 
82  if (::dup2(target_fd, fd) == -1)
83  ExitWithError(error_fd, "DupDescriptor-dup2");
84 
85  ::close(target_fd);
86 }
87 
88 namespace {
89 struct ForkFileAction {
90  ForkFileAction(const FileAction &act);
91 
92  FileAction::Action action;
93  int fd;
94  std::string path;
95  int arg;
96 };
97 
98 struct ForkLaunchInfo {
99  ForkLaunchInfo(const ProcessLaunchInfo &info);
100 
101  bool separate_process_group;
102  bool debug;
103  bool disable_aslr;
104  std::string wd;
105  const char **argv;
106  Environment::Envp envp;
107  std::vector<ForkFileAction> actions;
108 
109  bool has_action(int fd) const {
110  for (const ForkFileAction &action : actions) {
111  if (action.fd == fd)
112  return true;
113  }
114  return false;
115  }
116 };
117 } // namespace
118 
119 [[noreturn]] static void ChildFunc(int error_fd, const ForkLaunchInfo &info) {
120  if (info.separate_process_group) {
121  if (setpgid(0, 0) != 0)
122  ExitWithError(error_fd, "setpgid");
123  }
124 
125  for (const ForkFileAction &action : info.actions) {
126  switch (action.action) {
127  case FileAction::eFileActionClose:
128  if (close(action.fd) != 0)
129  ExitWithError(error_fd, "close");
130  break;
131  case FileAction::eFileActionDuplicate:
132  if (dup2(action.fd, action.arg) == -1)
133  ExitWithError(error_fd, "dup2");
134  break;
135  case FileAction::eFileActionOpen:
136  DupDescriptor(error_fd, action.path.c_str(), action.fd, action.arg);
137  break;
138  case FileAction::eFileActionNone:
139  break;
140  }
141  }
142 
143  // Change working directory
144  if (!info.wd.empty() && 0 != ::chdir(info.wd.c_str()))
145  ExitWithError(error_fd, "chdir");
146 
147  if (info.disable_aslr)
148  DisableASLR(error_fd);
149 
150  // Clear the signal mask to prevent the child from being affected by any
151  // masking done by the parent.
152  sigset_t set;
153  if (sigemptyset(&set) != 0 ||
154  pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
155  ExitWithError(error_fd, "pthread_sigmask");
156 
157  if (info.debug) {
158  // Do not inherit setgid powers.
159  if (setgid(getgid()) != 0)
160  ExitWithError(error_fd, "setgid");
161 
162  // HACK:
163  // Close everything besides stdin, stdout, and stderr that has no file
164  // action to avoid leaking. Only do this when debugging, as elsewhere we
165  // actually rely on passing open descriptors to child processes.
166  // NB: This code is not async-signal safe, but we currently do not launch
167  // processes for debugging from within multithreaded contexts.
168 
169  const llvm::StringRef proc_fd_path = "/proc/self/fd";
170  std::error_code ec;
171  bool result;
172  ec = llvm::sys::fs::is_directory(proc_fd_path, result);
173  if (result) {
174  std::vector<int> files_to_close;
175  // Directory iterator doesn't ensure any sequence.
176  for (llvm::sys::fs::directory_iterator iter(proc_fd_path, ec), file_end;
177  iter != file_end && !ec; iter.increment(ec)) {
178  int fd = std::stoi(iter->path().substr(proc_fd_path.size() + 1));
179 
180  // Don't close first three entries since they are stdin, stdout and
181  // stderr.
182  if (fd > 2 && !info.has_action(fd) && fd != error_fd)
183  files_to_close.push_back(fd);
184  }
185  for (int file_to_close : files_to_close)
186  close(file_to_close);
187  } else {
188  // Since /proc/self/fd didn't work, trying the slow way instead.
189  int max_fd = sysconf(_SC_OPEN_MAX);
190  for (int fd = 3; fd < max_fd; ++fd)
191  if (!info.has_action(fd) && fd != error_fd)
192  close(fd);
193  }
194 
195  // Start tracing this child that is about to exec.
196  if (ptrace(PT_TRACE_ME, 0, nullptr, 0) == -1)
197  ExitWithError(error_fd, "ptrace");
198  }
199 
200  // Execute. We should never return...
201  execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
202 
203 #if defined(__linux__)
204  if (errno == ETXTBSY) {
205  // On android M and earlier we can get this error because the adb daemon
206  // can hold a write handle on the executable even after it has finished
207  // uploading it. This state lasts only a short time and happens only when
208  // there are many concurrent adb commands being issued, such as when
209  // running the test suite. (The file remains open when someone does an "adb
210  // shell" command in the fork() child before it has had a chance to exec.)
211  // Since this state should clear up quickly, wait a while and then give it
212  // one more go.
213  usleep(50000);
214  execve(info.argv[0], const_cast<char *const *>(info.argv), info.envp);
215  }
216 #endif
217 
218  // ...unless exec fails. In which case we definitely need to end the child
219  // here.
220  ExitWithError(error_fd, "execve");
221 }
222 
223 // End of code running in the child process.
224 
225 ForkFileAction::ForkFileAction(const FileAction &act)
226  : action(act.GetAction()), fd(act.GetFD()), path(act.GetPath().str()),
227  arg(act.GetActionArgument()) {}
228 
229 static std::vector<ForkFileAction>
231  std::vector<ForkFileAction> result;
232  for (size_t i = 0; i < info.GetNumFileActions(); ++i)
233  result.emplace_back(*info.GetFileActionAtIndex(i));
234  return result;
235 }
236 
238 #ifdef __ANDROID__
239  // If there is no PATH variable specified inside the environment then set the
240  // path to /system/bin. It is required because the default path used by
241  // execve() is wrong on android.
242  env.try_emplace("PATH", "/system/bin");
243 #endif
244  return env.getEnvp();
245 }
246 
247 ForkLaunchInfo::ForkLaunchInfo(const ProcessLaunchInfo &info)
248  : separate_process_group(
249  info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)),
250  debug(info.GetFlags().Test(eLaunchFlagDebug)),
251  disable_aslr(info.GetFlags().Test(eLaunchFlagDisableASLR)),
252  wd(info.GetWorkingDirectory().GetPath()),
253  argv(info.GetArguments().GetConstArgumentVector()),
254  envp(FixupEnvironment(info.GetEnvironment())),
255  actions(MakeForkActions(info)) {}
256 
258 ProcessLauncherPosixFork::LaunchProcess(const ProcessLaunchInfo &launch_info,
259  Status &error) {
260  // A pipe used by the child process to report errors.
261  PipePosix pipe;
262  const bool child_processes_inherit = false;
263  error = pipe.CreateNew(child_processes_inherit);
264  if (error.Fail())
265  return HostProcess();
266 
267  const ForkLaunchInfo fork_launch_info(launch_info);
268 
269  ::pid_t pid = ::fork();
270  if (pid == -1) {
271  // Fork failed
272  error.SetErrorStringWithFormatv("Fork failed with error message: {0}",
273  llvm::sys::StrError());
275  }
276  if (pid == 0) {
277  // child process
278  pipe.CloseReadFileDescriptor();
279  ChildFunc(pipe.ReleaseWriteFileDescriptor(), fork_launch_info);
280  }
281 
282  // parent process
283 
284  pipe.CloseWriteFileDescriptor();
285  char buf[1000];
286  int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);
287 
288  if (r == 0)
289  return HostProcess(pid); // No error. We're done.
290 
291  error.SetErrorString(buf);
292 
293  llvm::sys::RetryAfterSignal(-1, waitpid, pid, nullptr, 0);
294 
295  return HostProcess();
296 }
lldb_private::HostProcess
Definition: HostProcess.h:33
LLDB_INVALID_PROCESS_ID
#define LLDB_INVALID_PROCESS_ID
Definition: lldb-defines.h:81
Host.h
lldb_private::Environment::Envp
Definition: Environment.h:22
ProcessLaunchInfo.h
HostProcess.h
lldb_private::FileAction
Definition: FileAction.h:17
write_string
static void write_string(int error_fd, const char *str)
Definition: ProcessLauncherPosixFork.cpp:45
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::ProcessLaunchInfo
Definition: ProcessLaunchInfo.h:31
Log.h
FixupEnvironment
static Environment::Envp FixupEnvironment(Environment env)
Definition: ProcessLauncherPosixFork.cpp:237
lldb_private::ProcessLaunchInfo::GetFileActionAtIndex
const FileAction * GetFileActionAtIndex(size_t idx) const
Definition: ProcessLaunchInfo.cpp:109
lldb_private::Environment::getEnvp
Envp getEnvp() const
Definition: Environment.h:78
Pipe.h
ChildFunc
static void ChildFunc(int error_fd, const ForkLaunchInfo &info)
Definition: ProcessLauncherPosixFork.cpp:119
lldb_private::ProcessLaunchInfo::GetNumFileActions
size_t GetNumFileActions() const
Definition: ProcessLaunchInfo.h:58
set
set(option_framework FRAMEWORK) endif() if(LLDB_ENABLE_PYTHON) get_target_property(python_bindings_dir swig_wrapper_python BINARY_DIR) set(lldb_python_wrapper $
Definition: API/CMakeLists.txt:5
string
string(SUBSTRING ${p} 10 -1 pStripped) if($
Definition: Plugins/CMakeLists.txt:40
lldb_private::Status
Definition: Status.h:44
lldb::pid_t
uint64_t pid_t
Definition: lldb-types.h:85
lldb_private::FileAction::Action
Action
Definition: FileAction.h:19
lldb_private::Environment
Definition: Environment.h:18
DupDescriptor
static void DupDescriptor(int error_fd, const char *file, int fd, int flags)
Definition: ProcessLauncherPosixFork.cpp:73
ExitWithError
static void ExitWithError(int error_fd, const char *operation)
Definition: ProcessLauncherPosixFork.cpp:50
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
fork
pid_t fork(void)
Definition: windows/PosixApi.h:96
FileSpec.h
MakeForkActions
static std::vector< ForkFileAction > MakeForkActions(const ProcessLaunchInfo &info)
Definition: ProcessLauncherPosixFork.cpp:230
DisableASLR
static void DisableASLR(int error_fd)
Definition: ProcessLauncherPosixFork.cpp:60
lldb
Definition: SBAddress.h:15
ProcessLauncherPosixFork.h