From: Jay Freeman (saurik) Date: Wed, 24 Aug 2016 09:51:13 +0000 (-0700) Subject: Unix domain sockets are often walled by sandboxes. X-Git-Tag: v0.9.593~1 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/0abb2a2f9d5b1c7fbe7a43619bab5291d7e55f87 Unix domain sockets are often walled by sandboxes. --- diff --git a/Console.cpp b/Console.cpp index 1f725ae..c3ebd77 100644 --- a/Console.cpp +++ b/Console.cpp @@ -249,11 +249,23 @@ void Setup(CYOutput &out, CYDriver &driver, CYOptions &options, bool lower) { driver.Replace(options); } -static CYUTF8String Run(CYPool &pool, int client, CYUTF8String code) { - const char *json; - uint32_t size; +class CYRemote { + public: + virtual CYUTF8String Run(CYPool &pool, CYUTF8String code) = 0; + + inline CYUTF8String Run(CYPool &pool, const std::string &code) { + return Run(pool, CYUTF8String(code.c_str(), code.size())); + } +}; + +class CYLocalRemote : + public CYRemote +{ + public: + virtual CYUTF8String Run(CYPool &pool, CYUTF8String code) { + const char *json; + uint32_t size; - if (client == -1) { mode_ = Running; #ifdef CY_EXECUTE json = CYExecute(CYGetJSContext(), pool, code); @@ -265,31 +277,95 @@ static CYUTF8String Run(CYPool &pool, int client, CYUTF8String code) { size = 0; else size = strlen(json); - } else { + + return CYUTF8String(json, size); + } +}; + +class CYSocketRemote : + public CYRemote +{ + private: + int socket_; + + public: + CYSocketRemote(const char *host, const char *port) { + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_flags = 0; + + struct addrinfo *infos; + _syscall(getaddrinfo(host, port, &hints, &infos)); + + _assert(infos != NULL); try { + for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) { + socket_ = _syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol)); try { + _syscall(connect(socket_, info->ai_addr, info->ai_addrlen)); + break; + } catch (...) { + _syscall(close(socket_)); + throw; + } + } + } catch (...) { + freeaddrinfo(infos); + throw; + } + } + + virtual CYUTF8String Run(CYPool &pool, CYUTF8String code) { + const char *json; + uint32_t size; + mode_ = Sending; size = code.size; - _assert(CYSendAll(client, &size, sizeof(size))); - _assert(CYSendAll(client, code.data, code.size)); + _assert(CYSendAll(socket_, &size, sizeof(size))); + _assert(CYSendAll(socket_, code.data, code.size)); mode_ = Waiting; - _assert(CYRecvAll(client, &size, sizeof(size))); + _assert(CYRecvAll(socket_, &size, sizeof(size))); if (size == _not(uint32_t)) { size = 0; json = NULL; } else { char *temp(new(pool) char[size + 1]); - _assert(CYRecvAll(client, temp, size)); + _assert(CYRecvAll(socket_, temp, size)); temp[size] = '\0'; json = temp; } mode_ = Working; + + return CYUTF8String(json, size); } +}; - return CYUTF8String(json, size); -} +void InjectLibrary(pid_t, std::ostream &stream, int, const char *const []); -static CYUTF8String Run(CYPool &pool, int client, const std::string &code) { - return Run(pool, client, CYUTF8String(code.c_str(), code.size())); -} +class CYInjectRemote : + public CYRemote +{ + private: + int pid_; + + public: + CYInjectRemote(int pid) : + pid_(pid) + { + // XXX: wait + } + + virtual CYUTF8String Run(CYPool &pool, CYUTF8String code) { + std::ostringstream stream; + const char *args[2] = {"-e", code.data}; + InjectLibrary(pid_, stream, 2, args); + std::string json(stream.str()); + if (!json.empty() && json[json.size() - 1] == '\n') + json.resize(json.size() - 1); + return CYUTF8String(strdup(json.c_str()), json.size()); + } +}; static std::ostream *out_; @@ -315,7 +391,7 @@ static void Output(CYUTF8String json, std::ostream *out, bool reparse = false) { const char *data(json.data); size_t size(json.size); - if (data == NULL || out == NULL) + if (size == 0 || out == NULL) return; CYLexerHighlight(data, size, *out); @@ -326,10 +402,10 @@ int (*append_history$)(int, const char *); static std::string command_; -static int client_; +static CYRemote *remote_; static CYUTF8String Run(CYPool &pool, const std::string &code) { - return Run(pool, client_, code); + return remote_->Run(pool, code); } static char **Complete(const char *word, int start, int end) { @@ -610,7 +686,7 @@ static void CYConsolePrepTerm(int meta) { static void CYOutputRun(const std::string &code, bool reparse = false) { CYPool pool; - Output(Run(pool, client_, code), &std::cout, reparse); + Output(Run(pool, code), &std::cout, reparse); } static void Console(CYOptions &options) { @@ -780,8 +856,6 @@ static void Console(CYOptions &options) { } } -void InjectLibrary(pid_t, int, const char *const []); - static uint64_t CYGetTime() { #ifdef __APPLE__ return mach_absolute_time(); @@ -1000,92 +1074,15 @@ int Main(int argc, char * const argv[], char const * const envp[]) { #endif #ifdef CY_ATTACH - if (pid == _not(pid_t)) - client_ = -1; - else { - struct Socket { - int fd_; - - Socket(int fd) : - fd_(fd) - { - } - - ~Socket() { - close(fd_); - } - - operator int() { - return fd_; - } - } server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0))); - - struct sockaddr_un address; - memset(&address, 0, sizeof(address)); - address.sun_family = AF_UNIX; - - const char *tmp; -#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) - tmp = "/Library/Caches"; -#else - tmp = "/tmp"; -#endif - - sprintf(address.sun_path, "%s/.s.cy.%u", tmp, getpid()); - unlink(address.sun_path); - - struct File { - const char *path_; - - File(const char *path) : - path_(path) - { - } - - ~File() { - unlink(path_); - } - } file(address.sun_path); - - _syscall(bind(server, reinterpret_cast(&address), sizeof(address))); - _syscall(chmod(address.sun_path, 0777)); - - _syscall(listen(server, 1)); - const char *const argv[] = {address.sun_path, NULL}; - InjectLibrary(pid, 1, argv); - client_ = _syscall(accept(server, NULL, NULL)); - } -#else - client_ = -1; + if (remote_ == NULL && pid != _not(pid_t)) + remote_ = new CYInjectRemote(pid); #endif - if (client_ == -1 && host != NULL && port != NULL) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - hints.ai_flags = 0; - - struct addrinfo *infos; - _syscall(getaddrinfo(host, port, &hints, &infos)); + if (remote_ == NULL && host != NULL && port != NULL) + remote_ = new CYSocketRemote(host, port); - _assert(infos != NULL); try { - for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) { - int client(_syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol))); try { - _syscall(connect(client, info->ai_addr, info->ai_addrlen)); - client_ = client; - break; - } catch (...) { - _syscall(close(client)); - throw; - } - } - } catch (...) { - freeaddrinfo(infos); - throw; - } - } + if (remote_ == NULL) + remote_ = new CYLocalRemote(); if (script == NULL && tty) Console(options); @@ -1156,7 +1153,7 @@ int Main(int argc, char * const argv[], char const * const envp[]) { if (compile) std::cout << code; else { - CYUTF8String json(Run(pool, client_, code)); + CYUTF8String json(Run(pool, code)); if (CYStartsWith(json, "throw ")) { CYLexerHighlight(json.data, json.size, std::cerr); std::cerr << std::endl; diff --git a/Handler.cpp b/Handler.cpp index da458d6..744344f 100644 --- a/Handler.cpp +++ b/Handler.cpp @@ -60,6 +60,54 @@ void CYPerform(void *arg) { pthread_mutex_unlock(&execute->mutex_); } +const char *CYHandleCommand(CYPool &pool, const std::string &code) { + bool dispatch; +#ifdef __APPLE__ + CFRunLoopRef loop(CFRunLoopGetMain()); + if (CFStringRef mode = CFRunLoopCopyCurrentMode(loop)) { + dispatch = true; + CFRelease(mode); + } else +#endif + dispatch = false; + + CYExecute_ execute = {pool, code.c_str()}; + + pthread_mutex_init(&execute.mutex_, NULL); + pthread_cond_init(&execute.condition_, NULL); + + if (!dispatch) + CYPerform(&execute); +#ifdef __APPLE__ + else { + CFRunLoopSourceContext context; + memset(&context, 0, sizeof(context)); + context.version = 0; + context.info = &execute; + context.perform = &CYPerform; + + CFRunLoopSourceRef source(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context)); + + pthread_mutex_lock(&execute.mutex_); + + CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes); + CFRunLoopSourceSignal(source); + + CFRunLoopWakeUp(loop); + pthread_cond_wait(&execute.condition_, &execute.mutex_); + pthread_mutex_unlock(&execute.mutex_); + + CFRunLoopRemoveSource(loop, source, kCFRunLoopCommonModes); + CFRelease(source); + } +#endif + + pthread_cond_destroy(&execute.condition_); + pthread_mutex_destroy(&execute.mutex_); + + return execute.data_; +} + struct CYClient : CYData { @@ -76,16 +124,6 @@ struct CYClient : } void Handle() { - bool dispatch; -#ifdef __APPLE__ - CFRunLoopRef loop(CFRunLoopGetMain()); - if (CFStringRef mode = CFRunLoopCopyCurrentMode(loop)) { - dispatch = true; - CFRelease(mode); - } else -#endif - dispatch = false; - for (;;) { uint32_t size; if (!CYRecvAll(socket_, &size, sizeof(size))) @@ -98,41 +136,7 @@ struct CYClient : data[size] = '\0'; std::string code(data, size); - CYExecute_ execute = {pool, code.c_str()}; - - pthread_mutex_init(&execute.mutex_, NULL); - pthread_cond_init(&execute.condition_, NULL); - - if (!dispatch) - CYPerform(&execute); -#ifdef __APPLE__ - else { - CFRunLoopSourceContext context; - memset(&context, 0, sizeof(context)); - context.version = 0; - context.info = &execute; - context.perform = &CYPerform; - - CFRunLoopSourceRef source(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context)); - - pthread_mutex_lock(&execute.mutex_); - - CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes); - CFRunLoopSourceSignal(source); - - CFRunLoopWakeUp(loop); - pthread_cond_wait(&execute.condition_, &execute.mutex_); - pthread_mutex_unlock(&execute.mutex_); - - CFRunLoopRemoveSource(loop, source, kCFRunLoopCommonModes); - CFRelease(source); - } -#endif - - pthread_cond_destroy(&execute.condition_); - pthread_mutex_destroy(&execute.mutex_); - - const char *json(execute.data_); + const char *json(CYHandleCommand(pool, code)); size = json == NULL ? _not(uint32_t) : strlen(json); if (!CYSendAll(socket_, &size, sizeof(size))) @@ -182,8 +186,24 @@ _extern void CYHandleServer(pid_t pid) { try { } } _extern char *MSmain0(int argc, char *argv[]) { try { - _assert(argc == 2); - CYHandleSocket(argv[1]); + char *error(NULL); + + switch (argc) { + case 2: + CYHandleSocket(argv[1]); + break; + + case 3: + if (false); + else if (strcmp(argv[1], "-e") == 0) { + CYPool pool; + error = strdup(CYHandleCommand(pool, argv[2]) ?: ""); + } else _assert(false); + break; + + default: + _assert(false); + } static void *handle(NULL); if (handle == NULL) { @@ -196,7 +216,7 @@ _extern char *MSmain0(int argc, char *argv[]) { try { #endif } - return NULL; + return error; } catch (const CYException &error) { CYPool pool; return strdup(error.PoolCString(pool)); diff --git a/Inject.cpp b/Inject.cpp index 46118d8..a451b3d 100644 --- a/Inject.cpp +++ b/Inject.cpp @@ -55,7 +55,7 @@ Type_ *shift(Type_ *data, size_t size) { return reinterpret_cast(reinterpret_cast(data) + size); } -void InjectLibrary(int pid, int argc, const char *const argv[]) { +void InjectLibrary(int pid, std::ostream &stream, int argc, const char *const argv[]) { auto cynject(LibraryFor(reinterpret_cast(&main))); auto slash(cynject.rfind('/')); _assert(slash != std::string::npos); @@ -113,8 +113,32 @@ void InjectLibrary(int pid, int argc, const char *const argv[]) { std::ostringstream inject; inject << cynject << " " << std::dec << pid << " " << library; - for (decltype(argc) i(0); i != argc; ++i) - inject << " " << argv[i]; + for (decltype(argc) i(0); i != argc; ++i) { + inject << " '"; + for (const char *arg(argv[i]); *arg != '\0'; ++arg) + if (*arg != '\'') + inject.put(*arg); + else + inject << "'\\''"; + inject << "'"; + } + + FILE *process(popen(inject.str().c_str(), "r")); + _assert(process != NULL); + + for (;;) { + char data[1024]; + auto writ(fread(data, 1, sizeof(data), process)); + stream.write(data, writ); + + if (writ == sizeof(data)) + continue; + _assert(!ferror(process)); + if (feof(process)) + break; + } - _assert(system(inject.str().c_str()) == 0); + auto status(pclose(process)); // XXX: _scope (sort of?) + _assert(status != -1); + _assert(status == 0); } diff --git a/control.in b/control.in index dfcb78c..a8e2e4b 100644 --- a/control.in +++ b/control.in @@ -6,7 +6,7 @@ Architecture: iphoneos-arm Version: # Description: runtime execution server and disassembler Name: Cycript -Depends: readline, adv-cmds, mobilesubstrate (>= 0.9.6100) +Depends: readline, adv-cmds, mobilesubstrate (>= 0.9.6300) Pre-Depends: dpkg (>= 1.14.25-8) Breaks: cydget (<< 0.9.4008) Author: Jay Freeman (saurik)