1//===-- DarwinProcessLauncher.cpp -------------------------------*- C++ -*-===//
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
9//
10//  DarwinProcessLauncher.cpp
11//  lldb
12//
13//  Created by Todd Fiala on 8/30/16.
14//
15//
16
17#include "DarwinProcessLauncher.h"
18
19// C includes
20#include <spawn.h>
21#include <sys/ptrace.h>
22#include <sys/stat.h>
23#include <sys/sysctl.h>
24
25#ifndef _POSIX_SPAWN_DISABLE_ASLR
26#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
27#endif
28
29// LLDB includes
30#include "lldb/lldb-enumerations.h"
31
32#include "lldb/Host/PseudoTerminal.h"
33#include "lldb/Target/ProcessLaunchInfo.h"
34#include "lldb/Utility/Log.h"
35#include "lldb/Utility/Status.h"
36#include "lldb/Utility/StreamString.h"
37#include "llvm/Support/Errno.h"
38
39#include "CFBundle.h"
40#include "CFString.h"
41
42using namespace lldb;
43using namespace lldb_private;
44using namespace lldb_private::process_darwin;
45using namespace lldb_private::darwin_process_launcher;
46
47namespace {
48static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
49}
50
51namespace lldb_private {
52namespace darwin_process_launcher {
53
54static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) {
55  int mib[CTL_MAXNAME] = {
56      0,
57  };
58  size_t len = CTL_MAXNAME;
59  if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
60    return 0;
61
62  mib[len] = pid;
63  len++;
64
65  cpu_type_t cpu;
66  size_t cpu_len = sizeof(cpu);
67  if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
68    cpu = 0;
69  return cpu;
70}
71
72static bool ResolveExecutablePath(const char *path, char *resolved_path,
73                                  size_t resolved_path_size) {
74  if (path == NULL || path[0] == '\0')
75    return false;
76
77  char max_path[PATH_MAX];
78  std::string result;
79  CFString::GlobPath(path, result);
80
81  if (result.empty())
82    result = path;
83
84  struct stat path_stat;
85  if (::stat(path, &path_stat) == 0) {
86    if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
87      CFBundle bundle(path);
88      CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
89      if (url.get()) {
90        if (::CFURLGetFileSystemRepresentation(
91                url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
92          return true;
93      }
94    }
95  }
96
97  if (realpath(path, max_path)) {
98    // Found the path relatively...
99    ::strncpy(resolved_path, max_path, resolved_path_size);
100    return strlen(resolved_path) + 1 < resolved_path_size;
101  } else {
102    // Not a relative path, check the PATH environment variable if the
103    const char *PATH = getenv("PATH");
104    if (PATH) {
105      const char *curr_path_start = PATH;
106      const char *curr_path_end;
107      while (curr_path_start && *curr_path_start) {
108        curr_path_end = strchr(curr_path_start, ':');
109        if (curr_path_end == NULL) {
110          result.assign(curr_path_start);
111          curr_path_start = NULL;
112        } else if (curr_path_end > curr_path_start) {
113          size_t len = curr_path_end - curr_path_start;
114          result.assign(curr_path_start, len);
115          curr_path_start += len + 1;
116        } else
117          break;
118
119        result += '/';
120        result += path;
121        struct stat s;
122        if (stat(result.c_str(), &s) == 0) {
123          ::strncpy(resolved_path, result.c_str(), resolved_path_size);
124          return result.size() + 1 < resolved_path_size;
125        }
126      }
127    }
128  }
129  return false;
130}
131
132// TODO check if we have a general purpose fork and exec.  We may be
133// able to get rid of this entirely.
134static Status ForkChildForPTraceDebugging(const char *path, char const *argv[],
135                                          char const *envp[], ::pid_t *pid,
136                                          int *pty_fd) {
137  Status error;
138  if (!path || !argv || !envp || !pid || !pty_fd) {
139    error.SetErrorString("invalid arguments");
140    return error;
141  }
142
143  // Use a fork that ties the child process's stdin/out/err to a pseudo
144  // terminal so we can read it in our MachProcess::STDIOThread as unbuffered
145  // io.
146  PseudoTerminal pty;
147  char fork_error[256];
148  memset(fork_error, 0, sizeof(fork_error));
149  *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error)));
150  if (*pid < 0) {
151    // Status during fork.
152    *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
153    error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
154                                   fork_error);
155    return error;
156  } else if (pid == 0) {
157    // Child process
158
159    // Debug this process.
160    ::ptrace(PT_TRACE_ME, 0, 0, 0);
161
162    // Get BSD signals as mach exceptions.
163    ::ptrace(PT_SIGEXC, 0, 0, 0);
164
165    // If our parent is setgid, lets make sure we don't inherit those extra
166    // powers due to nepotism.
167    if (::setgid(getgid()) == 0) {
168      // Let the child have its own process group. We need to execute this call
169      // in both the child and parent to avoid a race condition between the two
170      // processes.
171
172      // Set the child process group to match its pid.
173      ::setpgid(0, 0);
174
175      // Sleep a bit to before the exec call.
176      ::sleep(1);
177
178      // Turn this process into the given executable.
179      ::execv(path, (char *const *)argv);
180    }
181    // Exit with error code. Child process should have taken over in above exec
182    // call and if the exec fails it will exit the child process below.
183    ::exit(127);
184  } else {
185    // Parent process
186    // Let the child have its own process group. We need to execute this call
187    // in both the child and parent to avoid a race condition between the two
188    // processes.
189
190    // Set the child process group to match its pid
191    ::setpgid(*pid, *pid);
192    if (pty_fd) {
193      // Release our master pty file descriptor so the pty class doesn't close
194      // it and so we can continue to use it in our STDIO thread
195      *pty_fd = pty.ReleaseMasterFileDescriptor();
196    }
197  }
198  return error;
199}
200
201static Status
202CreatePosixSpawnFileAction(const FileAction &action,
203                           posix_spawn_file_actions_t *file_actions) {
204  Status error;
205
206  // Log it.
207  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
208  if (log) {
209    StreamString stream;
210    stream.PutCString("converting file action for posix_spawn(): ");
211    action.Dump(stream);
212    stream.Flush();
213    log->PutCString(stream.GetString().c_str());
214  }
215
216  // Validate args.
217  if (!file_actions) {
218    error.SetErrorString("mandatory file_actions arg is null");
219    return error;
220  }
221
222  // Build the posix file action.
223  switch (action.GetAction()) {
224  case FileAction::eFileActionOpen: {
225    const int error_code = ::posix_spawn_file_actions_addopen(
226        file_actions, action.GetFD(), action.GetPath(),
227        action.GetActionArgument(), 0);
228    if (error_code != 0) {
229      error.SetError(error_code, eErrorTypePOSIX);
230      return error;
231    }
232    break;
233  }
234
235  case FileAction::eFileActionClose: {
236    const int error_code =
237        ::posix_spawn_file_actions_addclose(file_actions, action.GetFD());
238    if (error_code != 0) {
239      error.SetError(error_code, eErrorTypePOSIX);
240      return error;
241    }
242    break;
243  }
244
245  case FileAction::eFileActionDuplicate: {
246    const int error_code = ::posix_spawn_file_actions_adddup2(
247        file_actions, action.GetFD(), action.GetActionArgument());
248    if (error_code != 0) {
249      error.SetError(error_code, eErrorTypePOSIX);
250      return error;
251    }
252    break;
253  }
254
255  case FileAction::eFileActionNone:
256  default:
257    LLDB_LOGF(log, "%s(): unsupported file action %u", __FUNCTION__,
258              action.GetAction());
259    break;
260  }
261
262  return error;
263}
264
265static Status PosixSpawnChildForPTraceDebugging(const char *path,
266                                                ProcessLaunchInfo &launch_info,
267                                                ::pid_t *pid,
268                                                cpu_type_t *actual_cpu_type) {
269  Status error;
270  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
271
272  if (!pid) {
273    error.SetErrorStringWithFormat("%s(): pid arg cannot be null",
274                                   __FUNCTION__);
275    return error;
276  }
277
278  posix_spawnattr_t attr;
279  short flags;
280  if (log) {
281    StreamString stream;
282    stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path);
283    launch_info.Dump(stream, nullptr);
284    stream.Flush();
285    log->PutCString(stream.GetString().c_str());
286  }
287
288  int error_code;
289  if ((error_code = ::posix_spawnattr_init(&attr)) != 0) {
290    LLDB_LOGF(log, "::posix_spawnattr_init(&attr) failed");
291    error.SetError(error_code, eErrorTypePOSIX);
292    return error;
293  }
294
295  // Ensure we clean up the spawnattr structure however we exit this function.
296  std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
297      &attr, ::posix_spawnattr_destroy);
298
299  flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
300          POSIX_SPAWN_SETSIGMASK;
301  if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
302    flags |= _POSIX_SPAWN_DISABLE_ASLR;
303
304  sigset_t no_signals;
305  sigset_t all_signals;
306  sigemptyset(&no_signals);
307  sigfillset(&all_signals);
308  ::posix_spawnattr_setsigmask(&attr, &no_signals);
309  ::posix_spawnattr_setsigdefault(&attr, &all_signals);
310
311  if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
312    LLDB_LOG(log,
313             "::posix_spawnattr_setflags(&attr, "
314             "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}",
315             flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR"
316                                               : "",
317             llvm::sys::StrError(error_code));
318    error.SetError(error_code, eErrorTypePOSIX);
319    return error;
320  }
321
322#if !defined(__arm__)
323
324  // We don't need to do this for ARM, and we really shouldn't now that we have
325  // multiple CPU subtypes and no posix_spawnattr call that allows us to set
326  // which CPU subtype to launch...
327  cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
328  if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
329    size_t ocount = 0;
330    error_code =
331        ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
332    if (error_code != 0) {
333      LLDB_LOG(log,
334               "::posix_spawnattr_setbinpref_np(&attr, 1, "
335               "cpu_type = {0:x8}, count => {1}): {2}",
336               desired_cpu_type, ocount, llvm::sys::StrError(error_code));
337      error.SetError(error_code, eErrorTypePOSIX);
338      return error;
339    }
340    if (ocount != 1) {
341      error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
342                                     "did not set the expected number "
343                                     "of cpu_type entries: expected 1 "
344                                     "but was %zu",
345                                     ocount);
346      return error;
347    }
348  }
349#endif
350
351  posix_spawn_file_actions_t file_actions;
352  if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
353    LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}",
354             llvm::sys::StrError(error_code));
355    error.SetError(error_code, eErrorTypePOSIX);
356    return error;
357  }
358
359  // Ensure we clean up file actions however we exit this.  When the
360  // file_actions_up below goes out of scope, we'll get our file action
361  // cleanup.
362  std::unique_ptr<posix_spawn_file_actions_t,
363                  int (*)(posix_spawn_file_actions_t *)>
364      file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
365
366  // We assume the caller has setup the file actions appropriately.  We are not
367  // in the business of figuring out what we really need here. lldb-server will
368  // have already called FinalizeFileActions() as well to button these up
369  // properly.
370  const size_t num_actions = launch_info.GetNumFileActions();
371  for (size_t action_index = 0; action_index < num_actions; ++action_index) {
372    const FileAction *const action =
373        launch_info.GetFileActionAtIndex(action_index);
374    if (!action)
375      continue;
376
377    error = CreatePosixSpawnFileAction(*action, &file_actions);
378    if (!error.Success()) {
379      LLDB_LOGF(log,
380                "%s(): error converting FileAction to posix_spawn "
381                "file action: %s",
382                __FUNCTION__, error.AsCString());
383      return error;
384    }
385  }
386
387  // TODO: Verify if we can set the working directory back immediately
388  // after the posix_spawnp call without creating a race condition???
389  const char *const working_directory =
390      launch_info.GetWorkingDirectory().GetCString();
391  if (working_directory && working_directory[0])
392    ::chdir(working_directory);
393
394  auto argv = launch_info.GetArguments().GetArgumentVector();
395  auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
396  error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
397                              (char *const *)argv, (char *const *)envp);
398  if (error_code != 0) {
399    LLDB_LOG(log,
400             "::posix_spawnp(pid => {0}, path = '{1}', file_actions "
401             "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}",
402             pid, path, &file_actions, &attr, argv, envp,
403             llvm::sys::StrError(error_code));
404    error.SetError(error_code, eErrorTypePOSIX);
405    return error;
406  }
407
408  // Validate we got a pid.
409  if (pid == LLDB_INVALID_PROCESS_ID) {
410    error.SetErrorString("posix_spawn() did not indicate a failure but it "
411                         "failed to return a pid, aborting.");
412    return error;
413  }
414
415  if (actual_cpu_type) {
416    *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
417    LLDB_LOGF(log,
418              "%s(): cpu type for launched process pid=%i: "
419              "cpu_type=0x%8.8x",
420              __FUNCTION__, *pid, *actual_cpu_type);
421  }
422
423  return error;
424}
425
426Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
427                      LaunchFlavor *launch_flavor) {
428  Status error;
429  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
430
431  if (!launch_flavor) {
432    error.SetErrorString("mandatory launch_flavor field was null");
433    return error;
434  }
435
436  if (log) {
437    StreamString stream;
438    stream.Printf("NativeProcessDarwin::%s(): launching with the "
439                  "following launch info:",
440                  __FUNCTION__);
441    launch_info.Dump(stream, nullptr);
442    stream.Flush();
443    log->PutCString(stream.GetString().c_str());
444  }
445
446  // Retrieve the binary name given to us.
447  char given_path[PATH_MAX];
448  given_path[0] = '\0';
449  launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
450
451  // Determine the manner in which we'll launch.
452  *launch_flavor = g_launch_flavor;
453  if (*launch_flavor == LaunchFlavor::Default) {
454    // Our default launch method is posix spawn
455    *launch_flavor = LaunchFlavor::PosixSpawn;
456#if defined WITH_FBS
457    // Check if we have an app bundle, if so launch using BackBoard Services.
458    if (strstr(given_path, ".app")) {
459      *launch_flavor = eLaunchFlavorFBS;
460    }
461#elif defined WITH_BKS
462    // Check if we have an app bundle, if so launch using BackBoard Services.
463    if (strstr(given_path, ".app")) {
464      *launch_flavor = eLaunchFlavorBKS;
465    }
466#elif defined WITH_SPRINGBOARD
467    // Check if we have an app bundle, if so launch using SpringBoard.
468    if (strstr(given_path, ".app")) {
469      *launch_flavor = eLaunchFlavorSpringBoard;
470    }
471#endif
472  }
473
474  // Attempt to resolve the binary name to an absolute path.
475  char resolved_path[PATH_MAX];
476  resolved_path[0] = '\0';
477
478  LLDB_LOGF(log, "%s(): attempting to resolve given binary path: \"%s\"",
479            __FUNCTION__, given_path);
480
481  // If we fail to resolve the path to our executable, then just use what we
482  // were given and hope for the best
483  if (!ResolveExecutablePath(given_path, resolved_path,
484                             sizeof(resolved_path))) {
485    LLDB_LOGF(log,
486              "%s(): failed to resolve binary path, using "
487              "what was given verbatim and hoping for the best",
488              __FUNCTION__);
489    ::strncpy(resolved_path, given_path, sizeof(resolved_path));
490  } else {
491    LLDB_LOGF(log, "%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
492              resolved_path);
493  }
494
495  char launch_err_str[PATH_MAX];
496  launch_err_str[0] = '\0';
497
498  // TODO figure out how to handle QSetProcessEvent
499  // const char *process_event = ctx.GetProcessEvent();
500
501  // Ensure the binary is there.
502  struct stat path_stat;
503  if (::stat(resolved_path, &path_stat) == -1) {
504    error.SetErrorToErrno();
505    return error;
506  }
507
508  // Fork a child process for debugging
509  // state_callback(eStateLaunching);
510
511  const auto argv = launch_info.GetArguments().GetConstArgumentVector();
512  const auto envp =
513      launch_info.GetEnvironmentEntries().GetConstArgumentVector();
514
515  switch (*launch_flavor) {
516  case LaunchFlavor::ForkExec: {
517    ::pid_t pid = LLDB_INVALID_PROCESS_ID;
518    error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
519                                        pty_master_fd);
520    if (error.Success()) {
521      launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
522    } else {
523      // Reset any variables that might have been set during a failed launch
524      // attempt.
525      if (pty_master_fd)
526        *pty_master_fd = -1;
527
528      // We're done.
529      return error;
530    }
531  } break;
532
533#ifdef WITH_FBS
534  case LaunchFlavor::FBS: {
535    const char *app_ext = strstr(path, ".app");
536    if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
537      std::string app_bundle_path(path, app_ext + strlen(".app"));
538      m_flags |= eMachProcessFlagsUsingFBS;
539      if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
540                                     no_stdio, disable_aslr, event_data,
541                                     launch_err) != 0)
542        return m_pid; // A successful SBLaunchForDebug() returns and assigns a
543                      // non-zero m_pid.
544      else
545        break; // We tried a FBS launch, but didn't succeed lets get out
546    }
547  } break;
548#endif
549
550#ifdef WITH_BKS
551  case LaunchFlavor::BKS: {
552    const char *app_ext = strstr(path, ".app");
553    if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
554      std::string app_bundle_path(path, app_ext + strlen(".app"));
555      m_flags |= eMachProcessFlagsUsingBKS;
556      if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
557                                     no_stdio, disable_aslr, event_data,
558                                     launch_err) != 0)
559        return m_pid; // A successful SBLaunchForDebug() returns and assigns a
560                      // non-zero m_pid.
561      else
562        break; // We tried a BKS launch, but didn't succeed lets get out
563    }
564  } break;
565#endif
566
567#ifdef WITH_SPRINGBOARD
568  case LaunchFlavor::SpringBoard: {
569    //  .../whatever.app/whatever ?
570    //  Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
571    //  "com.apple.whatever" here
572    const char *app_ext = strstr(path, ".app/");
573    if (app_ext == NULL) {
574      // .../whatever.app ?
575      int len = strlen(path);
576      if (len > 5) {
577        if (strcmp(path + len - 4, ".app") == 0) {
578          app_ext = path + len - 4;
579        }
580      }
581    }
582    if (app_ext) {
583      std::string app_bundle_path(path, app_ext + strlen(".app"));
584      if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
585                           disable_aslr, launch_err) != 0)
586        return m_pid; // A successful SBLaunchForDebug() returns and assigns a
587                      // non-zero m_pid.
588      else
589        break; // We tried a springboard launch, but didn't succeed lets get out
590    }
591  } break;
592#endif
593
594  case LaunchFlavor::PosixSpawn: {
595    ::pid_t pid = LLDB_INVALID_PROCESS_ID;
596
597    // Retrieve paths for stdin/stdout/stderr.
598    cpu_type_t actual_cpu_type = 0;
599    error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
600                                              &actual_cpu_type);
601    if (error.Success()) {
602      launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
603      if (pty_master_fd)
604        *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
605    } else {
606      // Reset any variables that might have been set during a failed launch
607      // attempt.
608      if (pty_master_fd)
609        *pty_master_fd = -1;
610
611      // We're done.
612      return error;
613    }
614    break;
615  }
616
617  default:
618    // Invalid launch flavor.
619    error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
620                                   "launch flavor %d",
621                                   __FUNCTION__, (int)*launch_flavor);
622    return error;
623  }
624
625  if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
626    // If we don't have a valid process ID and no one has set the error, then
627    // return a generic error.
628    if (error.Success())
629      error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
630                                     "specified",
631                                     __FUNCTION__);
632  }
633
634  // We're done with the launch side of the operation.
635  return error;
636}
637}
638} // namespaces
639