fix communication with debuggserver on ios-14 (#471)
* fix communication with debuggserver on ios-14
* decrease read buffer size, create socket with correct flags
* fix regression on older iOS devices
diff --git a/src/ios-deploy/MobileDevice.h b/src/ios-deploy/MobileDevice.h
index 2646bcd..637890b 100644
--- a/src/ios-deploy/MobileDevice.h
+++ b/src/ios-deploy/MobileDevice.h
@@ -65,7 +65,14 @@
typedef unsigned int afc_error_t;
typedef unsigned int usbmux_error_t;
-typedef unsigned int service_conn_t;
+
+typedef struct {
+ char unknown[0x10];
+ int sockfd;
+ void * sslContext;
+ // ??
+} service_conn_t;
+
typedef service_conn_t * ServiceConnRef;
struct am_recovery_device;
diff --git a/src/ios-deploy/ios-deploy.m b/src/ios-deploy/ios-deploy.m
index 25ea073..31ad128 100644
--- a/src/ios-deploy/ios-deploy.m
+++ b/src/ios-deploy/ios-deploy.m
@@ -12,6 +12,8 @@
#include <signal.h>
#include <getopt.h>
#include <pwd.h>
+#include <dlfcn.h>
+
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -75,6 +77,9 @@
mach_error_t AMDeviceSecureStartService(AMDeviceRef device, CFStringRef service_name, unsigned int *unknown, ServiceConnRef * handle);
mach_error_t AMDeviceCreateHouseArrestService(AMDeviceRef device, CFStringRef identifier, CFDictionaryRef options, AFCConnectionRef * handle);
CFSocketNativeHandle AMDServiceConnectionGetSocket(ServiceConnRef con);
+void AMDServiceConnectionInvalidate(ServiceConnRef con);
+
+bool AMDeviceIsAtLeastVersionOnPlatform(AMDeviceRef device, CFDictionaryRef vers);
int AMDeviceSecureTransferPath(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, void *callback, int cbarg);
int AMDeviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, void *callback, int cbarg);
int AMDeviceSecureInstallApplicationBundle(AMDeviceRef device, CFURLRef url, CFDictionaryRef options, void *callback, int cbarg);
@@ -82,6 +87,9 @@
mach_error_t AMDeviceLookupApplications(AMDeviceRef device, CFDictionaryRef options, CFDictionaryRef *result);
int AMDeviceGetInterfaceType(AMDeviceRef device);
+int AMDServiceConnectionSend(ServiceConnRef con, const void * data, size_t size);
+int AMDServiceConnectionReceive(ServiceConnRef con, void * data, size_t size);
+
bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, debugserver_only = false, detect_only = false, install = true, uninstall = false, no_wifi = false;
bool command_only = false;
char *command = NULL;
@@ -104,7 +112,7 @@
NSMutableArray *_file_meta_info = nil;
int port = 0; // 0 means "dynamically assigned"
CFStringRef last_path = NULL;
-service_conn_t gdbfd;
+ServiceConnRef dbgServiceConnection = NULL;
pid_t parent = 0;
// PID of child process running lldb
pid_t child = 0;
@@ -135,6 +143,22 @@
} \
} while (false);
+
+void disable_ssl(ServiceConnRef con)
+{
+ // MobileDevice links with SSL, so function will be available;
+ typedef void (*SSL_free_t)(void*);
+ static SSL_free_t SSL_free = NULL;
+ if (SSL_free == NULL)
+ {
+ SSL_free = (SSL_free_t)dlsym(RTLD_DEFAULT, "SSL_free");
+ }
+
+ SSL_free(con->sslContext);
+ con->sslContext = NULL;
+}
+
+
void on_error(NSString* format, ...)
{
va_list valist;
@@ -959,13 +983,24 @@
void
server_callback (CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info)
{
- if (CFDataGetLength (data) == 0) {
+ char buffer[0x1000];
+ int bytesRead = AMDServiceConnectionReceive(dbgServiceConnection, buffer, sizeof(buffer));
+ if (bytesRead == 0)
+ {
// close the socket on which we've got end-of-file, the server_socket.
CFSocketInvalidate(s);
CFRelease(s);
return;
}
- write(CFSocketGetNative(lldb_socket), CFDataGetBytePtr(data), CFDataGetLength(data));
+ write(CFSocketGetNative (lldb_socket), buffer, bytesRead);
+ while (bytesRead == sizeof(buffer))
+ {
+ bytesRead = AMDServiceConnectionReceive(dbgServiceConnection, buffer, sizeof(buffer));
+ if (bytesRead > 0)
+ {
+ write(CFSocketGetNative (lldb_socket), buffer, bytesRead);
+ }
+ }
}
void lldb_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info)
@@ -978,7 +1013,8 @@
CFRelease(s);
return;
}
- write (gdbfd, CFDataGetBytePtr (data), CFDataGetLength (data));
+ int sent = AMDServiceConnectionSend(dbgServiceConnection, CFDataGetBytePtr(data), CFDataGetLength (data));
+ assert (CFDataGetLength (data) == sent);
}
void fdvendor_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {
@@ -1012,8 +1048,19 @@
void start_remote_debug_server(AMDeviceRef device) {
- ServiceConnRef con = NULL;
- int start_err = AMDeviceSecureStartService(device, CFSTR("com.apple.debugserver"), NULL, &con);
+ dbgServiceConnection = NULL;
+ CFStringRef serviceName = CFSTR("com.apple.debugserver");
+ CFStringRef keys[] = { CFSTR("MinIPhoneVersion"), CFSTR("MinAppleTVVersion") };
+ CFStringRef values[] = { CFSTR("14.0"), CFSTR("14.0")};
+ CFDictionaryRef version = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ bool useSecureProxy = AMDeviceIsAtLeastVersionOnPlatform(device, version);
+ if (useSecureProxy)
+ {
+ serviceName = CFSTR("com.apple.debugserver.DVTSecureSocketProxy");
+ }
+
+ int start_err = AMDeviceSecureStartService(device, serviceName, NULL, &dbgServiceConnection);
if (start_err != 0)
{
// After we mount the image, iOS needs to scan the image to register new services.
@@ -1037,15 +1084,20 @@
default:
check_error(start_err);
}
- check_error(AMDeviceSecureStartService(device, CFSTR("com.apple.debugserver"), NULL, &con));
+ check_error(AMDeviceSecureStartService(device, serviceName, NULL, &dbgServiceConnection));
}
- assert(con != NULL);
- gdbfd = AMDServiceConnectionGetSocket(con);
+ assert(dbgServiceConnection != NULL);
+
+ if (!useSecureProxy)
+ {
+ disable_ssl(dbgServiceConnection);
+ }
+
/*
* The debugserver connection is through a fd handle, while lldb requires a host/port to connect, so create an intermediate
* socket to transfer data.
*/
- server_socket = CFSocketCreateWithNative (NULL, gdbfd, kCFSocketDataCallBack, &server_callback, NULL);
+ server_socket = CFSocketCreateWithNative (NULL, AMDServiceConnectionGetSocket(dbgServiceConnection), kCFSocketReadCallBack, &server_callback, NULL);
if (server_socket_runloop) {
CFRelease(server_socket_runloop);
}
@@ -2007,7 +2059,7 @@
CFStringRef values[] = { CFSTR("Developer") };
options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
check_error(AMDeviceSecureTransferPath(0, device, url, options, transfer_callback, 0));
- close(*afcFd);
+ AMDServiceConnectionInvalidate(afcFd);
connect_and_start_session(device);
check_error(AMDeviceSecureInstallApplication(0, device, url, options, install_callback, 0));