1c5f01b2fSopenharmony_ci//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===// 2c5f01b2fSopenharmony_ci// 3c5f01b2fSopenharmony_ci// The LLVM Compiler Infrastructure 4c5f01b2fSopenharmony_ci// 5c5f01b2fSopenharmony_ci// This file is distributed under the University of Illinois Open Source 6c5f01b2fSopenharmony_ci// License. See LICENSE.TXT for details. 7c5f01b2fSopenharmony_ci// 8c5f01b2fSopenharmony_ci//===----------------------------------------------------------------------===// 9c5f01b2fSopenharmony_ci// Misc utils for Darwin. 10c5f01b2fSopenharmony_ci//===----------------------------------------------------------------------===// 11c5f01b2fSopenharmony_ci#include "FuzzerDefs.h" 12c5f01b2fSopenharmony_ci#if LIBFUZZER_APPLE 13c5f01b2fSopenharmony_ci 14c5f01b2fSopenharmony_ci#include "FuzzerIO.h" 15c5f01b2fSopenharmony_ci#include <mutex> 16c5f01b2fSopenharmony_ci#include <signal.h> 17c5f01b2fSopenharmony_ci#include <spawn.h> 18c5f01b2fSopenharmony_ci#include <sys/wait.h> 19c5f01b2fSopenharmony_ci 20c5f01b2fSopenharmony_ci// There is no header for this on macOS so declare here 21c5f01b2fSopenharmony_ciextern "C" char **environ; 22c5f01b2fSopenharmony_ci 23c5f01b2fSopenharmony_cinamespace fuzzer { 24c5f01b2fSopenharmony_ci 25c5f01b2fSopenharmony_cistatic std::mutex SignalMutex; 26c5f01b2fSopenharmony_ci// Global variables used to keep track of how signal handling should be 27c5f01b2fSopenharmony_ci// restored. They should **not** be accessed without holding `SignalMutex`. 28c5f01b2fSopenharmony_cistatic int ActiveThreadCount = 0; 29c5f01b2fSopenharmony_cistatic struct sigaction OldSigIntAction; 30c5f01b2fSopenharmony_cistatic struct sigaction OldSigQuitAction; 31c5f01b2fSopenharmony_cistatic sigset_t OldBlockedSignalsSet; 32c5f01b2fSopenharmony_ci 33c5f01b2fSopenharmony_ci// This is a reimplementation of Libc's `system()`. On Darwin the Libc 34c5f01b2fSopenharmony_ci// implementation contains a mutex which prevents it from being used 35c5f01b2fSopenharmony_ci// concurrently. This implementation **can** be used concurrently. It sets the 36c5f01b2fSopenharmony_ci// signal handlers when the first thread enters and restores them when the last 37c5f01b2fSopenharmony_ci// thread finishes execution of the function and ensures this is not racey by 38c5f01b2fSopenharmony_ci// using a mutex. 39c5f01b2fSopenharmony_ciint ExecuteCommand(const std::string &Command) { 40c5f01b2fSopenharmony_ci posix_spawnattr_t SpawnAttributes; 41c5f01b2fSopenharmony_ci if (posix_spawnattr_init(&SpawnAttributes)) 42c5f01b2fSopenharmony_ci return -1; 43c5f01b2fSopenharmony_ci // Block and ignore signals of the current process when the first thread 44c5f01b2fSopenharmony_ci // enters. 45c5f01b2fSopenharmony_ci { 46c5f01b2fSopenharmony_ci std::lock_guard<std::mutex> Lock(SignalMutex); 47c5f01b2fSopenharmony_ci if (ActiveThreadCount == 0) { 48c5f01b2fSopenharmony_ci static struct sigaction IgnoreSignalAction; 49c5f01b2fSopenharmony_ci sigset_t BlockedSignalsSet; 50c5f01b2fSopenharmony_ci memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction)); 51c5f01b2fSopenharmony_ci IgnoreSignalAction.sa_handler = SIG_IGN; 52c5f01b2fSopenharmony_ci 53c5f01b2fSopenharmony_ci if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) { 54c5f01b2fSopenharmony_ci Printf("Failed to ignore SIGINT\n"); 55c5f01b2fSopenharmony_ci (void)posix_spawnattr_destroy(&SpawnAttributes); 56c5f01b2fSopenharmony_ci return -1; 57c5f01b2fSopenharmony_ci } 58c5f01b2fSopenharmony_ci if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) { 59c5f01b2fSopenharmony_ci Printf("Failed to ignore SIGQUIT\n"); 60c5f01b2fSopenharmony_ci // Try our best to restore the signal handlers. 61c5f01b2fSopenharmony_ci (void)sigaction(SIGINT, &OldSigIntAction, NULL); 62c5f01b2fSopenharmony_ci (void)posix_spawnattr_destroy(&SpawnAttributes); 63c5f01b2fSopenharmony_ci return -1; 64c5f01b2fSopenharmony_ci } 65c5f01b2fSopenharmony_ci 66c5f01b2fSopenharmony_ci (void)sigemptyset(&BlockedSignalsSet); 67c5f01b2fSopenharmony_ci (void)sigaddset(&BlockedSignalsSet, SIGCHLD); 68c5f01b2fSopenharmony_ci if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) == 69c5f01b2fSopenharmony_ci -1) { 70c5f01b2fSopenharmony_ci Printf("Failed to block SIGCHLD\n"); 71c5f01b2fSopenharmony_ci // Try our best to restore the signal handlers. 72c5f01b2fSopenharmony_ci (void)sigaction(SIGQUIT, &OldSigQuitAction, NULL); 73c5f01b2fSopenharmony_ci (void)sigaction(SIGINT, &OldSigIntAction, NULL); 74c5f01b2fSopenharmony_ci (void)posix_spawnattr_destroy(&SpawnAttributes); 75c5f01b2fSopenharmony_ci return -1; 76c5f01b2fSopenharmony_ci } 77c5f01b2fSopenharmony_ci } 78c5f01b2fSopenharmony_ci ++ActiveThreadCount; 79c5f01b2fSopenharmony_ci } 80c5f01b2fSopenharmony_ci 81c5f01b2fSopenharmony_ci // NOTE: Do not introduce any new `return` statements past this 82c5f01b2fSopenharmony_ci // point. It is important that `ActiveThreadCount` always be decremented 83c5f01b2fSopenharmony_ci // when leaving this function. 84c5f01b2fSopenharmony_ci 85c5f01b2fSopenharmony_ci // Make sure the child process uses the default handlers for the 86c5f01b2fSopenharmony_ci // following signals rather than inheriting what the parent has. 87c5f01b2fSopenharmony_ci sigset_t DefaultSigSet; 88c5f01b2fSopenharmony_ci (void)sigemptyset(&DefaultSigSet); 89c5f01b2fSopenharmony_ci (void)sigaddset(&DefaultSigSet, SIGQUIT); 90c5f01b2fSopenharmony_ci (void)sigaddset(&DefaultSigSet, SIGINT); 91c5f01b2fSopenharmony_ci (void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet); 92c5f01b2fSopenharmony_ci // Make sure the child process doesn't block SIGCHLD 93c5f01b2fSopenharmony_ci (void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet); 94c5f01b2fSopenharmony_ci short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; 95c5f01b2fSopenharmony_ci (void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags); 96c5f01b2fSopenharmony_ci 97c5f01b2fSopenharmony_ci pid_t Pid; 98c5f01b2fSopenharmony_ci char **Environ = environ; // Read from global 99c5f01b2fSopenharmony_ci const char *CommandCStr = Command.c_str(); 100c5f01b2fSopenharmony_ci const char *Argv[] = {"sh", "-c", CommandCStr, NULL}; 101c5f01b2fSopenharmony_ci int ErrorCode = 0, ProcessStatus = 0; 102c5f01b2fSopenharmony_ci // FIXME: We probably shouldn't hardcode the shell path. 103c5f01b2fSopenharmony_ci ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes, 104c5f01b2fSopenharmony_ci (char *const *)Argv, Environ); 105c5f01b2fSopenharmony_ci (void)posix_spawnattr_destroy(&SpawnAttributes); 106c5f01b2fSopenharmony_ci if (!ErrorCode) { 107c5f01b2fSopenharmony_ci pid_t SavedPid = Pid; 108c5f01b2fSopenharmony_ci do { 109c5f01b2fSopenharmony_ci // Repeat until call completes uninterrupted. 110c5f01b2fSopenharmony_ci Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0); 111c5f01b2fSopenharmony_ci } while (Pid == -1 && errno == EINTR); 112c5f01b2fSopenharmony_ci if (Pid == -1) { 113c5f01b2fSopenharmony_ci // Fail for some other reason. 114c5f01b2fSopenharmony_ci ProcessStatus = -1; 115c5f01b2fSopenharmony_ci } 116c5f01b2fSopenharmony_ci } else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) { 117c5f01b2fSopenharmony_ci // Fork failure. 118c5f01b2fSopenharmony_ci ProcessStatus = -1; 119c5f01b2fSopenharmony_ci } else { 120c5f01b2fSopenharmony_ci // Shell execution failure. 121c5f01b2fSopenharmony_ci ProcessStatus = W_EXITCODE(127, 0); 122c5f01b2fSopenharmony_ci } 123c5f01b2fSopenharmony_ci 124c5f01b2fSopenharmony_ci // Restore the signal handlers of the current process when the last thread 125c5f01b2fSopenharmony_ci // using this function finishes. 126c5f01b2fSopenharmony_ci { 127c5f01b2fSopenharmony_ci std::lock_guard<std::mutex> Lock(SignalMutex); 128c5f01b2fSopenharmony_ci --ActiveThreadCount; 129c5f01b2fSopenharmony_ci if (ActiveThreadCount == 0) { 130c5f01b2fSopenharmony_ci bool FailedRestore = false; 131c5f01b2fSopenharmony_ci if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) { 132c5f01b2fSopenharmony_ci Printf("Failed to restore SIGINT handling\n"); 133c5f01b2fSopenharmony_ci FailedRestore = true; 134c5f01b2fSopenharmony_ci } 135c5f01b2fSopenharmony_ci if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) { 136c5f01b2fSopenharmony_ci Printf("Failed to restore SIGQUIT handling\n"); 137c5f01b2fSopenharmony_ci FailedRestore = true; 138c5f01b2fSopenharmony_ci } 139c5f01b2fSopenharmony_ci if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) { 140c5f01b2fSopenharmony_ci Printf("Failed to unblock SIGCHLD\n"); 141c5f01b2fSopenharmony_ci FailedRestore = true; 142c5f01b2fSopenharmony_ci } 143c5f01b2fSopenharmony_ci if (FailedRestore) 144c5f01b2fSopenharmony_ci ProcessStatus = -1; 145c5f01b2fSopenharmony_ci } 146c5f01b2fSopenharmony_ci } 147c5f01b2fSopenharmony_ci return ProcessStatus; 148c5f01b2fSopenharmony_ci} 149c5f01b2fSopenharmony_ci 150c5f01b2fSopenharmony_ci} // namespace fuzzer 151c5f01b2fSopenharmony_ci 152c5f01b2fSopenharmony_ci#endif // LIBFUZZER_APPLE 153