Merge "PermissionMonitor: Limit preinstalled apps network permissions"

This commit is contained in:
Paul Hu
2018-09-03 09:16:52 +00:00
committed by Gerrit Code Review
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.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS;
import android.annotation.NonNull;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -34,6 +35,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
@@ -155,9 +157,8 @@ public class PermissionMonitor {
} }
@VisibleForTesting @VisibleForTesting
boolean isPreinstalledSystemApp(PackageInfo app) { static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0; return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0;
} }
@VisibleForTesting @VisibleForTesting
@@ -177,7 +178,13 @@ public class PermissionMonitor {
} }
private boolean hasRestrictedNetworkPermission(PackageInfo app) { 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) return hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); || 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 // This function defines what it means to hold the permission to use
// background networks. // background networks.
return hasPermission(app, CHANGE_NETWORK_STATE) return hasPermission(app, CHANGE_NETWORK_STATE)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)
|| hasPermission(app, CONNECTIVITY_INTERNAL)
|| hasPermission(app, NETWORK_STACK) || hasPermission(app, NETWORK_STACK)
// TODO : remove this check (b/31479477). Not all preinstalled apps should || hasRestrictedNetworkPermission(app);
// have access to background networks, they should just request the appropriate
// permission for their use case from the list above.
|| isPreinstalledSystemApp(app);
} }
public boolean hasUseBackgroundNetworksPermission(int uid) { 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_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK; 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 android.content.pm.PackageManager.GET_PERMISSIONS;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@@ -34,6 +36,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo; 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.os.Build;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
@@ -48,6 +51,10 @@ import org.mockito.MockitoAnnotations;
public class PermissionMonitorTest { public class PermissionMonitorTest {
private static final int MOCK_UID = 10001; private static final int MOCK_UID = 10001;
private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" }; 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 Context mContext;
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
@@ -62,39 +69,53 @@ public class PermissionMonitorTest {
mPermissionMonitor = new PermissionMonitor(mContext, null); mPermissionMonitor = new PermissionMonitor(mContext, null);
} }
private void expectPermission(String[] permissions, boolean preinstalled) throws Exception { private void expectPermission(String[] permissions, String partition,
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled); int targetSdkVersion) throws Exception {
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, partition);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
when(mPackageManager.getPackageInfoAsUser( when(mPackageManager.getPackageInfoAsUser(
eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo); 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(); final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = permissions; packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo(); 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; return packageInfo;
} }
@Test @Test
public void testHasPermission() { 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, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
app = packageInfoWithPermissions(new String[] { app = packageInfoWithPermissions(new String[] {
CHANGE_NETWORK_STATE, NETWORK_STACK CHANGE_NETWORK_STATE, NETWORK_STACK
}, false); }, PARTITION_SYSTEM);
assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
app = packageInfoWithPermissions(new String[] { app = packageInfoWithPermissions(new String[] {
CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL
}, false); }, PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
@@ -102,35 +123,64 @@ public class PermissionMonitorTest {
} }
@Test @Test
public void testIsPreinstalledSystemApp() { public void testIsVendorApp() {
PackageInfo app = packageInfoWithPermissions(new String[] {}, false); PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app)); assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM);
app = packageInfoWithPermissions(new String[] {}, true); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app)); app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
} }
@Test @Test
public void testHasUseBackgroundNetworksPermission() throws Exception { 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)); 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)); assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
// TODO : make this false when b/31479477 is fixed expectPermission(new String[] {}, PARTITION_SYSTEM, Build.VERSION_CODES.P);
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);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); 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)); assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID));
} }
} }