Merge "Only allow System apps to make VPN exempt routes" into klp-dev

This commit is contained in:
Chad Brubaker
2014-03-11 17:51:50 +00:00
committed by Android (Google) Code Review
2 changed files with 84 additions and 6 deletions

View File

@@ -32,6 +32,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -43,7 +44,9 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -412,6 +415,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private SettingsObserver mSettingsObserver;
private AppOpsManager mAppOpsManager;
NetworkConfig[] mNetConfigs;
int mNetworksDefined;
@@ -695,6 +700,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
filter = new IntentFilter();
filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
mContext.registerReceiver(mProvisioningReceiver, filter);
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
/**
@@ -1526,6 +1533,40 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
/**
* Check if the address falls into any of currently running VPN's route's.
*/
private boolean isAddressUnderVpn(InetAddress address) {
synchronized (mVpns) {
synchronized (mRoutesLock) {
int uid = UserHandle.getCallingUserId();
Vpn vpn = mVpns.get(uid);
if (vpn == null) {
return false;
}
// Check if an exemption exists for this address.
for (LinkAddress destination : mExemptAddresses) {
if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) {
continue;
}
int prefix = destination.getNetworkPrefixLength();
InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
prefix);
if (addrMasked.equals(destMasked)) {
return false;
}
}
// Finally check if the address is covered by the VPN.
return vpn.isAddressCovered(address);
}
}
}
/**
* @deprecated use requestRouteToHostAddress instead
*
@@ -1562,6 +1603,34 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mProtectedNetworks.contains(networkType)) {
enforceConnectivityInternalPermission();
}
boolean exempt;
InetAddress addr;
try {
addr = InetAddress.getByAddress(hostAddress);
} catch (UnknownHostException e) {
if (DBG) log("requestRouteToHostAddress got " + e.toString());
return false;
}
// System apps may request routes bypassing the VPN to keep other networks working.
if (Binder.getCallingUid() == Process.SYSTEM_UID) {
exempt = true;
} else {
mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
try {
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName,
0);
exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
} catch (NameNotFoundException e) {
throw new IllegalArgumentException("Failed to find calling package details", e);
}
}
// Non-exempt routeToHost's can only be added if the host is not covered by the VPN.
// This can be either because the VPN's routes do not cover the destination or a
// system application added an exemption that covers this destination.
if (!exempt && isAddressUnderVpn(addr)) {
return false;
}
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
@@ -1585,18 +1654,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
final long token = Binder.clearCallingIdentity();
try {
InetAddress addr = InetAddress.getByAddress(hostAddress);
LinkProperties lp = tracker.getLinkProperties();
boolean ok = addRouteToAddress(lp, addr, EXEMPT);
boolean ok = addRouteToAddress(lp, addr, exempt);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
return ok;
} catch (UnknownHostException e) {
if (DBG) log("requestRouteToHostAddress got " + e.toString());
} finally {
Binder.restoreCallingIdentity(token);
}
if (DBG) log("requestRouteToHostAddress X bottom return false");
return false;
}
private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,

View File

@@ -45,6 +45,7 @@ import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
@@ -77,6 +78,7 @@ import com.android.server.net.BaseNetworkObserver;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
@@ -435,6 +437,18 @@ public class Vpn extends BaseNetworkStateTracker {
return tun;
}
/**
* Check if a given address is covered by the VPN's routing rules.
*/
public boolean isAddressCovered(InetAddress address) {
synchronized (Vpn.this) {
if (!isRunningLocked()) {
return false;
}
return RouteInfo.selectBestRoute(mConfig.routes, address) != null;
}
}
private boolean isRunningLocked() {
return mVpnUsers != null;
}