Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting from PermissionMonitor
Let PermissionMonitor read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and grant netd system permission to uids whose package name is listed in setting. Bug: 185149952 Test: atest FrameworksNetTests Change-Id: I856b545c0339a262abbe9d432cfda125bc82dc12
This commit is contained in:
@@ -39,6 +39,7 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.net.ConnectivitySettingsManager;
|
||||||
import android.net.INetd;
|
import android.net.INetd;
|
||||||
import android.net.UidRange;
|
import android.net.UidRange;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -49,6 +50,7 @@ import android.os.SystemConfigManager;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
@@ -105,6 +107,14 @@ public class PermissionMonitor {
|
|||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private final Set<Integer> mAllApps = new HashSet<>();
|
private final Set<Integer> mAllApps = new HashSet<>();
|
||||||
|
|
||||||
|
// A set of apps which are allowed to use restricted networks. These apps can't hold the
|
||||||
|
// CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be signature|privileged
|
||||||
|
// apps. However, these apps should still be able to use restricted networks under certain
|
||||||
|
// conditions (e.g. government app using emergency services). So grant netd system permission
|
||||||
|
// to uids whose package name is listed in APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting.
|
||||||
|
@GuardedBy("this")
|
||||||
|
private final Set<String> mAppsAllowedOnRestrictedNetworks = new ArraySet<>();
|
||||||
|
|
||||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
@@ -165,6 +175,11 @@ public class PermissionMonitor {
|
|||||||
mIntentReceiver, intentFilter, null /* broadcastPermission */,
|
mIntentReceiver, intentFilter, null /* broadcastPermission */,
|
||||||
null /* scheduler */);
|
null /* scheduler */);
|
||||||
|
|
||||||
|
// Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
|
||||||
|
// mAppsAllowedOnRestrictedNetworks.
|
||||||
|
updateAppsAllowedOnRestrictedNetworks(
|
||||||
|
ConnectivitySettingsManager.getAppsAllowedOnRestrictedNetworks(mContext));
|
||||||
|
|
||||||
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
|
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
|
||||||
| MATCH_ANY_USER);
|
| MATCH_ANY_USER);
|
||||||
if (apps == null) {
|
if (apps == null) {
|
||||||
@@ -219,11 +234,33 @@ public class PermissionMonitor {
|
|||||||
sendPackagePermissionsToNetd(netdPermsUids);
|
sendPackagePermissionsToNetd(netdPermsUids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void updateAppsAllowedOnRestrictedNetworks(final Set<String> apps) {
|
||||||
|
mAppsAllowedOnRestrictedNetworks.clear();
|
||||||
|
mAppsAllowedOnRestrictedNetworks.addAll(apps);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
|
static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
|
||||||
return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
|
return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean isCarryoverPackage(final ApplicationInfo appInfo) {
|
||||||
|
if (appInfo == null) return false;
|
||||||
|
return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
|
||||||
|
// Backward compatibility for b/114245686, on devices that launched before Q daemons
|
||||||
|
// and apps running as the system UID are exempted from this check.
|
||||||
|
|| (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean isAppAllowedOnRestrictedNetworks(@NonNull final PackageInfo app) {
|
||||||
|
// Check whether package name is in allowed on restricted networks app list. If so, this app
|
||||||
|
// can have netd system permission.
|
||||||
|
return mAppsAllowedOnRestrictedNetworks.contains(app.packageName);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
|
boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
|
||||||
if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
|
if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
|
||||||
@@ -241,22 +278,10 @@ public class PermissionMonitor {
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
|
boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
|
||||||
// TODO : remove this check in the future(b/31479477). All apps should just
|
// TODO : remove carryover package check in the future(b/31479477). All apps should just
|
||||||
// request the appropriate permission for their use case since android Q.
|
// request the appropriate permission for their use case since android Q.
|
||||||
if (app.applicationInfo != null) {
|
return isCarryoverPackage(app.applicationInfo) || isAppAllowedOnRestrictedNetworks(app)
|
||||||
// Backward compatibility for b/114245686, on devices that launched before Q daemons
|
|| hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
|
||||||
// and apps running as the system UID are exempted from this check.
|
|
||||||
if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app.applicationInfo.targetSdkVersion < VERSION_Q
|
|
||||||
&& isVendorApp(app.applicationInfo)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
|
|
||||||
|| hasPermission(app, NETWORK_STACK)
|
|| hasPermission(app, NETWORK_STACK)
|
||||||
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
|
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
|
|||||||
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
|
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
|
||||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||||
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
import static android.content.pm.PackageManager.MATCH_ANY_USER;
|
||||||
|
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
|
||||||
import static android.os.Process.SYSTEM_UID;
|
import static android.os.Process.SYSTEM_UID;
|
||||||
|
|
||||||
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
|
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
|
||||||
@@ -68,12 +69,18 @@ import android.os.Build;
|
|||||||
import android.os.SystemConfigManager;
|
import android.os.SystemConfigManager;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.test.mock.MockContentResolver;
|
||||||
|
import android.util.ArraySet;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.util.test.FakeSettingsProvider;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -120,6 +127,7 @@ public class PermissionMonitorTest {
|
|||||||
@Mock private SystemConfigManager mSystemConfigManager;
|
@Mock private SystemConfigManager mSystemConfigManager;
|
||||||
|
|
||||||
private PermissionMonitor mPermissionMonitor;
|
private PermissionMonitor mPermissionMonitor;
|
||||||
|
private MockContentResolver mContentResolver;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -137,16 +145,33 @@ public class PermissionMonitorTest {
|
|||||||
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
|
doReturn(UserHandle.ALL).when(asUserCtx).getUser();
|
||||||
when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
|
when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
|
||||||
|
|
||||||
|
FakeSettingsProvider.clearSettingsProvider();
|
||||||
|
mContentResolver = new MockContentResolver();
|
||||||
|
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||||
|
when(mContext.getContentResolver()).thenReturn(mContentResolver);
|
||||||
|
|
||||||
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
|
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
|
||||||
|
|
||||||
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
|
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
|
||||||
mPermissionMonitor.startMonitoring();
|
mPermissionMonitor.startMonitoring();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
FakeSettingsProvider.clearSettingsProvider();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
|
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
|
||||||
String... permissions) {
|
String... permissions) {
|
||||||
|
return hasRestrictedNetworkPermission(
|
||||||
|
partition, targetSdkVersion, "" /* packageName */, uid, permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion,
|
||||||
|
String packageName, int uid, String... permissions) {
|
||||||
final PackageInfo packageInfo =
|
final PackageInfo packageInfo =
|
||||||
packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
|
packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
|
||||||
|
packageInfo.packageName = packageName;
|
||||||
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
|
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
|
||||||
packageInfo.applicationInfo.uid = uid;
|
packageInfo.applicationInfo.uid = uid;
|
||||||
return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
|
return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
|
||||||
@@ -280,6 +305,8 @@ public class PermissionMonitorTest {
|
|||||||
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
|
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
|
||||||
assertFalse(hasRestrictedNetworkPermission(
|
assertFalse(hasRestrictedNetworkPermission(
|
||||||
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
|
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
|
||||||
|
assertTrue(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK));
|
||||||
|
|
||||||
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
|
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
|
||||||
assertFalse(hasRestrictedNetworkPermission(
|
assertFalse(hasRestrictedNetworkPermission(
|
||||||
@@ -324,6 +351,90 @@ public class PermissionMonitorTest {
|
|||||||
PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
|
PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasRestrictedNetworkPermissionAppAllowedOnRestrictedNetworks() {
|
||||||
|
mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
|
||||||
|
new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
|
||||||
|
assertTrue(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
|
||||||
|
assertTrue(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
|
||||||
|
assertTrue(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
|
||||||
|
|
||||||
|
assertFalse(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1));
|
||||||
|
assertFalse(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE));
|
||||||
|
assertFalse(hasRestrictedNetworkPermission(
|
||||||
|
PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CONNECTIVITY_INTERNAL));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
|
||||||
|
final PackageInfo packageInfo = packageInfoWithPermissions(
|
||||||
|
REQUESTED_PERMISSION_GRANTED, new String[] {}, partition);
|
||||||
|
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
|
||||||
|
packageInfo.applicationInfo.uid = uid;
|
||||||
|
return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsCarryoverPackage() {
|
||||||
|
doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
|
||||||
|
|
||||||
|
doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
|
||||||
|
assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
|
||||||
|
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
|
||||||
|
assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wouldBeAppAllowedOnRestrictedNetworks(String packageName) {
|
||||||
|
final PackageInfo packageInfo = new PackageInfo();
|
||||||
|
packageInfo.packageName = packageName;
|
||||||
|
return mPermissionMonitor.isAppAllowedOnRestrictedNetworks(packageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsAppAllowedOnRestrictedNetworks() {
|
||||||
|
mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(new ArraySet<>());
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
|
||||||
|
|
||||||
|
mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
|
||||||
|
new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
|
||||||
|
assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
|
||||||
|
|
||||||
|
mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
|
||||||
|
new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
|
||||||
|
assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
|
||||||
|
|
||||||
|
mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
|
||||||
|
new ArraySet<>(new String[] { "com.android.test" }));
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
|
||||||
|
assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
|
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
|
||||||
String... permissions) throws Exception {
|
String... permissions) throws Exception {
|
||||||
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
|
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
|
||||||
|
|||||||
Reference in New Issue
Block a user