PermissionMonitor: Limit preinstalled apps network permissions

Not all preinstalled apps should have access to background
networks or restricted networks. But we give them all network
access permissions currently, it's not a good design. So we
shall limit preinstalled apps permissions, they should just
request the appropriate permission for their use case from
the network permissions.

Bug:19610688
Test: runtest frameworks-net
Change-Id: I184ae3197208c979847ca134c8f01b32528badf1
This commit is contained in:
paulhu
2018-08-20 11:01:21 +08:00
parent 43afefcd97
commit c7a3a56e57
2 changed files with 91 additions and 39 deletions

View File

@@ -24,6 +24,7 @@ import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +35,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Build;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -155,9 +157,8 @@ public class PermissionMonitor {
}
@VisibleForTesting
boolean isPreinstalledSystemApp(PackageInfo app) {
int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0;
return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
}
@VisibleForTesting
@@ -177,7 +178,13 @@ public class PermissionMonitor {
}
private boolean hasRestrictedNetworkPermission(PackageInfo app) {
if (isPreinstalledSystemApp(app)) return true;
// TODO : remove this check in the future(b/31479477). All apps should just
// request the appropriate permission for their use case since android Q.
if (app.applicationInfo != null
&& app.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q
&& isVendorApp(app.applicationInfo)) {
return true;
}
return hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
@@ -186,13 +193,8 @@ public class PermissionMonitor {
// This function defines what it means to hold the permission to use
// background networks.
return hasPermission(app, CHANGE_NETWORK_STATE)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
|| hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, NETWORK_STACK)
// TODO : remove this check (b/31479477). Not all preinstalled apps should
// have access to background networks, they should just request the appropriate
// permission for their use case from the list above.
|| isPreinstalledSystemApp(app);
|| hasRestrictedNetworkPermission(app);
}
public boolean hasUseBackgroundNetworksPermission(int uid) {

View File

@@ -21,7 +21,9 @@ 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.NETWORK_STACK;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static org.junit.Assert.assertFalse;
@@ -34,6 +36,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -48,6 +51,10 @@ import org.mockito.MockitoAnnotations;
public class PermissionMonitorTest {
private static final int MOCK_UID = 10001;
private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" };
private static final String PARTITION_SYSTEM = "system";
private static final String PARTITION_OEM = "oem";
private static final String PARTITION_PRODUCT = "product";
private static final String PARTITION_VENDOR = "vendor";
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
@@ -62,39 +69,53 @@ public class PermissionMonitorTest {
mPermissionMonitor = new PermissionMonitor(mContext, null);
}
private void expectPermission(String[] permissions, boolean preinstalled) throws Exception {
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled);
private void expectPermission(String[] permissions, String partition,
int targetSdkVersion) throws Exception {
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
when(mPackageManager.getPackageInfoAsUser(
eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
}
private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) {
private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags = preinstalled ? FLAG_SYSTEM : 0;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
privateFlags = PRIVATE_FLAG_OEM;
break;
case PARTITION_PRODUCT:
privateFlags = PRIVATE_FLAG_PRODUCT;
break;
case PARTITION_VENDOR:
privateFlags = PRIVATE_FLAG_VENDOR;
break;
}
packageInfo.applicationInfo.privateFlags = privateFlags;
return packageInfo;
}
@Test
public void testHasPermission() {
PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
app = packageInfoWithPermissions(new String[] {
CHANGE_NETWORK_STATE, NETWORK_STACK
}, false);
CHANGE_NETWORK_STATE, NETWORK_STACK
}, PARTITION_SYSTEM);
assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
app = packageInfoWithPermissions(new String[] {
CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
}, false);
CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
}, PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
@@ -102,35 +123,64 @@ public class PermissionMonitorTest {
}
@Test
public void testIsPreinstalledSystemApp() {
PackageInfo app = packageInfoWithPermissions(new String[] {}, false);
assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app));
app = packageInfoWithPermissions(new String[] {}, true);
assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app));
public void testIsVendorApp() {
PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
expectPermission(new String[] { CHANGE_NETWORK_STATE }, false);
expectPermission(new String[] { CHANGE_NETWORK_STATE },
PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { NETWORK_STACK }, PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_INTERNAL },
PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, false);
expectPermission(new String[] { CHANGE_NETWORK_STATE },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { NETWORK_STACK },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_INTERNAL },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CONNECTIVITY_USE_RESTRICTED_NETWORKS },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
// TODO : make this false when b/31479477 is fixed
expectPermission(new String[] {}, true);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE }, true);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, true);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] {}, false);
expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE },
PARTITION_SYSTEM, Build.VERSION_CODES.P);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE },
PARTITION_VENDOR, Build.VERSION_CODES.P);
assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE }, false);
expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.Q);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE },
PARTITION_SYSTEM, Build.VERSION_CODES.Q);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] {}, PARTITION_VENDOR, Build.VERSION_CODES.Q);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
expectPermission(new String[] { CHANGE_WIFI_STATE },
PARTITION_VENDOR, Build.VERSION_CODES.Q);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
}
}