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