TransportInfo: Add a generic redaction mechanism

This replaces the existing mechanism for redacting location sensitive
fields with a more extensible mechanism. Currently supported redactions
are for the following permissions:
i. ACCESS_FINE_LOCATION
ii. LOCAL_MAC_ADDRESS
iii. NETWORK_SETTINGS

Also, removed WifiInfo from ConnectivityServiceTest to reduce cross
dependencies on wifi code.

Bug: 156867433
Bug: 162602799
Test: atest android.net
Test: atest com.android.server
Change-Id: I2bb980c624667a55c1383f13ab71b9b97ed6eeab
This commit is contained in:
Roshan Pius
2021-02-23 08:47:39 -08:00
parent c2ea3ab97d
commit 98f59ecb99
8 changed files with 570 additions and 171 deletions

View File

@@ -82,6 +82,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -235,7 +239,6 @@ import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
@@ -8838,29 +8841,34 @@ public class ConnectivityServiceTest {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, includeLocationSensitiveInfo, callerUid,
netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
mContext.getPackageName(), getAttributionTag())
.getOwnerUid();
}
private void verifyWifiInfoCopyNetCapsPermission(
private void verifyTransportInfoCopyNetCapsPermission(
int callerUid, boolean includeLocationSensitiveInfo,
boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
final WifiInfo wifiInfo = mock(WifiInfo.class);
when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, includeLocationSensitiveInfo, callerUid,
netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
verify(transportInfo).makeCopy(REDACT_NONE);
} else {
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
}
private void verifyOwnerUidAndWifiInfoNetCapsPermission(
private void verifyOwnerUidAndTransportInfoNetCapsPermission(
boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
final int myUid = Process.myUid();
final int expectedOwnerUidWithoutIncludeFlag =
@@ -8874,13 +8882,13 @@ public class ConnectivityServiceTest {
assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, true /* includeLocationSensitiveInfo */));
verifyWifiInfoCopyNetCapsPermission(myUid,
verifyTransportInfoCopyNetCapsPermission(myUid,
false, /* includeLocationSensitiveInfo */
shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
verifyWifiInfoCopyNetCapsPermission(myUid,
verifyTransportInfoCopyNetCapsPermission(myUid,
true, /* includeLocationSensitiveInfo */
shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
}
@@ -8890,15 +8898,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8908,15 +8916,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8927,15 +8935,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8945,15 +8953,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8963,11 +8971,11 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8990,11 +8998,11 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9004,14 +9012,193 @@ public class ConnectivityServiceTest {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// don't redact MAC_ADDRESS fields, only location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// redact both MAC_ADDRESS & location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
| REDACT_FOR_LOCAL_MAC_ADDRESS);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// don't redact NETWORK_SETTINGS fields, only location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// redact both NETWORK_SETTINGS & location sensitive fields.
verify(transportInfo).makeCopy(
REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
}
/**
* Test TransportInfo to verify redaction mechanism.
*/
private static class TestTransportInfo implements TransportInfo {
public final boolean locationRedacted;
public final boolean localMacAddressRedacted;
public final boolean settingsRedacted;
TestTransportInfo() {
locationRedacted = false;
localMacAddressRedacted = false;
settingsRedacted = false;
}
TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
boolean settingsRedacted) {
this.locationRedacted = locationRedacted;
this.localMacAddressRedacted =
localMacAddressRedacted;
this.settingsRedacted = settingsRedacted;
}
@Override
public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return new TestTransportInfo(
(redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
(redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
(redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
);
}
@Override
public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
| REDACT_FOR_NETWORK_SETTINGS;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof TestTransportInfo)) return false;
TestTransportInfo that = (TestTransportInfo) other;
return that.locationRedacted == this.locationRedacted
&& that.localMacAddressRedacted == this.localMacAddressRedacted
&& that.settingsRedacted == this.settingsRedacted;
}
@Override
public int hashCode() {
return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
}
}
private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
@NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
@NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
@NonNull TransportInfo expectedTransportInfo) throws Exception {
when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
final NetworkCapabilities ncTemplate =
new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
.setOwnerUid(actualOwnerUid);
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
ncTemplate);
mWiFiNetworkAgent.connect(false);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// Send network capabilities update with TransportInfo to trigger capabilities changed
// callback.
mWiFiNetworkAgent.setNetworkCapabilities(
ncTemplate.setTransportInfo(actualTransportInfo), true);
wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
&& Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
}
@Test
public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
final int ownerUid = Process.myUid();
final TransportInfo transportInfo = new TestTransportInfo();
// Even though the test uid holds privileged permissions, mask location fields since
// the callback did not explicitly opt-in to get location data.
final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
true, /* locationRedacted */
true, /* localMacAddressRedacted */
true /* settingsRedacted */
);
// Should not expect location data since the callback does not set the flag for including
// location data.
verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);