Skip to content

Commit

Permalink
fruity: Account for frida-server bind() delay
Browse files Browse the repository at this point in the history
Where we just opened the tunnel, but frida-server hasn't yet noticed the
new interface and had a chance to bind() on it. This means we should
wait a bit and try again. Otherwise we may end up falling back to
usbmuxd, and use a less desirable transport. And if we're really
unlucky, even that could fail, and we'd end up falling back to jailed
mode.

Co-authored-by: Håvard Sørbø <[email protected]>
  • Loading branch information
oleavr and hsorbo committed Nov 26, 2024
1 parent 1bd9d38 commit ef4fa0d
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/fruity/device-monitor-macos.vala
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ namespace Frida.Fruity {
}
}

public int64 opened_at {
get {
return _opened_at;
}
}

public Darwin.Xpc.Uuid? assertion_identifier {
get {
return _assertion_identifier;
Expand All @@ -256,6 +262,7 @@ namespace Frida.Fruity {
private Darwin.Xpc.Uuid? _assertion_identifier;
private InetAddress? tunnel_device_address;
private DiscoveryService? _discovery;
private int64 _opened_at = -1;

public MacOSTunnel (XpcClient pairing_device) {
this.pairing_device = pairing_device;
Expand All @@ -275,6 +282,8 @@ namespace Frida.Fruity {
r.body.set_int64 ("flags", 0);
var response = yield pairing_device.request (r.message, cancellable);

_opened_at = get_monotonic_time ();

var reader = new XpcObjectReader (response);
reader.read_member ("response");

Expand Down
22 changes: 22 additions & 0 deletions src/fruity/device-monitor.vala
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,10 @@ namespace Frida.Fruity {
get;
}

public abstract int64 opened_at {
get;
}

public abstract async void close (Cancellable? cancellable) throws IOError;
public abstract async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError;
}
Expand Down Expand Up @@ -1635,9 +1639,16 @@ namespace Frida.Fruity {
}
}

public int64 opened_at {
get {
return _opened_at;
}
}

private UsbNcmDriver? ncm;
private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
private int64 _opened_at = -1;

public PortableUsbTunnel (UsbDevice device, NcmPeer peer, PairingStore store) {
Object (
Expand Down Expand Up @@ -1670,6 +1681,8 @@ namespace Frida.Fruity {
TunnelConnection tc = yield pairing_service.open_tunnel (ncm_peer.ip, netstack, cancellable);
tc.closed.connect (on_tunnel_connection_close);

_opened_at = get_monotonic_time ();

var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
port: tc.remote_rsd_port,
Expand Down Expand Up @@ -1831,8 +1844,15 @@ namespace Frida.Fruity {
}
}

public int64 opened_at {
get {
return _opened_at;
}
}

private TunnelConnection? tunnel_connection;
private DiscoveryService? _discovery_service;
private int64 _opened_at = -1;

private const uint PAIRING_CONNECTION_TIMEOUT = 2000;

Expand All @@ -1854,6 +1874,8 @@ namespace Frida.Fruity {

TunnelConnection tc = yield pairing_service.open_tunnel (endpoint.get_address (), netstack, cancellable);

_opened_at = get_monotonic_time ();

var rsd_endpoint = (InetSocketAddress) Object.new (typeof (InetSocketAddress),
address: tc.remote_address,
port: tc.remote_rsd_port,
Expand Down
48 changes: 46 additions & 2 deletions src/fruity/fruity-host-session.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1087,8 +1087,7 @@ namespace Frida {

DBusConnection? connection = null;
try {
var channel =
yield device.open_tcp_channel (DEFAULT_CONTROL_PORT.to_string (), ALLOW_ANY_TRANSPORT, cancellable);
var channel = yield connect_to_remote_server (cancellable);

IOStream stream = channel.stream;
WebServiceTransport transport = PLAIN;
Expand Down Expand Up @@ -1157,6 +1156,51 @@ namespace Frida {
}
}

private async Fruity.TcpChannel connect_to_remote_server (Cancellable? cancellable) throws Error, IOError {
var tunnel = yield device.find_tunnel (cancellable);
bool tunnel_recently_opened = tunnel != null && get_monotonic_time () - tunnel.opened_at < 1000000;

uint delays[] = { 0, 50, 250 };
uint max_attempts = tunnel_recently_opened ? delays.length : 1;
var main_context = MainContext.ref_thread_default ();

Error? pending_error = null;
for (uint attempts = 0; attempts != max_attempts; attempts++) {
uint delay = delays[attempts];
if (delay != 0) {
var timeout_source = new TimeoutSource (delay);
timeout_source.set_callback (connect_to_remote_server.callback);
timeout_source.attach (main_context);

var cancel_source = new CancellableSource (cancellable);
cancel_source.set_callback (connect_to_remote_server.callback);
cancel_source.attach (main_context);

yield;

cancel_source.destroy ();
timeout_source.destroy ();

if (cancellable.is_cancelled ())
break;
}

bool is_last_attempt = attempts == max_attempts - 1;
var open_flags = is_last_attempt
? Fruity.OpenTcpChannelFlags.ALLOW_ANY_TRANSPORT
: Fruity.OpenTcpChannelFlags.ALLOW_TUNNEL;

try {
return yield device.open_tcp_channel (DEFAULT_CONTROL_PORT.to_string (), open_flags, cancellable);
} catch (Error e) {
pending_error = e;
if (!(e is Error.SERVER_NOT_RUNNING))
break;
}
}
throw pending_error;
}

private void attach_remote_server (RemoteServer server) {
server.connection.on_closed.connect (on_remote_connection_closed);

Expand Down

0 comments on commit ef4fa0d

Please sign in to comment.