tunnel: avoid race between shutdown and stats

wgTurnOff can block for a while, in which case, calling getStatistics
will use a stale handle and stale tunnel. Not only that, but wgGetConfig
might return null, in which case string.split throws.

    java.lang.NullPointerException: Attempt to invoke virtual method
    'java.lang.String[] java.lang.String.split(java.lang.String)' on a null
    at com.wireguard.android.backend.GoBackend.getStatistics

Reported-by: tomt@adslweb.co.uk
Link: https://lists.zx2c4.com/pipermail/wireguard/2021-May/006709.html
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2021-05-06 10:45:43 +02:00
parent bcd8c33005
commit d6a8e9d4dc

View File

@ -68,7 +68,7 @@ public final class GoBackend implements Backend {
alwaysOnCallback = cb; alwaysOnCallback = cb;
} }
private static native String wgGetConfig(int handle); @Nullable private static native String wgGetConfig(int handle);
private static native int wgGetSocketV4(int handle); private static native int wgGetSocketV4(int handle);
@ -115,10 +115,11 @@ public final class GoBackend implements Backend {
@Override @Override
public Statistics getStatistics(final Tunnel tunnel) { public Statistics getStatistics(final Tunnel tunnel) {
final Statistics stats = new Statistics(); final Statistics stats = new Statistics();
if (tunnel != currentTunnel) { if (tunnel != currentTunnel || currentTunnelHandle == -1)
return stats; return stats;
}
final String config = wgGetConfig(currentTunnelHandle); final String config = wgGetConfig(currentTunnelHandle);
if (config == null)
return stats;
Key key = null; Key key = null;
long rx = 0; long rx = 0;
long tx = 0; long tx = 0;
@ -294,11 +295,11 @@ public final class GoBackend implements Backend {
Log.w(TAG, "Tunnel already down"); Log.w(TAG, "Tunnel already down");
return; return;
} }
int handleToClose = currentTunnelHandle;
wgTurnOff(currentTunnelHandle);
currentTunnel = null; currentTunnel = null;
currentTunnelHandle = -1; currentTunnelHandle = -1;
currentConfig = null; currentConfig = null;
wgTurnOff(handleToClose);
} }
tunnel.onStateChange(state); tunnel.onStateChange(state);