Merge branch '1980-catch-security-exceptions-from-connectivity-manager' into 'master'

Catch SecurityExceptions from all ConnectivityManager calls

Closes #1980

See merge request briar/briar!1634
This commit is contained in:
akwizgran
2022-04-20 14:51:57 +00:00
3 changed files with 120 additions and 71 deletions

View File

@@ -11,6 +11,8 @@ import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.Network; import android.net.Network;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.event.EventExecutor;
@@ -38,6 +40,7 @@ import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static android.content.Context.CONNECTIVITY_SERVICE; import static android.content.Context.CONNECTIVITY_SERVICE;
import static android.content.Context.WIFI_SERVICE;
import static android.content.Intent.ACTION_SCREEN_OFF; import static android.content.Intent.ACTION_SCREEN_OFF;
import static android.content.Intent.ACTION_SCREEN_ON; import static android.content.Intent.ACTION_SCREEN_ON;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -111,15 +114,37 @@ class AndroidNetworkManager implements NetworkManager, Service {
@Override @Override
public NetworkStatus getNetworkStatus() { public NetworkStatus getNetworkStatus() {
NetworkInfo net = connectivityManager.getActiveNetworkInfo(); // https://issuetracker.google.com/issues/175055271
boolean connected = net != null && net.isConnected(); try {
boolean wifi = false, ipv6Only = false; NetworkInfo net = connectivityManager.getActiveNetworkInfo();
if (connected) { boolean connected = net != null && net.isConnected();
wifi = net.getType() == TYPE_WIFI; boolean wifi = false, ipv6Only = false;
if (SDK_INT >= 23) ipv6Only = isActiveNetworkIpv6Only(); if (connected) {
else ipv6Only = areAllAvailableNetworksIpv6Only(); 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);
// Without the ConnectivityManager we can't detect whether we have
// internet access. Assume we do, which is probably less harmful
// than assuming we don't. Likewise, assume the connection is
// IPv6-only. Fall back to the WifiManager to detect whether we
// have a wifi connection.
LOG.info("ConnectivityManager is broken, guessing connectivity");
boolean connected = true, wifi = false, ipv6Only = true;
WifiManager wm = (WifiManager) app.getSystemService(WIFI_SERVICE);
if (wm != null) {
WifiInfo info = wm.getConnectionInfo();
if (info != null && info.getIpAddress() != 0) {
LOG.info("Connected to wifi");
wifi = true;
ipv6Only = false;
}
}
return new NetworkStatus(connected, wifi, ipv6Only);
} }
return new NetworkStatus(connected, wifi, ipv6Only);
} }
/** /**
@@ -130,23 +155,29 @@ class AndroidNetworkManager implements NetworkManager, Service {
*/ */
@TargetApi(23) @TargetApi(23)
private boolean isActiveNetworkIpv6Only() { private boolean isActiveNetworkIpv6Only() {
Network net = connectivityManager.getActiveNetwork(); // https://issuetracker.google.com/issues/175055271
if (net == null) { try {
LOG.info("No active network"); 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; 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;
} }
/** /**

View File

@@ -175,16 +175,24 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
@TargetApi(21) @TargetApi(21)
@Nullable @Nullable
private InetAddress getWifiClientIpv6Address() { private InetAddress getWifiClientIpv6Address() {
for (Network net : connectivityManager.getAllNetworks()) { // https://issuetracker.google.com/issues/175055271
NetworkCapabilities caps = try {
connectivityManager.getNetworkCapabilities(net); for (Network net : connectivityManager.getAllNetworks()) {
if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) continue; NetworkCapabilities caps =
LinkProperties props = connectivityManager.getLinkProperties(net); connectivityManager.getNetworkCapabilities(net);
if (props == null) continue; if (caps == null || !caps.hasTransport(TRANSPORT_WIFI)) {
for (LinkAddress linkAddress : props.getLinkAddresses()) { continue;
InetAddress addr = linkAddress.getAddress(); }
if (isIpv6LinkLocalAddress(addr)) return addr; 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; return null;
} }
@@ -227,12 +235,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// network's socket factory may try to connect via another network // network's socket factory may try to connect via another network
private SocketFactory getSocketFactory() { private SocketFactory getSocketFactory() {
if (SDK_INT < 21) return SocketFactory.getDefault(); if (SDK_INT < 21) return SocketFactory.getDefault();
for (Network net : connectivityManager.getAllNetworks()) { // https://issuetracker.google.com/issues/175055271
NetworkCapabilities caps = try {
connectivityManager.getNetworkCapabilities(net); for (Network net : connectivityManager.getAllNetworks()) {
if (caps != null && caps.hasTransport(TRANSPORT_WIFI)) { NetworkCapabilities caps =
return net.getSocketFactory(); 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"); LOG.warning("Could not find suitable socket factory");
return SocketFactory.getDefault(); return SocketFactory.getDefault();

View File

@@ -198,38 +198,47 @@ class BriarReportCollector {
private ReportItem getConnectivity() { private ReportItem getConnectivity() {
MultiReportInfo connectivityInfo = new MultiReportInfo(); MultiReportInfo connectivityInfo = new MultiReportInfo();
// Is mobile data available? // https://issuetracker.google.com/issues/175055271
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 { try {
Class<?> clazz = Class.forName(cm.getClass().getName()); // Is mobile data available?
Method method = clazz.getDeclaredMethod("getMobileDataEnabled"); ConnectivityManager cm = requireNonNull(
method.setAccessible(true); getSystemService(ctx, ConnectivityManager.class));
mobileEnabled = (Boolean) requireNonNull(method.invoke(cm)); NetworkInfo mobile = cm.getNetworkInfo(TYPE_MOBILE);
} catch (ClassNotFoundException boolean mobileAvailable = mobile != null && mobile.isAvailable();
| NoSuchMethodException connectivityInfo.add("MobileDataAvailable", mobileAvailable);
| IllegalArgumentException
| InvocationTargetException // Is mobile data enabled?
| IllegalAccessException e) { boolean mobileEnabled = false;
connectivityInfo try {
.add("MobileDataReflectionException", e.toString()); 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? // Is wifi enabled?
WifiManager wm = getSystemService(ctx, WifiManager.class); WifiManager wm = getSystemService(ctx, WifiManager.class);
@@ -237,10 +246,6 @@ class BriarReportCollector {
wm.getWifiState() == WIFI_STATE_ENABLED; wm.getWifiState() == WIFI_STATE_ENABLED;
connectivityInfo.add("WifiEnabled", wifiEnabled); connectivityInfo.add("WifiEnabled", wifiEnabled);
// Is wifi connected?
boolean wifiConnected = wifi != null && wifi.isConnected();
connectivityInfo.add("WifiConnected", wifiConnected);
// Is wifi direct supported? // Is wifi direct supported?
boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null; boolean wifiDirect = ctx.getSystemService(WIFI_P2P_SERVICE) != null;
connectivityInfo.add("WiFiDirectSupported", wifiDirect); connectivityInfo.add("WiFiDirectSupported", wifiDirect);