Merge "Sanitize owner UID iff owning app does not have location permissions." am: 4d95254cb3

Change-Id: Ie5876d063d7440aacc57d48cb4573798303910ea
This commit is contained in:
Automerger Merge Worker
2020-02-20 05:30:20 +00:00
5 changed files with 185 additions and 62 deletions

View File

@@ -1279,7 +1279,8 @@ public class ConnectivityManager {
@UnsupportedAppUsage @UnsupportedAppUsage
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
try { try {
return mService.getDefaultNetworkCapabilitiesForUser(userId); return mService.getDefaultNetworkCapabilitiesForUser(
userId, mContext.getOpPackageName());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -1361,7 +1362,7 @@ public class ConnectivityManager {
@Nullable @Nullable
public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) { public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
try { try {
return mService.getNetworkCapabilities(network); return mService.getNetworkCapabilities(network, mContext.getOpPackageName());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -4036,10 +4037,9 @@ public class ConnectivityManager {
@NonNull PendingIntent operation) { @NonNull PendingIntent operation) {
printStackTrace(); printStackTrace();
checkPendingIntentNotNull(operation); checkPendingIntentNotNull(operation);
final String callingPackageName = mContext.getOpPackageName();
try { try {
mService.pendingRequestForNetwork( mService.pendingRequestForNetwork(
request.networkCapabilities, operation, callingPackageName); request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {
@@ -4151,10 +4151,9 @@ public class ConnectivityManager {
@NonNull PendingIntent operation) { @NonNull PendingIntent operation) {
printStackTrace(); printStackTrace();
checkPendingIntentNotNull(operation); checkPendingIntentNotNull(operation);
final String callingPackageName = mContext.getOpPackageName();
try { try {
mService.pendingListenForNetwork( mService.pendingListenForNetwork(
request.networkCapabilities, operation, callingPackageName); request.networkCapabilities, operation, mContext.getOpPackageName());
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) {

View File

@@ -59,7 +59,8 @@ interface IConnectivityManager
NetworkInfo[] getAllNetworkInfo(); NetworkInfo[] getAllNetworkInfo();
Network getNetworkForType(int networkType); Network getNetworkForType(int networkType);
Network[] getAllNetworks(); Network[] getAllNetworks();
NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId); NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
int userId, String callingPackageName);
boolean isNetworkSupported(int networkType); boolean isNetworkSupported(int networkType);
@@ -68,7 +69,7 @@ interface IConnectivityManager
LinkProperties getLinkPropertiesForType(int networkType); LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network); LinkProperties getLinkProperties(in Network network);
NetworkCapabilities getNetworkCapabilities(in Network network); NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
@UnsupportedAppUsage @UnsupportedAppUsage
NetworkState[] getAllNetworkState(); NetworkState[] getAllNetworkState();

View File

@@ -830,6 +830,23 @@ public final class NetworkCapabilities implements Parcelable {
* <p>This field keeps track of the UID of the app that created this network and is in charge of * <p>This field keeps track of the UID of the app that created this network and is in charge of
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
* VPN, or Carrier Service app managing a cellular data connection. * VPN, or Carrier Service app managing a cellular data connection.
*
* <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
* reset to Process.INVALID_UID unless all the following conditions are met:
*
* <ol>
* <li>The destination app is the network owner
* <li>The destination app has the ACCESS_FINE_LOCATION permission granted
* <li>The user's location toggle is on
* </ol>
*
* This is because the owner UID is location-sensitive. The apps that request a network could
* know where the device is if they can tell for sure the system has connected to the network
* they requested.
*
* <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
* an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
* server.
*/ */
private int mOwnerUid = Process.INVALID_UID; private int mOwnerUid = Process.INVALID_UID;
@@ -842,7 +859,16 @@ public final class NetworkCapabilities implements Parcelable {
} }
/** /**
* Retrieves the UID of the owner app. * Retrieves the UID of the app that owns this network.
*
* <p>For user privacy reasons, this field will only be populated if:
*
* <ol>
* <li>The calling app is the network owner
* <li>The calling app has the ACCESS_FINE_LOCATION permission granted
* <li>The user's location toggle is on
* </ol>
*
*/ */
public int getOwnerUid() { public int getOwnerUid() {
return mOwnerUid; return mOwnerUid;
@@ -880,8 +906,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param administratorUids the UIDs to be set as administrators of this Network. * @param administratorUids the UIDs to be set as administrators of this Network.
* @hide * @hide
*/ */
@NonNull
@SystemApi @SystemApi
public @NonNull NetworkCapabilities setAdministratorUids( public NetworkCapabilities setAdministratorUids(
@NonNull final List<Integer> administratorUids) { @NonNull final List<Integer> administratorUids) {
mAdministratorUids.clear(); mAdministratorUids.clear();
mAdministratorUids.addAll(administratorUids); mAdministratorUids.addAll(administratorUids);

View File

@@ -1536,7 +1536,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
@Override @Override
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) { public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
int userId, String callingPackageName) {
// The basic principle is: if an app's traffic could possibly go over a // The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific, // network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in // (hence, by "default"), then include that network's capabilities in
@@ -1558,7 +1559,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkAgentInfo nai = getDefaultNetwork(); NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai); NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) { if (nc != null) {
result.put(nai.network, nc); result.put(
nai.network,
maybeSanitizeLocationInfoForCaller(
nc, Binder.getCallingUid(), callingPackageName));
} }
synchronized (mVpns) { synchronized (mVpns) {
@@ -1568,10 +1572,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
Network[] networks = vpn.getUnderlyingNetworks(); Network[] networks = vpn.getUnderlyingNetworks();
if (networks != null) { if (networks != null) {
for (Network network : networks) { for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network); nc = getNetworkCapabilitiesInternal(network);
nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) { if (nc != null) {
result.put(network, nc); result.put(
network,
maybeSanitizeLocationInfoForCaller(
nc, Binder.getCallingUid(), callingPackageName));
} }
} }
} }
@@ -1638,20 +1644,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) { private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai == null) return null; if (nai == null) return null;
synchronized (nai) { synchronized (nai) {
if (nai.networkCapabilities == null) return null; if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions( return networkCapabilitiesRestrictedForCallerPermissions(
nai.networkCapabilities, nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
Binder.getCallingPid(), Binder.getCallingUid());
} }
} }
@Override @Override
public NetworkCapabilities getNetworkCapabilities(Network network) { public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
enforceAccessPermission(); enforceAccessPermission();
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network)); return maybeSanitizeLocationInfoForCaller(
getNetworkCapabilitiesInternal(network),
Binder.getCallingUid(), callingPackageName);
} }
@VisibleForTesting @VisibleForTesting
@@ -1667,20 +1679,34 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
newNc.setAdministratorUids(Collections.EMPTY_LIST); newNc.setAdministratorUids(Collections.EMPTY_LIST);
maybeSanitizeLocationInfoForCaller(newNc, callerUid);
return newNc; return newNc;
} }
private void maybeSanitizeLocationInfoForCaller( @VisibleForTesting
NetworkCapabilities nc, int callerUid) { @Nullable
// TODO(b/142072839): Conditionally reset the owner UID if the following NetworkCapabilities maybeSanitizeLocationInfoForCaller(
// conditions are not met: @Nullable NetworkCapabilities nc, int callerUid, @NonNull String callerPkgName) {
// 1. The destination app is the network owner if (nc == null) {
// 2. The destination app has the ACCESS_COARSE_LOCATION permission granted return null;
// if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted }
// 3. The user's location toggle is on final NetworkCapabilities newNc = new NetworkCapabilities(nc);
nc.setOwnerUid(INVALID_UID); if (callerUid != newNc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
Binder.withCleanCallingIdentity(
() -> {
if (!mLocationPermissionChecker.checkLocationPermission(
callerPkgName, null /* featureId */, callerUid, null /* message */)) {
// Caller does not have the requisite location permissions. Reset the
// owner's UID in the NetworkCapabilities.
newNc.setOwnerUid(INVALID_UID);
}
}
);
return newNc;
} }
private LinkProperties linkPropertiesRestrictedForCallerPermissions( private LinkProperties linkPropertiesRestrictedForCallerPermissions(
@@ -1755,7 +1781,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public boolean isActiveNetworkMetered() { public boolean isActiveNetworkMetered() {
enforceAccessPermission(); enforceAccessPermission();
final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork()); final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
if (caps != null) { if (caps != null) {
return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else { } else {
@@ -5322,8 +5348,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
public String toString() { public String toString() {
return "uid/pid:" + mUid + "/" + mPid + " " + request + return "uid/pid:" + mUid + "/" + mPid + " " + request
(mPendingIntent == null ? "" : " to trigger " + mPendingIntent); + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
} }
} }
@@ -6416,8 +6442,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
switch (notificationType) { switch (notificationType) {
case ConnectivityManager.CALLBACK_AVAILABLE: { case ConnectivityManager.CALLBACK_AVAILABLE: {
putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions( final NetworkCapabilities nc =
networkAgent.networkCapabilities, nri.mPid, nri.mUid)); networkCapabilitiesRestrictedForCallerPermissions(
networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(
bundle,
maybeSanitizeLocationInfoForCaller(
nc, nri.mUid, nri.request.getRequestorPackageName()));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
networkAgent.linkProperties, nri.mPid, nri.mUid)); networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status. // For this notification, arg1 contains the blocked status.
@@ -6430,9 +6461,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
case ConnectivityManager.CALLBACK_CAP_CHANGED: { case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above. // networkAgent can't be null as it has been accessed a few lines above.
final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions( final NetworkCapabilities netCap =
networkAgent.networkCapabilities, nri.mPid, nri.mUid); networkCapabilitiesRestrictedForCallerPermissions(
putParcelable(bundle, nc); networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(
bundle,
maybeSanitizeLocationInfoForCaller(
netCap, nri.mUid, nri.request.getRequestorPackageName()));
break; break;
} }
case ConnectivityManager.CALLBACK_IP_CHANGED: { case ConnectivityManager.CALLBACK_IP_CHANGED: {

View File

@@ -1180,6 +1180,10 @@ public class ConnectivityServiceTest {
Arrays.asList(new UserInfo[] { Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0), new UserInfo(VPN_USER, "", 0),
})); }));
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not. // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 . // http://b/25897652 .
@@ -3041,7 +3045,7 @@ public class ConnectivityServiceTest {
networkCapabilities.addTransportType(TRANSPORT_WIFI) networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier()); .setNetworkSpecifier(new MatchAllNetworkSpecifier());
mService.requestNetwork(networkCapabilities, null, 0, null, mService.requestNetwork(networkCapabilities, null, 0, null,
ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME); ConnectivityManager.TYPE_WIFI, mContext.getPackageName());
}); });
class NonParcelableSpecifier extends NetworkSpecifier { class NonParcelableSpecifier extends NetworkSpecifier {
@@ -6438,17 +6442,89 @@ public class ConnectivityServiceTest {
assertEquals(wifiLp, mService.getActiveLinkProperties()); assertEquals(wifiLp, mService.getActiveLinkProperties());
} }
private void setupLocationPermissions(
int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
if (op != null) {
when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
if (perm != null) {
mServiceContext.setPermission(perm, PERMISSION_GRANTED);
}
}
private int getOwnerUidNetCapsForCallerPermission(int ownerUid, int callerUid) {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService
.maybeSanitizeLocationInfoForCaller(netCap, callerUid, mContext.getPackageName())
.getOwnerUid();
}
@Test @Test
public void testNetworkCapabilitiesRestrictedForCallerPermissions() { public void testMaybeSanitizeLocationInfoForCallerWithFineLocationAfterQ() throws Exception {
int callerUid = Process.myUid(); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
final NetworkCapabilities originalNc = new NetworkCapabilities(); Manifest.permission.ACCESS_FINE_LOCATION);
originalNc.setOwnerUid(callerUid);
final NetworkCapabilities newNc = final int myUid = Process.myUid();
mService.networkCapabilitiesRestrictedForCallerPermissions( assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
originalNc, Process.myPid(), callerUid); }
assertEquals(Process.INVALID_UID, newNc.getOwnerUid()); @Test
public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationPreQ() throws Exception {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
final int myUid = Process.myUid();
assertEquals(myUid, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
@Test
public void testMaybeSanitizeLocationInfoForCallerLocationOff() throws Exception {
// Test that even with fine location permission, and UIDs matching, the UID is sanitized.
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
@Test
public void testMaybeSanitizeLocationInfoForCallerWrongUid() throws Exception {
// Test that even with fine location permission, not being the owner leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid + 1, myUid));
}
@Test
public void testMaybeSanitizeLocationInfoForCallerWithCoarseLocationAfterQ() throws Exception {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
// Test that without the location permission, the owner field is sanitized.
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
}
@Test
public void testMaybeSanitizeLocationInfoForCallerWithoutLocationPermission() throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
// Test that without the location permission, the owner field is sanitized.
final int myUid = Process.myUid();
assertEquals(Process.INVALID_UID, getOwnerUidNetCapsForCallerPermission(myUid, myUid));
} }
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
@@ -6734,21 +6810,6 @@ public class ConnectivityServiceTest {
mContext.getOpPackageName())); mContext.getOpPackageName()));
} }
private void setupLocationPermissions(
int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = targetSdk;
when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
.thenReturn(applicationInfo);
when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()), eq(mContext.getPackageName())))
.thenReturn(AppOpsManager.MODE_ALLOWED);
mServiceContext.setPermission(perm, PERMISSION_GRANTED);
}
private void setUpConnectivityDiagnosticsCallback() throws Exception { private void setUpConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build(); final NetworkRequest request = new NetworkRequest.Builder().build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder); when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);