summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Kabir Oberai2021-07-25 17:13:19 +0200
committerGravatar Nikias Bassen2021-07-26 03:51:19 +0200
commit93622ece5bfd0c3e2e37c3ae643411c0284da9c8 (patch)
tree24c9e553f461669440aa76ba8792e4fc4ea0057b /src
parent65fddc7b67ae6bcebce54f0b55e4191332067c73 (diff)
downloadlibimobiledevice-93622ece5bfd0c3e2e37c3ae643411c0284da9c8.tar.gz
libimobiledevice-93622ece5bfd0c3e2e37c3ae643411c0284da9c8.tar.bz2
idevice: Route OpenSSL reads/writes through internal_connection_*
Let's not allow OpenSSL to directly access our file descriptors
Diffstat (limited to 'src')
-rw-r--r--src/idevice.c106
-rw-r--r--src/idevice.h2
2 files changed, 66 insertions, 42 deletions
diff --git a/src/idevice.c b/src/idevice.c
index ecc0418..a2a4d0b 100644
--- a/src/idevice.c
+++ b/src/idevice.c
@@ -432,6 +432,8 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
new_connection->data = (void*)(long)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
+ new_connection->ssl_recv_timeout = (unsigned int)-1;
+ new_connection->status = IDEVICE_E_SUCCESS;
*connection = new_connection;
return IDEVICE_E_SUCCESS;
} else if (device->conn_type == CONNECTION_NETWORK) {
@@ -478,6 +480,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connect(idevice_t device, uint16_t
new_connection->data = (void*)(long)sfd;
new_connection->ssl_data = NULL;
new_connection->device = device;
+ new_connection->ssl_recv_timeout = (unsigned int)-1;
*connection = new_connection;
@@ -558,15 +561,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_
}
if (connection->ssl_data) {
+ connection->status = IDEVICE_E_SUCCESS;
uint32_t sent = 0;
while (sent < len) {
#ifdef HAVE_OPENSSL
- int c = socket_check_fd((int)(long)connection->data, FDM_WRITE, 100);
- if (c == 0 || c == -ETIMEDOUT || c == -EAGAIN) {
- continue;
- } else if (c < 0) {
- break;
- }
int s = SSL_write(connection->ssl_data->session, (const void*)(data+sent), (int)(len-sent));
if (s <= 0) {
int sslerr = SSL_get_error(connection->ssl_data->session, s);
@@ -586,7 +584,7 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_send(idevice_connection_
debug_info("SSL_write %d, sent %d", len, sent);
if (sent < len) {
*sent_bytes = 0;
- return IDEVICE_E_SSL_ERROR;
+ return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status;
}
*sent_bytes = sent;
return IDEVICE_E_SUCCESS;
@@ -670,30 +668,17 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_
if (connection->ssl_data) {
uint32_t received = 0;
- int do_select = 1;
- idevice_error_t error = IDEVICE_E_SSL_ERROR;
+ if (connection->ssl_recv_timeout != (unsigned int)-1) {
+ debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout");
+ }
+
+ // this should be reset after the SSL_read call on all codepaths, as
+ // the supplied timeout should only apply to the current read.
+ connection->ssl_recv_timeout = timeout;
+ connection->status = IDEVICE_E_SUCCESS;
while (received < len) {
#ifdef HAVE_OPENSSL
- do_select = (SSL_pending(connection->ssl_data->session) == 0);
-#endif
- if (do_select) {
- int conn_error = socket_check_fd((int)(long)connection->data, FDM_READ, timeout);
- error = socket_recv_to_idevice_error(conn_error, len, received);
- switch (error) {
- case IDEVICE_E_SUCCESS:
- case IDEVICE_E_TIMEOUT:
- break;
- case IDEVICE_E_UNKNOWN_ERROR:
- default:
- debug_info("ERROR: socket_check_fd returned %d (%s)", conn_error, strerror(-conn_error));
- return error;
- }
- }
- if (error == IDEVICE_E_TIMEOUT) {
- break;
- }
-#ifdef HAVE_OPENSSL
int r = SSL_read(connection->ssl_data->session, (void*)((char*)(data+received)), (int)len-received);
if (r > 0) {
received += r;
@@ -713,11 +698,12 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive_timeout(idevice_
}
#endif
}
+ connection->ssl_recv_timeout = (unsigned int)-1;
debug_info("SSL_read %d, received %d", len, received);
if (received < len) {
*recv_bytes = received;
- return error;
+ return connection->status == IDEVICE_E_SUCCESS ? IDEVICE_E_SSL_ERROR : connection->status;
}
*recv_bytes = received;
@@ -763,6 +749,10 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_receive(idevice_connecti
}
if (connection->ssl_data) {
+ if (connection->ssl_recv_timeout != (unsigned int)-1) {
+ debug_info("WARNING: ssl_recv_timeout was not properly reset in idevice_connection_receive_timeout");
+ connection->ssl_recv_timeout = (unsigned int)-1;
+ }
#ifdef HAVE_OPENSSL
int received = SSL_read(connection->ssl_data->session, (void*)data, (int)len);
debug_info("SSL_read %d, received %d", len, received);
@@ -816,28 +806,36 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_get_udid(idevice_t device, char **u
return IDEVICE_E_SUCCESS;
}
-#ifndef HAVE_OPENSSL
/**
- * Internally used gnutls callback function for receiving encrypted data.
+ * Internally used SSL callback function for receiving encrypted data.
*/
-static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer, size_t length)
+static ssize_t internal_ssl_read(idevice_connection_t connection, char *buffer, size_t length)
{
int bytes = 0, pos_start_fill = 0;
size_t tbytes = 0;
int this_len = length;
idevice_error_t res;
- idevice_connection_t connection = (idevice_connection_t)transport;
char *recv_buffer;
debug_info("pre-read client wants %zi bytes", length);
recv_buffer = (char *)malloc(sizeof(char) * this_len);
+ unsigned int timeout = connection->ssl_recv_timeout;
+
/* repeat until we have the full data or an error occurs */
do {
- if ((res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes)) != IDEVICE_E_SUCCESS) {
- debug_info("ERROR: idevice_connection_receive returned %d", res);
- return res;
+ if (timeout == (unsigned int)-1) {
+ res = internal_connection_receive(connection, recv_buffer, this_len, (uint32_t*)&bytes);
+ } else {
+ res = internal_connection_receive_timeout(connection, recv_buffer, this_len, (uint32_t*)&bytes, (unsigned int)timeout);
+ }
+ if (res != IDEVICE_E_SUCCESS) {
+ if (res != IDEVICE_E_TIMEOUT) {
+ debug_info("ERROR: %s returned %d", (timeout == (unsigned int)-1) ? "internal_connection_receive" : "internal_connection_receive_timeout", res);
+ }
+ connection->status = res;
+ return -1;
}
debug_info("post-read we got %i bytes", bytes);
@@ -863,22 +861,21 @@ static ssize_t internal_ssl_read(gnutls_transport_ptr_t transport, char *buffer,
}
/**
- * Internally used gnutls callback function for sending encrypted data.
+ * Internally used SSL callback function for sending encrypted data.
*/
-static ssize_t internal_ssl_write(gnutls_transport_ptr_t transport, char *buffer, size_t length)
+static ssize_t internal_ssl_write(idevice_connection_t connection, const char *buffer, size_t length)
{
uint32_t bytes = 0;
idevice_error_t res;
- idevice_connection_t connection = (idevice_connection_t)transport;
debug_info("pre-send length = %zi", length);
if ((res = internal_connection_send(connection, buffer, length, &bytes)) != IDEVICE_E_SUCCESS) {
debug_info("ERROR: internal_connection_send returned %d", res);
+ connection->status = res;
return -1;
}
debug_info("post-send sent %i bytes", bytes);
return bytes;
}
-#endif
/**
* Internally used function for cleaning up SSL stuff.
@@ -918,6 +915,32 @@ static void internal_ssl_cleanup(ssl_data_t ssl_data)
}
#ifdef HAVE_OPENSSL
+static long ssl_idevice_bio_callback(BIO *b, int oper, const char *argp, int argi, long argl, long retvalue)
+{
+ idevice_connection_t conn = (idevice_connection_t)BIO_get_callback_arg(b);
+ size_t len = (size_t)argi;
+ switch (oper) {
+ case (BIO_CB_READ|BIO_CB_RETURN):
+ return argp ? (long)internal_ssl_read(conn, (char *)argp, len) : 0;
+ case (BIO_CB_PUTS|BIO_CB_RETURN):
+ len = strlen(argp);
+ // fallthrough
+ case (BIO_CB_WRITE|BIO_CB_RETURN):
+ return (long)internal_ssl_write(conn, argp, len);
+ default:
+ return retvalue;
+ }
+}
+
+static BIO *ssl_idevice_bio_new(idevice_connection_t conn)
+{
+ BIO *b = BIO_new(BIO_s_null());
+ if (!b) return NULL;
+ BIO_set_callback_arg(b, (char *)conn);
+ BIO_set_callback(b, ssl_idevice_bio_callback);
+ return b;
+}
+
static int ssl_verify_callback(int ok, X509_STORE_CTX *ctx)
{
return 1;
@@ -1009,12 +1032,11 @@ LIBIMOBILEDEVICE_API idevice_error_t idevice_connection_enable_ssl(idevice_conne
if (pair_record)
plist_free(pair_record);
- BIO *ssl_bio = BIO_new(BIO_s_socket());
+ BIO *ssl_bio = ssl_idevice_bio_new(connection);
if (!ssl_bio) {
debug_info("ERROR: Could not create SSL bio.");
return ret;
}
- BIO_set_fd(ssl_bio, (int)(long)connection->data, BIO_NOCLOSE);
SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
if (ssl_ctx == NULL) {
diff --git a/src/idevice.h b/src/idevice.h
index 8709c9a..4e53a7f 100644
--- a/src/idevice.h
+++ b/src/idevice.h
@@ -68,6 +68,8 @@ struct idevice_connection_private {
enum idevice_connection_type type;
void *data;
ssl_data_t ssl_data;
+ unsigned int ssl_recv_timeout;
+ idevice_error_t status;
};
struct idevice_private {