From e7fc37d81e26897c4c2214b49d6c9c694f352404 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 19 Apr 2022 11:03:08 +0100 Subject: [PATCH] Catch SecurityExceptions from all ConnectivityManager calls. This issue occurs on Android 11 and no fix is expected. When the issue occurs, Tor connectivity and outgoing LAN connectivity will be broken until the app is restarted. --- .../network/AndroidNetworkManager.java | 58 +++++++++------ .../plugin/tcp/AndroidLanTcpPlugin.java | 41 +++++++---- .../reporting/BriarReportCollector.java | 73 ++++++++++--------- 3 files changed, 101 insertions(+), 71 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/network/AndroidNetworkManager.java b/bramble-android/src/main/java/org/briarproject/bramble/network/AndroidNetworkManager.java index dd6f91018..2f1195fc6 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/network/AndroidNetworkManager.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/network/AndroidNetworkManager.java @@ -111,15 +111,21 @@ class AndroidNetworkManager implements NetworkManager, Service { @Override public NetworkStatus getNetworkStatus() { - NetworkInfo net = connectivityManager.getActiveNetworkInfo(); - boolean connected = net != null && net.isConnected(); - boolean wifi = false, ipv6Only = false; - if (connected) { - wifi = net.getType() == TYPE_WIFI; - if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only(); - else ipv6Only = areAllAvailableNetworksIpv6Only(); + // https://issuetracker.google.com/issues/175055271 + try { + NetworkInfo net = connectivityManager.getActiveNetworkInfo(); + boolean connected = net != null && net.isConnected(); + boolean wifi = false, ipv6Only = false; + if (connected) { + wifi = net.getType() == TYPE_WIFI; + if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only(); + else ipv6Only = areAllAvailableNetworksIpv6Only(); + } + return new NetworkStatus(connected, wifi, ipv6Only); + } catch (SecurityException e) { + logException(LOG, WARNING, e); + return new NetworkStatus(false, false, false); } - return new NetworkStatus(connected, wifi, ipv6Only); } /** @@ -130,23 +136,29 @@ class AndroidNetworkManager implements NetworkManager, Service { */ @TargetApi(23) private boolean isActiveNetworkIpv6Only() { - Network net = connectivityManager.getActiveNetwork(); - if (net == null) { - LOG.info("No active network"); + // https://issuetracker.google.com/issues/175055271 + try { + Network net = connectivityManager.getActiveNetwork(); + if (net == null) { + LOG.info("No active network"); + return false; + } + LinkProperties props = connectivityManager.getLinkProperties(net); + if (props == null) { + LOG.info("No link properties for active network"); + return false; + } + boolean hasIpv6Unicast = false; + for (LinkAddress linkAddress : props.getLinkAddresses()) { + InetAddress addr = linkAddress.getAddress(); + if (addr instanceof Inet4Address) return false; + if (!addr.isMulticastAddress()) hasIpv6Unicast = true; + } + return hasIpv6Unicast; + } catch (SecurityException e) { + logException(LOG, WARNING, e); return false; } - LinkProperties props = connectivityManager.getLinkProperties(net); - if (props == null) { - LOG.info("No link properties for active network"); - return false; - } - boolean hasIpv6Unicast = false; - for (LinkAddress linkAddress : props.getLinkAddresses()) { - InetAddress addr = linkAddress.getAddress(); - if (addr instanceof Inet4Address) return false; - if (!addr.isMulticastAddress()) hasIpv6Unicast = true; - } - return hasIpv6Unicast; } /** diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index 22dfbe8df..11e164148 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -175,16 +175,24 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { @TargetApi(21) @Nullable private InetAddress getWifiClientIpv6Address() { - for (Network net : connectivityManager.getAllNetworks()) { - NetworkCapabilities caps = - connectivityManager.getNetworkCapabilities(net); - if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) continue; - LinkProperties props = connectivityManager.getLinkProperties(net); - if (props == null) continue; - for (LinkAddress linkAddress : props.getLinkAddresses()) { - InetAddress addr = linkAddress.getAddress(); - if (isIpv6LinkLocalAddress(addr)) return addr; + // https://issuetracker.google.com/issues/175055271 + try { + for (Network net : connectivityManager.getAllNetworks()) { + NetworkCapabilities caps = + connectivityManager.getNetworkCapabilities(net); + if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) { + continue; + } + LinkProperties props = + connectivityManager.getLinkProperties(net); + if (props == null) continue; + for (LinkAddress linkAddress : props.getLinkAddresses()) { + InetAddress addr = linkAddress.getAddress(); + if (isIpv6LinkLocalAddress(addr)) return addr; + } } + } catch (SecurityException e) { + logException(LOG, WARNING, e); } return null; } @@ -227,12 +235,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { // network's socket factory may try to connect via another network private SocketFactory getSocketFactory() { if (SDK_INT < 21) return SocketFactory.getDefault(); - for (Network net : connectivityManager.getAllNetworks()) { - NetworkCapabilities caps = - connectivityManager.getNetworkCapabilities(net); - if (caps != null && caps.hasTransport(TRANSPORT_WIFI)) { - return net.getSocketFactory(); + // https://issuetracker.google.com/issues/175055271 + try { + for (Network net : connectivityManager.getAllNetworks()) { + NetworkCapabilities caps = + connectivityManager.getNetworkCapabilities(net); + if (caps != null && caps.hasTransport(TRANSPORT_WIFI)) { + return net.getSocketFactory(); + } } + } catch (SecurityException e) { + logException(LOG, WARNING, e); } LOG.warning("Could not find suitable socket factory"); return SocketFactory.getDefault(); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java index b6ea21664..f3c5bf7e5 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/reporting/BriarReportCollector.java @@ -198,38 +198,47 @@ class BriarReportCollector { private ReportItem getConnectivity() { MultiReportInfo connectivityInfo = new MultiReportInfo(); - // Is mobile data available? - ConnectivityManager cm = requireNonNull( - getSystemService(ctx, ConnectivityManager.class)); - NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); - boolean mobileAvailable = mobile != null && mobile.isAvailable(); - connectivityInfo.add("MobileDataAvailable", mobileAvailable); - - // Is mobile data enabled? - boolean mobileEnabled = false; + // https://issuetracker.google.com/issues/175055271 try { - Class clazz = Class.forName(cm.getClass().getName()); - Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); - method.setAccessible(true); - mobileEnabled = (Boolean) requireNonNull(method.invoke(cm)); - } catch (ClassNotFoundException - | NoSuchMethodException - | IllegalArgumentException - | InvocationTargetException - | IllegalAccessException e) { - connectivityInfo - .add("MobileDataReflectionException", e.toString()); + // Is mobile data available? + ConnectivityManager cm = requireNonNull( + getSystemService(ctx, ConnectivityManager.class)); + NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE); + boolean mobileAvailable = mobile != null && mobile.isAvailable(); + connectivityInfo.add("MobileDataAvailable", mobileAvailable); + + // Is mobile data enabled? + boolean mobileEnabled = false; + try { + Class clazz = Class.forName(cm.getClass().getName()); + Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); + method.setAccessible(true); + mobileEnabled = (Boolean) requireNonNull(method.invoke(cm)); + } catch (ClassNotFoundException + | NoSuchMethodException + | IllegalArgumentException + | InvocationTargetException + | IllegalAccessException e) { + connectivityInfo + .add("MobileDataReflectionException", e.toString()); + } + connectivityInfo.add("MobileDataEnabled", mobileEnabled); + + // Is mobile data connected ? + boolean mobileConnected = mobile != null && mobile.isConnected(); + connectivityInfo.add("MobileDataConnected", mobileConnected); + + // Is wifi available? + NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); + boolean wifiAvailable = wifi != null && wifi.isAvailable(); + connectivityInfo.add("WifiAvailable", wifiAvailable); + + // Is wifi connected? + boolean wifiConnected = wifi != null && wifi.isConnected(); + connectivityInfo.add("WifiConnected", wifiConnected); + } catch (SecurityException e) { + connectivityInfo.add("ConnectivityManagerException", e.toString()); } - connectivityInfo.add("MobileDataEnabled", mobileEnabled); - - // Is mobile data connected ? - boolean mobileConnected = mobile != null && mobile.isConnected(); - connectivityInfo.add("MobileDataConnected", mobileConnected); - - // Is wifi available? - NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI); - boolean wifiAvailable = wifi != null && wifi.isAvailable(); - connectivityInfo.add("WifiAvailable", wifiAvailable); // Is wifi enabled? WifiManager wm = getSystemService(ctx, WifiManager.class); @@ -237,10 +246,6 @@ class BriarReportCollector { wm.getWifiState() == WIFI_STATE_ENABLED; connectivityInfo.add("WifiEnabled", wifiEnabled); - // Is wifi connected? - boolean wifiConnected = wifi != null && wifi.isConnected(); - connectivityInfo.add("WifiConnected", wifiConnected); - // Is wifi direct supported? boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null; connectivityInfo.add("WiFiDirectSupported", wifiDirect);