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/Core/Error.h"
34 #include "lldb/Core/Log.h"
35 #include "lldb/Core/StreamString.h"
36 #include "lldb/Target/ProcessLaunchInfo.h"
37 #include "lldb/Utility/PseudoTerminal.h"
38 
39 #include "CFBundle.h"
40 #include "CFString.h"
41 
42 using namespace lldb;
43 using namespace lldb_private;
44 using namespace lldb_private::process_darwin;
45 using namespace lldb_private::darwin_process_launcher;
46 
47 namespace {
48 static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
49 }
50 
51 namespace lldb_private {
52 namespace darwin_process_launcher {
53 
54 static 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 
72 static 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.
134 static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
135                                          char const *envp[], ::pid_t *pid,
136                                          int *pty_fd) {
137   Error 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
145   // as unbuffered io.
146   lldb_utility::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     //--------------------------------------------------------------
152     // Error during fork.
153     //--------------------------------------------------------------
154     *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
155     error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
156                                    fork_error);
157     return error;
158   } else if (pid == 0) {
159     //--------------------------------------------------------------
160     // Child process
161     //--------------------------------------------------------------
162 
163     // Debug this process.
164     ::ptrace(PT_TRACE_ME, 0, 0, 0);
165 
166     // Get BSD signals as mach exceptions.
167     ::ptrace(PT_SIGEXC, 0, 0, 0);
168 
169     // If our parent is setgid, lets make sure we don't inherit those
170     // extra powers due to nepotism.
171     if (::setgid(getgid()) == 0) {
172       // Let the child have its own process group. We need to execute
173       // this call in both the child and parent to avoid a race
174       // condition between the two processes.
175 
176       // Set the child process group to match its pid.
177       ::setpgid(0, 0);
178 
179       // Sleep a bit to before the exec call.
180       ::sleep(1);
181 
182       // Turn this process into the given executable.
183       ::execv(path, (char *const *)argv);
184     }
185     // Exit with error code. Child process should have taken
186     // over in above exec call and if the exec fails it will
187     // 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
194     // this call in both the child and parent to avoid a race condition
195     // between the two 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
201       // close 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 Error
209 CreatePosixSpawnFileAction(const FileAction &action,
210                            posix_spawn_file_actions_t *file_actions) {
211   Error 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 
273 static Error PosixSpawnChildForPTraceDebugging(const char *path,
274                                                ProcessLaunchInfo &launch_info,
275                                                ::pid_t *pid,
276                                                cpu_type_t *actual_cpu_type) {
277   Error 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
305   // function.
306   std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
307       &attr, ::posix_spawnattr_destroy);
308 
309   flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
310           POSIX_SPAWN_SETSIGMASK;
311   if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
312     flags |= _POSIX_SPAWN_DISABLE_ASLR;
313 
314   sigset_t no_signals;
315   sigset_t all_signals;
316   sigemptyset(&no_signals);
317   sigfillset(&all_signals);
318   ::posix_spawnattr_setsigmask(&attr, &no_signals);
319   ::posix_spawnattr_setsigdefault(&attr, &all_signals);
320 
321   if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
322     if (log)
323       log->Printf("::posix_spawnattr_setflags(&attr, "
324                   "POSIX_SPAWN_START_SUSPENDED%s) failed: %s",
325                   flags & _POSIX_SPAWN_DISABLE_ASLR
326                       ? " | _POSIX_SPAWN_DISABLE_ASLR"
327                       : "",
328                   strerror(error_code));
329     error.SetError(error_code, eErrorTypePOSIX);
330     return error;
331   }
332 
333 #if !defined(__arm__)
334 
335   // We don't need to do this for ARM, and we really shouldn't now that we
336   // have multiple CPU subtypes and no posix_spawnattr call that allows us
337   // to set which CPU subtype to launch...
338   cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
339   if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
340     size_t ocount = 0;
341     error_code =
342         ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
343     if (error_code != 0) {
344       if (log)
345         log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, "
346                     "cpu_type = 0x%8.8x, count => %llu): %s",
347                     desired_cpu_type, (uint64_t)ocount, strerror(error_code));
348       error.SetError(error_code, eErrorTypePOSIX);
349       return error;
350     }
351     if (ocount != 1) {
352       error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
353                                      "did not set the expected number "
354                                      "of cpu_type entries: expected 1 "
355                                      "but was %zu",
356                                      ocount);
357       return error;
358     }
359   }
360 #endif
361 
362   posix_spawn_file_actions_t file_actions;
363   if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
364     if (log)
365       log->Printf("::posix_spawn_file_actions_init(&file_actions) "
366                   "failed: %s",
367                   strerror(error_code));
368     error.SetError(error_code, eErrorTypePOSIX);
369     return error;
370   }
371 
372   // Ensure we clean up file actions however we exit this.  When the
373   // file_actions_up below goes out of scope, we'll get our file action
374   // cleanup.
375   std::unique_ptr<posix_spawn_file_actions_t,
376                   int (*)(posix_spawn_file_actions_t *)>
377       file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
378 
379   // We assume the caller has setup the file actions appropriately.  We
380   // are not in the business of figuring out what we really need here.
381   // lldb-server will have already called FinalizeFileActions() as well
382   // to button these up properly.
383   const size_t num_actions = launch_info.GetNumFileActions();
384   for (size_t action_index = 0; action_index < num_actions; ++action_index) {
385     const FileAction *const action =
386         launch_info.GetFileActionAtIndex(action_index);
387     if (!action)
388       continue;
389 
390     error = CreatePosixSpawnFileAction(*action, &file_actions);
391     if (!error.Success()) {
392       if (log)
393         log->Printf("%s(): error converting FileAction to posix_spawn "
394                     "file action: %s",
395                     __FUNCTION__, error.AsCString());
396       return error;
397     }
398   }
399 
400   // TODO: Verify if we can set the working directory back immediately
401   // after the posix_spawnp call without creating a race condition???
402   const char *const working_directory =
403       launch_info.GetWorkingDirectory().GetCString();
404   if (working_directory && working_directory[0])
405     ::chdir(working_directory);
406 
407   auto argv = launch_info.GetArguments().GetArgumentVector();
408   auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
409   error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
410                               (char *const *)argv, (char *const *)envp);
411   if (error_code != 0) {
412     if (log)
413       log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions "
414                   "= %p, attr = %p, argv = %p, envp = %p) failed: %s",
415                   pid, path, &file_actions, &attr, argv, envp,
416                   strerror(error_code));
417     error.SetError(error_code, eErrorTypePOSIX);
418     return error;
419   }
420 
421   // Validate we got a pid.
422   if (pid == LLDB_INVALID_PROCESS_ID) {
423     error.SetErrorString("posix_spawn() did not indicate a failure but it "
424                          "failed to return a pid, aborting.");
425     return error;
426   }
427 
428   if (actual_cpu_type) {
429     *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
430     if (log)
431       log->Printf("%s(): cpu type for launched process pid=%i: "
432                   "cpu_type=0x%8.8x",
433                   __FUNCTION__, *pid, *actual_cpu_type);
434   }
435 
436   return error;
437 }
438 
439 Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
440                      LaunchFlavor *launch_flavor) {
441   Error error;
442   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
443 
444   if (!launch_flavor) {
445     error.SetErrorString("mandatory launch_flavor field was null");
446     return error;
447   }
448 
449   if (log) {
450     StreamString stream;
451     stream.Printf("NativeProcessDarwin::%s(): launching with the "
452                   "following launch info:",
453                   __FUNCTION__);
454     launch_info.Dump(stream, nullptr);
455     stream.Flush();
456     log->PutCString(stream.GetString().c_str());
457   }
458 
459   // Retrieve the binary name given to us.
460   char given_path[PATH_MAX];
461   given_path[0] = '\0';
462   launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
463 
464   // Determine the manner in which we'll launch.
465   *launch_flavor = g_launch_flavor;
466   if (*launch_flavor == LaunchFlavor::Default) {
467     // Our default launch method is posix spawn
468     *launch_flavor = LaunchFlavor::PosixSpawn;
469 #if defined WITH_FBS
470     // Check if we have an app bundle, if so launch using BackBoard Services.
471     if (strstr(given_path, ".app")) {
472       *launch_flavor = eLaunchFlavorFBS;
473     }
474 #elif defined WITH_BKS
475     // Check if we have an app bundle, if so launch using BackBoard Services.
476     if (strstr(given_path, ".app")) {
477       *launch_flavor = eLaunchFlavorBKS;
478     }
479 #elif defined WITH_SPRINGBOARD
480     // Check if we have an app bundle, if so launch using SpringBoard.
481     if (strstr(given_path, ".app")) {
482       *launch_flavor = eLaunchFlavorSpringBoard;
483     }
484 #endif
485   }
486 
487   // Attempt to resolve the binary name to an absolute path.
488   char resolved_path[PATH_MAX];
489   resolved_path[0] = '\0';
490 
491   if (log)
492     log->Printf("%s(): attempting to resolve given binary path: \"%s\"",
493                 __FUNCTION__, given_path);
494 
495   // If we fail to resolve the path to our executable, then just use what we
496   // were given and hope for the best
497   if (!ResolveExecutablePath(given_path, resolved_path,
498                              sizeof(resolved_path))) {
499     if (log)
500       log->Printf("%s(): failed to resolve binary path, using "
501                   "what was given verbatim and hoping for the best",
502                   __FUNCTION__);
503     ::strncpy(resolved_path, given_path, sizeof(resolved_path));
504   } else {
505     if (log)
506       log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
507                   resolved_path);
508   }
509 
510   char launch_err_str[PATH_MAX];
511   launch_err_str[0] = '\0';
512 
513   // TODO figure out how to handle QSetProcessEvent
514   // const char *process_event = ctx.GetProcessEvent();
515 
516   // Ensure the binary is there.
517   struct stat path_stat;
518   if (::stat(resolved_path, &path_stat) == -1) {
519     error.SetErrorToErrno();
520     return error;
521   }
522 
523   // Fork a child process for debugging
524   // state_callback(eStateLaunching);
525 
526   const auto argv = launch_info.GetArguments().GetConstArgumentVector();
527   const auto envp =
528       launch_info.GetEnvironmentEntries().GetConstArgumentVector();
529 
530   switch (*launch_flavor) {
531   case LaunchFlavor::ForkExec: {
532     ::pid_t pid = LLDB_INVALID_PROCESS_ID;
533     error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
534                                         pty_master_fd);
535     if (error.Success()) {
536       launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
537     } else {
538       // Reset any variables that might have been set during a failed
539       // launch attempt.
540       if (pty_master_fd)
541         *pty_master_fd = -1;
542 
543       // We're done.
544       return error;
545     }
546   } break;
547 
548 #ifdef WITH_FBS
549   case LaunchFlavor::FBS: {
550     const char *app_ext = strstr(path, ".app");
551     if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
552       std::string app_bundle_path(path, app_ext + strlen(".app"));
553       m_flags |= eMachProcessFlagsUsingFBS;
554       if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
555                                      no_stdio, disable_aslr, event_data,
556                                      launch_err) != 0)
557         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
558                       // non-zero m_pid.
559       else
560         break; // We tried a FBS launch, but didn't succeed lets get out
561     }
562   } break;
563 #endif
564 
565 #ifdef WITH_BKS
566   case LaunchFlavor::BKS: {
567     const char *app_ext = strstr(path, ".app");
568     if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
569       std::string app_bundle_path(path, app_ext + strlen(".app"));
570       m_flags |= eMachProcessFlagsUsingBKS;
571       if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
572                                      no_stdio, disable_aslr, event_data,
573                                      launch_err) != 0)
574         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
575                       // non-zero m_pid.
576       else
577         break; // We tried a BKS launch, but didn't succeed lets get out
578     }
579   } break;
580 #endif
581 
582 #ifdef WITH_SPRINGBOARD
583   case LaunchFlavor::SpringBoard: {
584     //  .../whatever.app/whatever ?
585     //  Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
586     //  "com.apple.whatever" here
587     const char *app_ext = strstr(path, ".app/");
588     if (app_ext == NULL) {
589       // .../whatever.app ?
590       int len = strlen(path);
591       if (len > 5) {
592         if (strcmp(path + len - 4, ".app") == 0) {
593           app_ext = path + len - 4;
594         }
595       }
596     }
597     if (app_ext) {
598       std::string app_bundle_path(path, app_ext + strlen(".app"));
599       if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
600                            disable_aslr, launch_err) != 0)
601         return m_pid; // A successful SBLaunchForDebug() returns and assigns a
602                       // non-zero m_pid.
603       else
604         break; // We tried a springboard launch, but didn't succeed lets get out
605     }
606   } break;
607 #endif
608 
609   case LaunchFlavor::PosixSpawn: {
610     ::pid_t pid = LLDB_INVALID_PROCESS_ID;
611 
612     // Retrieve paths for stdin/stdout/stderr.
613     cpu_type_t actual_cpu_type = 0;
614     error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
615                                               &actual_cpu_type);
616     if (error.Success()) {
617       launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
618       if (pty_master_fd)
619         *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
620     } else {
621       // Reset any variables that might have been set during a failed
622       // launch attempt.
623       if (pty_master_fd)
624         *pty_master_fd = -1;
625 
626       // We're done.
627       return error;
628     }
629     break;
630   }
631 
632   default:
633     // Invalid launch flavor.
634     error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
635                                    "launch flavor %d",
636                                    __FUNCTION__, (int)*launch_flavor);
637     return error;
638   }
639 
640   if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
641     // If we don't have a valid process ID and no one has set the error,
642     // then return a generic error.
643     if (error.Success())
644       error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
645                                      "specified",
646                                      __FUNCTION__);
647   }
648 
649   // We're done with the launch side of the operation.
650   return error;
651 }
652 }
653 } // namespaces
654