Check local network permissions when permission changes, or when user or

packages is added or removed

Bug: 388803658
Test: atest ConnectivityCoverageTests

Change-Id: I7d098c4d9a7614d0bd40ae23869a2010ee3f0779
This commit is contained in:
Jacque Li 2024-10-21 20:02:15 +00:00 • committed by Neha Raj
commit 8d5c6eae80
8 changed files with 317 additions and 33 deletions

View file

@ -564,6 +564,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// The Context is created for UserHandle.ALL.
private final Context mUserAllContext;
private final Dependencies mDeps;
private final PermissionMonitor.Dependencies mPermissionMonitorDeps;
private final ConnectivityFlags mFlags;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@ -1808,12 +1809,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
public ConnectivityService(Context context) {
this(context, getDnsResolver(context), new IpConnectivityLog(),
INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
new Dependencies());
new Dependencies(), new PermissionMonitor.Dependencies());
}
@VisibleForTesting
protected ConnectivityService(Context context, IDnsResolver dnsresolver,
IpConnectivityLog logger, INetd netd, Dependencies deps) {
IpConnectivityLog logger, INetd netd, Dependencies deps,
PermissionMonitor.Dependencies mPermDeps) {
if (DBG) log("ConnectivityService starting up");
mDeps = Objects.requireNonNull(deps, "missing Dependencies");
@ -1886,8 +1888,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetd = netd;
mBpfNetMaps = mDeps.getBpfNetMaps(mContext, netd);
mHandlerThread = mDeps.makeHandlerThread("ConnectivityServiceThread");
mPermissionMonitorDeps = mPermDeps;
mPermissionMonitor =
new PermissionMonitor(mContext, mNetd, mBpfNetMaps, mHandlerThread);
new PermissionMonitor(mContext, mNetd, mBpfNetMaps, mPermissionMonitorDeps,
mHandlerThread);
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());

View file

@ -19,6 +19,7 @@ package com.android.server.connectivity;
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@ -40,6 +41,7 @@ import static com.android.net.module.util.CollectionUtils.toIntArray;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.CompatChanges;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -62,6 +64,7 @@ import android.os.ServiceSpecificException;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@ -98,6 +101,8 @@ public class PermissionMonitor {
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final SystemConfigManager mSystemConfigManager;
private final PermissionManager mPermissionManager;
private final PermissionChangeListener mPermissionChangeListener;
private final INetd mNetd;
private final Dependencies mDeps;
private final Context mContext;
@ -229,6 +234,12 @@ public class PermissionMonitor {
context.getContentResolver().registerContentObserver(
uri, notifyForDescendants, observer);
}
public boolean shouldEnforceLocalNetRestrictions(int uid) {
// TODO(b/394567896): Update compat change checks for enforcement
return BpfNetMaps.isAtLeast25Q2() &&
CompatChanges.isChangeEnabled(RESTRICT_LOCAL_NETWORK, uid);
}
}
private static class MultiSet<T> {
@ -269,13 +280,15 @@ public class PermissionMonitor {
}
@VisibleForTesting
PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
@NonNull final BpfNetMaps bpfNetMaps,
@NonNull final Dependencies deps,
@NonNull final HandlerThread thread) {
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
mPermissionManager = context.getSystemService(PermissionManager.class);
mPermissionChangeListener = new PermissionChangeListener();
mNetd = netd;
mDeps = deps;
mContext = context;
@ -286,7 +299,29 @@ public class PermissionMonitor {
// This listener should finish registration by the time the system has completed
// boot setup such that any changes to runtime permissions for local network
// restrictions can only occur after this registration has completed.
mPackageManager.addOnPermissionsChangeListener(new PermissionChangeListener());
mPackageManager.addOnPermissionsChangeListener(mPermissionChangeListener);
}
}
@VisibleForTesting
void setLocalNetworkPermissions(final int uid, @Nullable final String packageName) {
if (!mDeps.shouldEnforceLocalNetRestrictions(uid)) return;
final AttributionSource attributionSource =
new AttributionSource.Builder(uid).setPackageName(packageName).build();
final int permissionState = mPermissionManager.checkPermissionForPreflight(
NEARBY_WIFI_DEVICES, attributionSource);
if (permissionState == PermissionManager.PERMISSION_GRANTED) {
mBpfNetMaps.removeUidFromLocalNetBlockMap(attributionSource.getUid());
} else {
mBpfNetMaps.addUidToLocalNetBlockMap(attributionSource.getUid());
}
if (hasSdkSandbox(uid)){
// SDKs in the SDK RT cannot hold runtime permissions
final int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
if (!mBpfNetMaps.isUidBlockedFromUsingLocalNetwork(sdkSandboxUid)) {
mBpfNetMaps.addUidToLocalNetBlockMap(sdkSandboxUid);
}
}
}
@ -350,6 +385,7 @@ public class PermissionMonitor {
uidsPerm.put(sdkSandboxUid, permission);
}
}
setLocalNetworkPermissions(uid, app.packageName);
}
return uidsPerm;
}
@ -597,7 +633,7 @@ public class PermissionMonitor {
final List<PackageInfo> apps = getInstalledPackagesAsUser(user);
// Save all apps
// Save all apps in mAllApps
updateAllApps(apps);
// Uids network permissions
@ -634,6 +670,11 @@ public class PermissionMonitor {
final int uid = allUids.keyAt(i);
if (user.equals(UserHandle.getUserHandleForUid(uid))) {
mUidToNetworkPerm.delete(uid);
if (mDeps.shouldEnforceLocalNetRestrictions(uid)) {
mBpfNetMaps.removeUidFromLocalNetBlockMap(uid);
if (hasSdkSandbox(uid)) mBpfNetMaps.removeUidFromLocalNetBlockMap(
sProcessShim.toSdkSandboxUid(uid));
}
removedUids.put(uid, allUids.valueAt(i));
}
}
@ -828,6 +869,7 @@ public class PermissionMonitor {
}
sendUidsNetworkPermission(apps, true /* add */);
}
setLocalNetworkPermissions(uid, packageName);
// If the newly-installed package falls within some VPN's uid range, update Netd with it.
// This needs to happen after the mUidToNetworkPerm update above, since
@ -872,6 +914,11 @@ public class PermissionMonitor {
synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
// Update uid permission.
updateAppIdTrafficPermission(uid);
if (BpfNetMaps.isAtLeast25Q2()) {
mBpfNetMaps.removeUidFromLocalNetBlockMap(uid);
if (hasSdkSandbox(uid)) mBpfNetMaps.removeUidFromLocalNetBlockMap(
sProcessShim.toSdkSandboxUid(uid));
}
// Get the appId permission from all users then send the latest permission to netd.
final int appId = UserHandle.getAppId(uid);
final int appIdTrafficPerm = getAppIdTrafficPermission(appId);
@ -1324,16 +1371,7 @@ public class PermissionMonitor {
private class PermissionChangeListener implements PackageManager.OnPermissionsChangedListener {
@Override
public void onPermissionsChanged(int uid) {
// RESTRICT_LOCAL_NETWORK is a compat change that is enabled when developers manually
// opt-in to this change, or when the app's targetSdkVersion is greater than 36.
// The RESTRICT_LOCAL_NETWORK compat change is used here instead of the
// Flags.restrictLocalNetwork() is used to offer the feature to devices, but it will
// only be enforced when develoeprs choose to enable it.
// TODO(b/394567896): Update compat change checks
if (CompatChanges.isChangeEnabled(RESTRICT_LOCAL_NETWORK, uid)
&& BpfNetMaps.isAtLeast25Q2()) {
// TODO(b/388803658): Update network permissions and record change
}
setLocalNetworkPermissions(uid, null);
}
}
}

View file

@ -62,6 +62,7 @@ import com.android.server.connectivity.CarrierPrivilegeAuthenticator
import com.android.server.connectivity.ConnectivityResources
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.MultinetworkPolicyTracker
import com.android.server.connectivity.PermissionMonitor
import com.android.server.connectivity.ProxyTracker
import com.android.server.connectivity.SatelliteAccessController
import com.android.testutils.DevSdkIgnoreRunner
@ -222,7 +223,7 @@ class ConnectivityServiceIntegrationTest {
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
context, dnsResolver, log, netd, deps)
context, dnsResolver, log, netd, deps, PermissionMonitorDependencies())
private inner class TestDependencies : ConnectivityService.Dependencies() {
override fun getNetworkStack() = networkStackClient
@ -277,6 +278,10 @@ class ConnectivityServiceIntegrationTest {
override fun makeL2capNetworkProvider(context: Context) = null
}
private inner class PermissionMonitorDependencies : PermissionMonitor.Dependencies() {
override fun shouldEnforceLocalNetRestrictions(uid: Int) = false
}
@After
fun tearDown() {
nsInstrumentation.clearAllState()

View file

@ -154,6 +154,7 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIAL
import static android.net.Proxy.PROXY_CHANGE_ACTION;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION;
import static android.net.connectivity.ConnectivityCompatChanges.RESTRICT_LOCAL_NETWORK;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
@ -257,6 +258,7 @@ import android.app.BroadcastOptions;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.app.compat.CompatChanges;
import android.app.usage.NetworkStatsManager;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.BroadcastReceiver;
@ -426,6 +428,7 @@ import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.SatelliteAccessController;
@ -594,6 +597,7 @@ public class ConnectivityServiceTest {
private MockContext mServiceContext;
private HandlerThread mCsHandlerThread;
private ConnectivityServiceDependencies mDeps;
private PermissionMonitorDependencies mPermDeps;
private AutomaticOnOffKeepaliveTrackerDependencies mAutoOnOffKeepaliveDependencies;
private ConnectivityService mService;
private WrappedConnectivityManager mCm;
@ -1921,6 +1925,7 @@ public class ConnectivityServiceTest {
doReturn(mResources).when(mockResContext).getResources();
ConnectivityResources.setResourcesContextForTest(mockResContext);
mDeps = new ConnectivityServiceDependencies(mockResContext);
mPermDeps = new PermissionMonitorDependencies();
doReturn(true).when(mMockKeepaliveTrackerDependencies)
.isAddressTranslationEnabled(mServiceContext);
doReturn(new ConnectivityResources(mockResContext)).when(mMockKeepaliveTrackerDependencies)
@ -1933,7 +1938,7 @@ public class ConnectivityServiceTest {
mMockDnsResolver,
mock(IpConnectivityLog.class),
mMockNetd,
mDeps);
mDeps, mPermDeps);
mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
@ -2389,6 +2394,13 @@ public class ConnectivityServiceTest {
}
}
static class PermissionMonitorDependencies extends PermissionMonitor.Dependencies {
@Override
public boolean shouldEnforceLocalNetRestrictions(int uid) {
return false;
}
}
private class AutomaticOnOffKeepaliveTrackerDependencies
extends AutomaticOnOffKeepaliveTracker.Dependencies {
AutomaticOnOffKeepaliveTrackerDependencies(Context context) {

View file

@ -21,6 +21,7 @@ import static android.Manifest.permission.CHANGE_WIFI_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
@ -31,6 +32,7 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.net.ConnectivitySettingsManager.UIDS_ALLOWED_ON_RESTRICTED_NETWORKS;
import static android.net.INetd.PERMISSION_INTERNET;
import static android.net.INetd.PERMISSION_NETWORK;
@ -39,16 +41,20 @@ import static android.net.INetd.PERMISSION_SYSTEM;
import static android.net.INetd.PERMISSION_UNINSTALLED;
import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.connectivity.ConnectivityCompatChanges.RESTRICT_LOCAL_NETWORK;
import static android.os.Process.SYSTEM_UID;
import static android.permission.PermissionManager.PERMISSION_GRANTED;
import static com.android.server.connectivity.PermissionMonitor.isHigherNetworkPermission;
import static com.android.testutils.TestPermissionUtil.runAsShell;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@ -68,6 +74,8 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -85,7 +93,9 @@ import android.os.Process;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.SparseIntArray;
import androidx.annotation.NonNull;
@ -102,9 +112,13 @@ import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
@ -121,6 +135,8 @@ import java.util.Set;
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class PermissionMonitorTest {
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
private static final int MOCK_USER_ID1 = 0;
private static final int MOCK_USER_ID2 = 1;
private static final int MOCK_USER_ID3 = 2;
@ -162,9 +178,14 @@ public class PermissionMonitorTest {
private static final int PERMISSION_TRAFFIC_ALL =
PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS;
private static final int TIMEOUT_MS = 2_000;
// The ACCESS_LOCAL_NETWORK permission is not available yet. For the time being, use
// NEARBY_WIFI_DEVICES as a means to develop, for expediency.
// TODO(b/375236298): remove this constant when the ACCESS_LOCAL_NETWORK permission is defined.
private static final String ACCESS_LOCAL_NETWORK = NEARBY_WIFI_DEVICES;
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@Mock private PermissionManager mPermissionManager;
@Mock private INetd mNetdService;
@Mock private UserManager mUserManager;
@Mock private PermissionMonitor.Dependencies mDeps;
@ -183,6 +204,7 @@ public class PermissionMonitorTest {
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
doReturn(List.of(MOCK_USER1)).when(mUserManager).getUserHandles(eq(true));
when(mContext.getSystemService(PermissionManager.class)).thenReturn(mPermissionManager);
when(mContext.getSystemServiceName(SystemConfigManager.class))
.thenReturn(Context.SYSTEM_CONFIG_SERVICE);
when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
@ -295,19 +317,28 @@ public class PermissionMonitorTest {
return result;
}
private void buildAndMockPackageInfoWithPermissions(String packageName, int uid,
private PackageInfo buildAndMockPackageInfoWithPermissions(String packageName, int uid,
String... permissions) throws Exception {
final PackageInfo packageInfo = buildPackageInfo(packageName, uid, permissions);
// This will return the wrong UID for the package when queried with other users.
doReturn(packageInfo).when(mPackageManager)
.getPackageInfo(eq(packageName), anyInt() /* flag */);
if (BpfNetMaps.isAtLeast25Q2()) {
// Runtime permission checks for local net restrictions were introduced in 25Q2
for (String permission : permissions) {
doReturn(PERMISSION_GRANTED).when(mPermissionManager).checkPermissionForPreflight(
eq(permission),
argThat(attributionSource -> attributionSource.getUid() == uid));
}
}
final String[] oldPackages = mPackageManager.getPackagesForUid(uid);
// If it's duplicated package, no need to set it again.
if (CollectionUtils.contains(oldPackages, packageName)) return;
if (CollectionUtils.contains(oldPackages, packageName)) return packageInfo;
// Combine the package if this uid is shared with other packages.
final String[] newPackages = appendElement(String.class, oldPackages, packageName);
doReturn(newPackages).when(mPackageManager).getPackagesForUid(eq(uid));
return packageInfo;
}
private void startMonitoring() {
@ -342,7 +373,7 @@ public class PermissionMonitorTest {
private void addPackage(String packageName, int uid, String... permissions) throws Exception {
buildAndMockPackageInfoWithPermissions(packageName, uid, permissions);
processOnHandlerThread(() -> mPermissionMonitor.onPackageAdded(packageName, uid));
onPackageAdded(packageName, uid);
}
private void removePackage(String packageName, int uid) {
@ -354,7 +385,12 @@ public class PermissionMonitorTest {
final String[] newPackages = Arrays.stream(oldPackages).filter(e -> !e.equals(packageName))
.toArray(String[]::new);
doReturn(newPackages).when(mPackageManager).getPackagesForUid(eq(uid));
processOnHandlerThread(() -> mPermissionMonitor.onPackageRemoved(packageName, uid));
if (BpfNetMaps.isAtLeast25Q2()){
// Runtime permission checks for local net restrictions were introduced in 25Q2
doReturn(PERMISSION_DENIED).when(mPermissionManager).checkPermissionForPreflight(
anyString(), argThat(as -> as.getUid() == uid));
}
onPackageRemoved(packageName, uid);
}
@Test
@ -585,6 +621,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testHasUseBackgroundNetworksPermission() throws Exception {
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
@ -606,6 +643,7 @@ public class PermissionMonitorTest {
private class BpfMapMonitor {
private final SparseIntArray mAppIdsTrafficPermission = new SparseIntArray();
private final ArraySet<Integer> mLocalNetBlockedUids = new ArraySet<>();
private static final int DOES_NOT_EXIST = -2;
BpfMapMonitor(BpfNetMaps mockBpfmap) throws Exception {
@ -618,6 +656,18 @@ public class PermissionMonitorTest {
}
return null;
}).when(mockBpfmap).setNetPermForUids(anyInt(), any(int[].class));
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
final int uid = (int) args[0];
mLocalNetBlockedUids.add(uid);
return null;
}).when(mockBpfmap).addUidToLocalNetBlockMap(anyInt());
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
final int uid = (int) args[0];
mLocalNetBlockedUids.remove(uid);
return null;
}).when(mockBpfmap).removeUidFromLocalNetBlockMap(anyInt());
}
public void expectTrafficPerm(int permission, Integer... appIds) {
@ -642,6 +692,18 @@ public class PermissionMonitorTest {
}
}
}
public boolean hasLocalNetPermissions(int uid) {
return !mLocalNetBlockedUids.contains(uid);
}
public boolean isUidPresentInLocalNetBlockMap(int uid) {
return mLocalNetBlockedUids.contains(uid);
}
public boolean hasBlockedLocalNetForSandboxUid(int sandboxUid) {
return mLocalNetBlockedUids.contains(sandboxUid);
}
}
private class NetdMonitor {
@ -725,6 +787,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUserAndPackageAddRemove() throws Exception {
// MOCK_UID11: MOCK_PACKAGE1 only has network permission.
// SYSTEM_APP_UID11: SYSTEM_PACKAGE1 has system permission.
@ -814,6 +877,48 @@ public class PermissionMonitorTest {
MOCK_APPID1);
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_onUserAdded() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
final PackageInfo packageInfo = buildAndMockPackageInfoWithPermissions(
MOCK_PACKAGE1, MOCK_UID11, CHANGE_NETWORK_STATE);
// Set package for all users on devices
doReturn(List.of(packageInfo)).when(mPackageManager)
.getInstalledPackagesAsUser(anyInt(), eq(MOCK_USER1.getIdentifier()));
onUserAdded(MOCK_USER1);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
if (hasSdkSandbox(MOCK_UID11)) {
assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID11)));
}
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_onUserRemoved() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
final PackageInfo packageInfo = buildAndMockPackageInfoWithPermissions(
MOCK_PACKAGE1, MOCK_UID11, CHANGE_NETWORK_STATE);
// Set package for all users on devices
doReturn(List.of(packageInfo)).when(mPackageManager)
.getInstalledPackagesAsUser(anyInt(), eq(MOCK_USER1.getIdentifier()));
onUserAdded(MOCK_USER1);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
onUserRemoved(MOCK_USER1);
assertFalse(mBpfMapMonitor.isUidPresentInLocalNetBlockMap(MOCK_UID11));
}
private void doTestUidFilteringDuringVpnConnectDisconnectAndUidUpdates(@Nullable String ifName)
throws Exception {
doReturn(List.of(
@ -860,11 +965,13 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
doTestUidFilteringDuringVpnConnectDisconnectAndUidUpdates("tun0");
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdatesWithWildcard()
throws Exception {
doTestUidFilteringDuringVpnConnectDisconnectAndUidUpdates(null /* ifName */);
@ -897,16 +1004,19 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
doTestUidFilteringDuringPackageInstallAndUninstall("tun0");
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidFilteringDuringPackageInstallAndUninstallWithWildcard() throws Exception {
doTestUidFilteringDuringPackageInstallAndUninstall(null /* ifName */);
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLockdownUidFilteringWithLockdownEnableDisable() {
doReturn(List.of(
buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID11, CHANGE_NETWORK_STATE,
@ -938,6 +1048,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLockdownUidFilteringWithLockdownEnableDisableWithMultiAdd() {
doReturn(List.of(
buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID11, CHANGE_NETWORK_STATE,
@ -979,6 +1090,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLockdownUidFilteringWithLockdownEnableDisableWithMultiAddAndOverlap() {
doReturn(List.of(buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID11, CHANGE_NETWORK_STATE,
CONNECTIVITY_USE_RESTRICTED_NETWORKS),
@ -1039,6 +1151,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLockdownUidFilteringWithLockdownEnableDisableWithDuplicates() {
doReturn(List.of(
buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID11, CHANGE_NETWORK_STATE,
@ -1073,6 +1186,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLockdownUidFilteringWithInstallAndUnInstall() {
doReturn(List.of(
buildPackageInfo(SYSTEM_PACKAGE1, SYSTEM_APP_UID11, CHANGE_NETWORK_STATE,
@ -1109,15 +1223,13 @@ public class PermissionMonitorTest {
// called multiple times with the uid corresponding to each user.
private void addPackageForUsers(UserHandle[] users, String packageName, int appId) {
for (final UserHandle user : users) {
processOnHandlerThread(() ->
mPermissionMonitor.onPackageAdded(packageName, user.getUid(appId)));
onPackageAdded(packageName, user.getUid(appId));
}
}
private void removePackageForUsers(UserHandle[] users, String packageName, int appId) {
for (final UserHandle user : users) {
processOnHandlerThread(() ->
mPermissionMonitor.onPackageRemoved(packageName, user.getUid(appId)));
onPackageRemoved(packageName, user.getUid(appId));
}
}
@ -1165,6 +1277,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageInstall() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET, UPDATE_DEVICE_STATS);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
@ -1173,7 +1286,25 @@ public class PermissionMonitorTest {
mBpfMapMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID2);
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_onPackageInstall() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
addPackage(MOCK_PACKAGE2, MOCK_UID12, ACCESS_LOCAL_NETWORK);
assertTrue(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID12));
if (hasSdkSandbox(MOCK_UID12)) assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID12)));
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageInstallSharedUid() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET, UPDATE_DEVICE_STATS);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
@ -1185,6 +1316,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageUninstallBasic() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET, UPDATE_DEVICE_STATS);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
@ -1194,7 +1326,24 @@ public class PermissionMonitorTest {
mBpfMapMonitor.expectTrafficPerm(PERMISSION_UNINSTALLED, MOCK_APPID1);
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_onPackageUninstall() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
addPackage(MOCK_PACKAGE1, MOCK_UID11, ACCESS_LOCAL_NETWORK);
assertTrue(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
when(mPackageManager.getPackagesForUid(MOCK_UID11)).thenReturn(new String[]{});
onPackageRemoved(MOCK_PACKAGE1, MOCK_UID11);
assertFalse(mBpfMapMonitor.isUidPresentInLocalNetBlockMap(MOCK_UID11));
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageRemoveThenAdd() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET, UPDATE_DEVICE_STATS);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
@ -1207,7 +1356,30 @@ public class PermissionMonitorTest {
mBpfMapMonitor.expectTrafficPerm(PERMISSION_INTERNET, MOCK_APPID1);
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_onPackageRemoveThenAdd() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
addPackage(MOCK_PACKAGE1, MOCK_UID11, ACCESS_LOCAL_NETWORK);
assertTrue(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
if (hasSdkSandbox(MOCK_UID12)) assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID11)));
removePackage(MOCK_PACKAGE1, MOCK_UID11);
assertFalse(mBpfMapMonitor.isUidPresentInLocalNetBlockMap(MOCK_UID11));
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
if (hasSdkSandbox(MOCK_UID12)) assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID11)));
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageUpdate() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_NONE, MOCK_APPID1);
@ -1217,6 +1389,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testPackageUninstallWithMultiplePackages() throws Exception {
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET, UPDATE_DEVICE_STATS);
mBpfMapMonitor.expectTrafficPerm(PERMISSION_TRAFFIC_ALL, MOCK_APPID1);
@ -1248,6 +1421,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
.thenReturn(new int[]{ MOCK_UID11, MOCK_UID12 });
@ -1287,6 +1461,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testIntentReceiver() throws Exception {
startMonitoring();
final BroadcastReceiver receiver = expectBroadcastReceiver(
@ -1325,6 +1500,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidsAllowedOnRestrictedNetworksChanged() throws Exception {
startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
@ -1357,6 +1533,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
@ -1390,6 +1567,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testUidsAllowedOnRestrictedNetworksChangedWithMultipleUsers() throws Exception {
startMonitoring();
final ContentObserver contentObserver = expectRegisterContentObserver(
@ -1444,6 +1622,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testOnExternalApplicationsAvailable() throws Exception {
// Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
// and have different uids. There has no permission for both uids.
@ -1475,6 +1654,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testOnExternalApplicationsAvailable_AppsNotRegisteredOnStartMonitoring()
throws Exception {
startMonitoring();
@ -1502,6 +1682,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testOnExternalApplicationsAvailableWithSharedUid()
throws Exception {
// Initial the permission state. MOCK_PACKAGE1 and MOCK_PACKAGE2 are installed on external
@ -1528,6 +1709,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testOnExternalApplicationsAvailableWithSharedUid_DifferentStorage()
throws Exception {
// Initial the permission state. MOCK_PACKAGE1 is installed on external storage and
@ -1570,6 +1752,38 @@ public class PermissionMonitorTest {
assertFalse(isHigherNetworkPermission(PERMISSION_SYSTEM, PERMISSION_SYSTEM));
}
@IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testLocalNetRestrictions_setPermChanges() throws Exception {
assumeTrue(BpfNetMaps.isAtLeast25Q2());
doReturn(true).when(mDeps).shouldEnforceLocalNetRestrictions(anyInt());
when(mPermissionManager.checkPermissionForPreflight(
anyString(), any(AttributionSource.class))).thenReturn(PERMISSION_DENIED);
addPackage(MOCK_PACKAGE1, MOCK_UID11, INTERNET);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
// Mock permission grant
when(mPermissionManager.checkPermissionForPreflight(
eq(ACCESS_LOCAL_NETWORK),
argThat(attributionSource -> attributionSource.getUid() == MOCK_UID11)))
.thenReturn(PERMISSION_GRANTED);
mPermissionMonitor.setLocalNetworkPermissions(MOCK_UID11, null);
assertTrue(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
if (hasSdkSandbox(MOCK_UID12)) assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID11)));
// Mock permission denied
when(mPermissionManager.checkPermissionForPreflight(
eq(ACCESS_LOCAL_NETWORK),
argThat(attributionSource -> attributionSource.getUid() == MOCK_UID11)))
.thenReturn(PERMISSION_DENIED);
mPermissionMonitor.setLocalNetworkPermissions(MOCK_UID11, null);
assertFalse(mBpfMapMonitor.hasLocalNetPermissions(MOCK_UID11));
if (hasSdkSandbox(MOCK_UID12)) assertTrue(mBpfMapMonitor.hasBlockedLocalNetForSandboxUid(
mProcessShim.toSdkSandboxUid(MOCK_UID11)));
}
private void prepareMultiUserPackages() {
// MOCK_USER1 has installed 3 packages
// mockApp1 has no permission and share MOCK_APPID1.
@ -1602,7 +1816,7 @@ public class PermissionMonitorTest {
private void addUserAndVerifyAppIdsPermissions(UserHandle user, int appId1Perm,
int appId2Perm, int appId3Perm) {
processOnHandlerThread(() -> mPermissionMonitor.onUserAdded(user));
onUserAdded(user);
mBpfMapMonitor.expectTrafficPerm(appId1Perm, MOCK_APPID1);
mBpfMapMonitor.expectTrafficPerm(appId2Perm, MOCK_APPID2);
mBpfMapMonitor.expectTrafficPerm(appId3Perm, MOCK_APPID3);
@ -1610,13 +1824,14 @@ public class PermissionMonitorTest {
private void removeUserAndVerifyAppIdsPermissions(UserHandle user, int appId1Perm,
int appId2Perm, int appId3Perm) {
processOnHandlerThread(() -> mPermissionMonitor.onUserRemoved(user));
onUserRemoved(user);
mBpfMapMonitor.expectTrafficPerm(appId1Perm, MOCK_APPID1);
mBpfMapMonitor.expectTrafficPerm(appId2Perm, MOCK_APPID2);
mBpfMapMonitor.expectTrafficPerm(appId3Perm, MOCK_APPID3);
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testAppIdsTrafficPermission_UserAddedRemoved() {
prepareMultiUserPackages();
@ -1650,6 +1865,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testAppIdsTrafficPermission_Multiuser_PackageAdded() throws Exception {
// Add two users with empty package list.
onUserAdded(MOCK_USER1);
@ -1720,6 +1936,7 @@ public class PermissionMonitorTest {
}
@Test
@EnableCompatChanges(RESTRICT_LOCAL_NETWORK)
public void testAppIdsTrafficPermission_Multiuser_PackageRemoved() throws Exception {
// Add two users with empty package list.
onUserAdded(MOCK_USER1);

View file

@ -54,9 +54,7 @@ import org.mockito.Mockito.eq
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
private const val TIMEOUT_MS = 200L
private const val MEDIUM_TIMEOUT_MS = 1_000L

View file

@ -72,6 +72,7 @@ import com.android.server.connectivity.MulticastRoutingCoordinatorService
import com.android.server.connectivity.MultinetworkPolicyTracker
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies
import com.android.server.connectivity.NetworkRequestStateStatsMetrics
import com.android.server.connectivity.PermissionMonitor
import com.android.server.connectivity.ProxyTracker
import com.android.server.connectivity.SatelliteAccessController
import com.android.testutils.visibleOnHandlerThread
@ -217,6 +218,7 @@ open class CSTest {
val destroySocketsWrapper = mock<DestroySocketsWrapper>()
val deps = CSDeps()
val permDeps = PermDeps()
// Initializations that start threads are done from setUp to avoid thread leak
lateinit var alarmHandlerThread: HandlerThread
@ -253,7 +255,9 @@ open class CSTest {
alarmHandlerThread = HandlerThread("TestAlarmManager").also { it.start() }
alarmManager = makeMockAlarmManager(alarmHandlerThread)
service = makeConnectivityService(context, netd, deps).also { it.systemReadyInternal() }
service = makeConnectivityService(context, netd, deps, permDeps).also {
it.systemReadyInternal()
}
cm = ConnectivityManager(context, service)
// csHandler initialization must be after makeConnectivityService since ConnectivityService
// constructor starts csHandlerThread
@ -399,6 +403,10 @@ open class CSTest {
override fun makeL2capNetworkProvider(context: Context) = null
}
inner class PermDeps : PermissionMonitor.Dependencies() {
override fun shouldEnforceLocalNetRestrictions(uid: Int) = false
}
inner class CSContext(base: Context) : BroadcastInterceptingContext(base) {
val pacProxyManager = mock<PacProxyManager>()
val networkPolicyManager = mock<NetworkPolicyManager>()

View file

@ -54,6 +54,7 @@ import com.android.internal.util.test.FakeSettingsProvider
import com.android.modules.utils.build.SdkLevel
import com.android.server.ConnectivityService.Dependencies
import com.android.server.connectivity.ConnectivityResources
import com.android.server.connectivity.PermissionMonitor
import kotlin.test.fail
import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.any
@ -192,13 +193,14 @@ internal fun initMockedResources(res: Resources) {
private val TEST_LINGER_DELAY_MS = 400
private val TEST_NASCENT_DELAY_MS = 300
internal fun makeConnectivityService(context: Context, netd: INetd, deps: Dependencies) =
internal fun makeConnectivityService(context: Context, netd: INetd, deps: Dependencies,
mPermDeps: PermissionMonitor.Dependencies) =
ConnectivityService(
context,
mock<IDnsResolver>(),
mock<IpConnectivityLog>(),
netd,
deps).also {
deps, mPermDeps).also {
it.mLingerDelayMs = TEST_LINGER_DELAY_MS
it.mNascentDelayMs = TEST_NASCENT_DELAY_MS
}