Loading core/java/com/android/internal/util/LocationPermissionChecker.java +41 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.location.LocationManager; import android.location.LocationManager; import android.net.NetworkStack; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.UserHandle; import android.os.UserHandle; Loading Loading @@ -147,6 +148,13 @@ public class LocationPermissionChecker { int uid, @Nullable String message) { int uid, @Nullable String message) { checkPackage(uid, pkgName); checkPackage(uid, pkgName); // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK // are granted a bypass. if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) { return SUCCEEDED; } // Location mode must be enabled // Location mode must be enabled if (!isLocationModeEnabled()) { if (!isLocationModeEnabled()) { return ERROR_LOCATION_MODE_OFF; return ERROR_LOCATION_MODE_OFF; Loading Loading @@ -259,4 +267,37 @@ public class LocationPermissionChecker { // We don't care about pid, pass in -1 // We don't care about pid, pass in -1 return mContext.checkPermission(permissionType, -1, uid); return mContext.checkPermission(permissionType, -1, uid); } } /** * Returns true if the |uid| holds NETWORK_SETTINGS permission. */ public boolean checkNetworkSettingsPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. */ public boolean checkNetworkSetupWizardPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds NETWORK_STACK permission. */ public boolean checkNetworkStackPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. */ public boolean checkMainlineNetworkStackPermission(int uid) { return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) == PackageManager.PERMISSION_GRANTED; } } } core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package com.android.internal.util; package com.android.internal.util; import static android.Manifest.permission.NETWORK_SETTINGS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -82,6 +84,7 @@ public class LocationPermissionCheckerTest { private int mAllowCoarseLocationApps; private int mAllowCoarseLocationApps; private int mFineLocationPermission; private int mFineLocationPermission; private int mAllowFineLocationApps; private int mAllowFineLocationApps; private int mNetworkSettingsPermission; private int mCurrentUser; private int mCurrentUser; private boolean mIsLocationEnabled; private boolean mIsLocationEnabled; private boolean mThrowSecurityException; private boolean mThrowSecurityException; Loading Loading @@ -138,6 +141,7 @@ public class LocationPermissionCheckerTest { mFineLocationPermission = PackageManager.PERMISSION_DENIED; mFineLocationPermission = PackageManager.PERMISSION_DENIED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED; } } private void setupMockInterface() { private void setupMockInterface() { Loading @@ -151,6 +155,8 @@ public class LocationPermissionCheckerTest { .thenReturn(mCoarseLocationPermission); .thenReturn(mCoarseLocationPermission); when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) .thenReturn(mFineLocationPermission); .thenReturn(mFineLocationPermission); when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid)) .thenReturn(mNetworkSettingsPermission); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); } } Loading Loading @@ -264,6 +270,21 @@ public class LocationPermissionCheckerTest { assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); } } @Test public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings() throws Exception { mThrowSecurityException = false; mIsLocationEnabled = false; mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED; setupTestCase(); final int result = mChecker.checkLocationPermissionWithDetailInfo( TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); assertEquals(LocationPermissionChecker.SUCCEEDED, result); } private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { try { try { r.run(); r.run(); Loading tests/net/java/com/android/server/ConnectivityServiceTest.java +20 −8 Original line number Original line Diff line number Diff line Loading @@ -2074,10 +2074,6 @@ public class ConnectivityServiceTest { @Test @Test public void testOwnerUidCannotChange() throws Exception { public void testOwnerUidCannotChange() throws Exception { // Owner UIDs are not visible without location permission. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); final NetworkCapabilities ncTemplate = new NetworkCapabilities(); final NetworkCapabilities ncTemplate = new NetworkCapabilities(); final int originalOwnerUid = Process.myUid(); final int originalOwnerUid = Process.myUid(); ncTemplate.setOwnerUid(originalOwnerUid); ncTemplate.setOwnerUid(originalOwnerUid); Loading @@ -2097,6 +2093,10 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); waitForIdle(); waitForIdle(); // Owner UIDs are not visible without location permission. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); // Check that the capability change has been applied but the owner UID is not modified. // Check that the capability change has been applied but the owner UID is not modified. NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); assertEquals(originalOwnerUid, nc.getOwnerUid()); assertEquals(originalOwnerUid, nc.getOwnerUid()); Loading Loading @@ -7781,8 +7781,22 @@ public class ConnectivityServiceTest { naExtraInfo.unregister(); naExtraInfo.unregister(); } } // To avoid granting location permission bypass. private void denyAllLocationPrivilegedPermissions() { mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD, PERMISSION_DENIED); } private void setupLocationPermissions( private void setupLocationPermissions( int targetSdk, boolean locationToggle, String op, String perm) throws Exception { int targetSdk, boolean locationToggle, String op, String perm) throws Exception { denyAllLocationPrivilegedPermissions(); final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = targetSdk; applicationInfo.targetSdkVersion = targetSdk; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) Loading Loading @@ -8156,15 +8170,13 @@ public class ConnectivityServiceTest { new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); mMockVpn.establishForMyUid(); mMockVpn.establishForMyUid(); assertUidRangesUpdatedForMyUid(true); assertUidRangesUpdatedForMyUid(true); // Wait for networks to connect and broadcasts to be sent before removing permissions. // Wait for networks to connect and broadcasts to be sent before removing permissions. waitForIdle(); waitForIdle(); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); waitForIdle(); waitForIdle(); Loading Loading
core/java/com/android/internal/util/LocationPermissionChecker.java +41 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.location.LocationManager; import android.location.LocationManager; import android.net.NetworkStack; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.UserHandle; import android.os.UserHandle; Loading Loading @@ -147,6 +148,13 @@ public class LocationPermissionChecker { int uid, @Nullable String message) { int uid, @Nullable String message) { checkPackage(uid, pkgName); checkPackage(uid, pkgName); // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_STACK & MAINLINE_NETWORK_STACK // are granted a bypass. if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)) { return SUCCEEDED; } // Location mode must be enabled // Location mode must be enabled if (!isLocationModeEnabled()) { if (!isLocationModeEnabled()) { return ERROR_LOCATION_MODE_OFF; return ERROR_LOCATION_MODE_OFF; Loading Loading @@ -259,4 +267,37 @@ public class LocationPermissionChecker { // We don't care about pid, pass in -1 // We don't care about pid, pass in -1 return mContext.checkPermission(permissionType, -1, uid); return mContext.checkPermission(permissionType, -1, uid); } } /** * Returns true if the |uid| holds NETWORK_SETTINGS permission. */ public boolean checkNetworkSettingsPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_SETTINGS, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission. */ public boolean checkNetworkSetupWizardPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds NETWORK_STACK permission. */ public boolean checkNetworkStackPermission(int uid) { return getUidPermission(android.Manifest.permission.NETWORK_STACK, uid) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission. */ public boolean checkMainlineNetworkStackPermission(int uid) { return getUidPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid) == PackageManager.PERMISSION_GRANTED; } } }
core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package com.android.internal.util; package com.android.internal.util; import static android.Manifest.permission.NETWORK_SETTINGS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; Loading Loading @@ -82,6 +84,7 @@ public class LocationPermissionCheckerTest { private int mAllowCoarseLocationApps; private int mAllowCoarseLocationApps; private int mFineLocationPermission; private int mFineLocationPermission; private int mAllowFineLocationApps; private int mAllowFineLocationApps; private int mNetworkSettingsPermission; private int mCurrentUser; private int mCurrentUser; private boolean mIsLocationEnabled; private boolean mIsLocationEnabled; private boolean mThrowSecurityException; private boolean mThrowSecurityException; Loading Loading @@ -138,6 +141,7 @@ public class LocationPermissionCheckerTest { mFineLocationPermission = PackageManager.PERMISSION_DENIED; mFineLocationPermission = PackageManager.PERMISSION_DENIED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; mNetworkSettingsPermission = PackageManager.PERMISSION_DENIED; } } private void setupMockInterface() { private void setupMockInterface() { Loading @@ -151,6 +155,8 @@ public class LocationPermissionCheckerTest { .thenReturn(mCoarseLocationPermission); .thenReturn(mCoarseLocationPermission); when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) .thenReturn(mFineLocationPermission); .thenReturn(mFineLocationPermission); when(mMockContext.checkPermission(NETWORK_SETTINGS, -1, mUid)) .thenReturn(mNetworkSettingsPermission); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); } } Loading Loading @@ -264,6 +270,21 @@ public class LocationPermissionCheckerTest { assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); assertEquals(LocationPermissionChecker.ERROR_LOCATION_MODE_OFF, result); } } @Test public void testenforceCanAccessScanResults_LocationModeDisabledHasNetworkSettings() throws Exception { mThrowSecurityException = false; mIsLocationEnabled = false; mNetworkSettingsPermission = PackageManager.PERMISSION_GRANTED; setupTestCase(); final int result = mChecker.checkLocationPermissionWithDetailInfo( TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); assertEquals(LocationPermissionChecker.SUCCEEDED, result); } private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { try { try { r.run(); r.run(); Loading
tests/net/java/com/android/server/ConnectivityServiceTest.java +20 −8 Original line number Original line Diff line number Diff line Loading @@ -2074,10 +2074,6 @@ public class ConnectivityServiceTest { @Test @Test public void testOwnerUidCannotChange() throws Exception { public void testOwnerUidCannotChange() throws Exception { // Owner UIDs are not visible without location permission. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); final NetworkCapabilities ncTemplate = new NetworkCapabilities(); final NetworkCapabilities ncTemplate = new NetworkCapabilities(); final int originalOwnerUid = Process.myUid(); final int originalOwnerUid = Process.myUid(); ncTemplate.setOwnerUid(originalOwnerUid); ncTemplate.setOwnerUid(originalOwnerUid); Loading @@ -2097,6 +2093,10 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true); waitForIdle(); waitForIdle(); // Owner UIDs are not visible without location permission. setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); // Check that the capability change has been applied but the owner UID is not modified. // Check that the capability change has been applied but the owner UID is not modified. NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); assertEquals(originalOwnerUid, nc.getOwnerUid()); assertEquals(originalOwnerUid, nc.getOwnerUid()); Loading Loading @@ -7781,8 +7781,22 @@ public class ConnectivityServiceTest { naExtraInfo.unregister(); naExtraInfo.unregister(); } } // To avoid granting location permission bypass. private void denyAllLocationPrivilegedPermissions() { mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD, PERMISSION_DENIED); } private void setupLocationPermissions( private void setupLocationPermissions( int targetSdk, boolean locationToggle, String op, String perm) throws Exception { int targetSdk, boolean locationToggle, String op, String perm) throws Exception { denyAllLocationPrivilegedPermissions(); final ApplicationInfo applicationInfo = new ApplicationInfo(); final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = targetSdk; applicationInfo.targetSdkVersion = targetSdk; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) Loading Loading @@ -8156,15 +8170,13 @@ public class ConnectivityServiceTest { new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); mMockVpn.establishForMyUid(); mMockVpn.establishForMyUid(); assertUidRangesUpdatedForMyUid(true); assertUidRangesUpdatedForMyUid(true); // Wait for networks to connect and broadcasts to be sent before removing permissions. // Wait for networks to connect and broadcasts to be sent before removing permissions. waitForIdle(); waitForIdle(); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); waitForIdle(); waitForIdle(); Loading