]> git.saurik.com Git - cycript.git/commitdiff
Unix domain sockets are often walled by sandboxes.
authorJay Freeman (saurik) <saurik@saurik.com>
Wed, 24 Aug 2016 09:51:13 +0000 (02:51 -0700)
committerJay Freeman (saurik) <saurik@saurik.com>
Wed, 24 Aug 2016 09:51:13 +0000 (02:51 -0700)
Console.cpp
Handler.cpp
Inject.cpp
control.in

index 1f725ae54188b213dfee840283c9f10cd7af2f41..c3ebd77da5dde602de3a0a7b418142b0d70bb194 100644 (file)
@@ -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<sockaddr *>(&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;
index da458d6e7bb5ca4fedc4e3a8ebe92ed00c5fc98e..744344fc9c5709bf487e14dc846119cbd6ecdfcd 100644 (file)
@@ -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));
index 46118d8dd4224f6a201700cbbc272e638c9c3042..a451b3db74fb3210a3dcac66f4ef4df2c08745aa 100644 (file)
@@ -55,7 +55,7 @@ Type_ *shift(Type_ *data, size_t size) {
     return reinterpret_cast<Type_ *>(reinterpret_cast<uint8_t *>(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<void *>(&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);
 }
index dfcb78c1880a4dfb5b58e9746c248004f43f5214..a8e2e4bb2de57b4bea07d8462b63047c561b5d76 100644 (file)
@@ -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) <saurik@saurik.com>