Merge changes Ifafafcd6,I5802dedc into main
* changes: Fix incorrect nullability annotations Add helper method to enfore a package name belongs to an uid
This commit is contained in:
commit
fbc97d95bb
6 changed files with 75 additions and 29 deletions
|
|
@ -23,6 +23,7 @@ import static android.net.TrafficStats.UID_TETHERING;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
@ -109,7 +110,7 @@ public final class NetworkStatsAccess {
|
||||||
|
|
||||||
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
|
/** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
|
||||||
public static @NetworkStatsAccess.Level int checkAccessLevel(
|
public static @NetworkStatsAccess.Level int checkAccessLevel(
|
||||||
Context context, int callingPid, int callingUid, String callingPackage) {
|
Context context, int callingPid, int callingUid, @Nullable String callingPackage) {
|
||||||
final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
|
final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class);
|
||||||
final TelephonyManager tm = (TelephonyManager)
|
final TelephonyManager tm = (TelephonyManager)
|
||||||
context.getSystemService(Context.TELEPHONY_SERVICE);
|
context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
|
|
||||||
|
|
@ -492,9 +492,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
*/
|
*/
|
||||||
private static class OpenSessionKey {
|
private static class OpenSessionKey {
|
||||||
public final int uid;
|
public final int uid;
|
||||||
|
@Nullable
|
||||||
public final String packageName;
|
public final String packageName;
|
||||||
|
|
||||||
OpenSessionKey(int uid, @NonNull String packageName) {
|
OpenSessionKey(int uid, @Nullable String packageName) {
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
}
|
}
|
||||||
|
|
@ -1461,7 +1462,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
return now - lastCallTime < POLL_RATE_LIMIT_MS;
|
return now - lastCallTime < POLL_RATE_LIMIT_MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int restrictFlagsForCaller(int flags, @NonNull String callingPackage) {
|
private int restrictFlagsForCaller(int flags, @Nullable String callingPackage) {
|
||||||
// All non-privileged callers are not allowed to turn off POLL_ON_OPEN.
|
// All non-privileged callers are not allowed to turn off POLL_ON_OPEN.
|
||||||
final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext,
|
final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext,
|
||||||
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
|
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
|
||||||
|
|
@ -1478,7 +1479,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) {
|
private INetworkStatsSession openSessionInternal(
|
||||||
|
final int flags, @Nullable final String callingPackage) {
|
||||||
final int restrictedFlags = restrictFlagsForCaller(flags, callingPackage);
|
final int restrictedFlags = restrictFlagsForCaller(flags, callingPackage);
|
||||||
if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN
|
if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN
|
||||||
| NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
|
| NetworkStatsManager.FLAG_POLL_FORCE)) != 0) {
|
||||||
|
|
@ -1495,6 +1497,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
|
|
||||||
return new INetworkStatsSession.Stub() {
|
return new INetworkStatsSession.Stub() {
|
||||||
private final int mCallingUid = Binder.getCallingUid();
|
private final int mCallingUid = Binder.getCallingUid();
|
||||||
|
@Nullable
|
||||||
private final String mCallingPackage = callingPackage;
|
private final String mCallingPackage = callingPackage;
|
||||||
private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel(
|
private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel(
|
||||||
callingPackage);
|
callingPackage);
|
||||||
|
|
@ -1633,7 +1636,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enforceTemplatePermissions(@NonNull NetworkTemplate template,
|
private void enforceTemplatePermissions(@NonNull NetworkTemplate template,
|
||||||
@NonNull String callingPackage) {
|
@Nullable String callingPackage) {
|
||||||
// For a template with wifi network keys, it is possible for a malicious
|
// For a template with wifi network keys, it is possible for a malicious
|
||||||
// client to track the user locations via querying data usage. Thus, enforce
|
// client to track the user locations via querying data usage. Thus, enforce
|
||||||
// fine location permission check.
|
// fine location permission check.
|
||||||
|
|
@ -1654,7 +1657,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
|
private @NetworkStatsAccess.Level int checkAccessLevel(@Nullable String callingPackage) {
|
||||||
return NetworkStatsAccess.checkAccessLevel(
|
return NetworkStatsAccess.checkAccessLevel(
|
||||||
mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
|
mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3021,26 +3021,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getAppUid(final String app, final UserHandle user) {
|
|
||||||
final PackageManager pm =
|
|
||||||
mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
return pm.getPackageUid(app, 0 /* flags */);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
return -1;
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyCallingUidAndPackage(String packageName, int callingUid) {
|
|
||||||
final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
|
|
||||||
if (getAppUid(packageName, user) != callingUid) {
|
|
||||||
throw new SecurityException(packageName + " does not belong to uid " + callingUid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that a network route exists to deliver traffic to the specified
|
* Ensure that a network route exists to deliver traffic to the specified
|
||||||
* host via the specified network interface.
|
* host via the specified network interface.
|
||||||
|
|
@ -3056,7 +3036,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||||
if (disallowedBecauseSystemCaller()) {
|
if (disallowedBecauseSystemCaller()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
verifyCallingUidAndPackage(callingPackageName, mDeps.getCallingUid());
|
PermissionUtils.enforcePackageNameMatchesUid(
|
||||||
|
mContext, mDeps.getCallingUid(), callingPackageName);
|
||||||
enforceChangePermission(callingPackageName, callingAttributionTag);
|
enforceChangePermission(callingPackageName, callingAttributionTag);
|
||||||
if (mProtectedNetworks.contains(networkType)) {
|
if (mProtectedNetworks.contains(networkType)) {
|
||||||
enforceConnectivityRestrictedNetworksPermission(true /* checkUidsAllowedList */);
|
enforceConnectivityRestrictedNetworksPermission(true /* checkUidsAllowedList */);
|
||||||
|
|
|
||||||
|
|
@ -189,8 +189,9 @@ public class LocationPermissionChecker {
|
||||||
* @param message A message describing why the permission was checked. Only needed if this is
|
* @param message A message describing why the permission was checked. Only needed if this is
|
||||||
* not inside of a two-way binder call from the data receiver
|
* not inside of a two-way binder call from the data receiver
|
||||||
*/
|
*/
|
||||||
public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
|
public boolean checkCallersLocationPermission(@Nullable String pkgName,
|
||||||
int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
|
@Nullable String featureId, int uid, boolean coarseForTargetSdkLessThanQ,
|
||||||
|
@Nullable String message) {
|
||||||
|
|
||||||
boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
|
boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,9 @@ import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -183,4 +185,33 @@ public final class PermissionUtils {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enforces that the given package name belongs to the given uid.
|
||||||
|
*
|
||||||
|
* @param context {@link android.content.Context} for the process.
|
||||||
|
* @param uid User ID to check the package ownership for.
|
||||||
|
* @param packageName Package name to verify.
|
||||||
|
* @throws SecurityException If the package does not belong to the specified uid.
|
||||||
|
*/
|
||||||
|
public static void enforcePackageNameMatchesUid(
|
||||||
|
@NonNull Context context, int uid, @Nullable String packageName) {
|
||||||
|
final UserHandle user = UserHandle.getUserHandleForUid(uid);
|
||||||
|
if (getAppUid(context, packageName, user) != uid) {
|
||||||
|
throw new SecurityException(packageName + " does not belong to uid " + uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getAppUid(Context context, final String app, final UserHandle user) {
|
||||||
|
final PackageManager pm =
|
||||||
|
context.createContextAsUser(user, 0 /* flags */).getPackageManager();
|
||||||
|
final long token = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
return pm.getPackageUid(app, 0 /* flags */);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return -1;
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package com.android.net.module.util
|
||||||
import android.Manifest.permission.NETWORK_STACK
|
import android.Manifest.permission.NETWORK_STACK
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.PackageManager.NameNotFoundException
|
||||||
import android.content.pm.PackageManager.PERMISSION_DENIED
|
import android.content.pm.PackageManager.PERMISSION_DENIED
|
||||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||||
import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
|
import android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
|
||||||
|
|
@ -28,6 +29,7 @@ import com.android.net.module.util.PermissionUtils.checkAnyPermissionOf
|
||||||
import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf
|
import com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf
|
||||||
import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission
|
import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission
|
||||||
import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr
|
import com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr
|
||||||
|
import com.android.net.module.util.PermissionUtils.enforcePackageNameMatchesUid
|
||||||
import com.android.net.module.util.PermissionUtils.enforceSystemFeature
|
import com.android.net.module.util.PermissionUtils.enforceSystemFeature
|
||||||
import com.android.testutils.DevSdkIgnoreRule
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
import com.android.testutils.DevSdkIgnoreRunner
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
|
@ -42,7 +44,10 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers
|
||||||
import org.mockito.ArgumentMatchers.any
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.ArgumentMatchers.eq
|
||||||
import org.mockito.Mockito.doReturn
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.doThrow
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
|
|
||||||
/** Tests for PermissionUtils */
|
/** Tests for PermissionUtils */
|
||||||
|
|
@ -53,6 +58,9 @@ class PermissionUtilsTest {
|
||||||
val ignoreRule = DevSdkIgnoreRule()
|
val ignoreRule = DevSdkIgnoreRule()
|
||||||
private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1"
|
private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1"
|
||||||
private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2"
|
private val TEST_PERMISSION2 = "android.permission.TEST_PERMISSION2"
|
||||||
|
private val TEST_UID1 = 1234
|
||||||
|
private val TEST_UID2 = 1235
|
||||||
|
private val TEST_PACKAGE_NAME = "test.package"
|
||||||
private val mockContext = mock(Context::class.java)
|
private val mockContext = mock(Context::class.java)
|
||||||
private val mockPackageManager = mock(PackageManager::class.java)
|
private val mockPackageManager = mock(PackageManager::class.java)
|
||||||
|
|
||||||
|
|
@ -61,6 +69,7 @@ class PermissionUtilsTest {
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
doReturn(mockPackageManager).`when`(mockContext).packageManager
|
doReturn(mockPackageManager).`when`(mockContext).packageManager
|
||||||
|
doReturn(mockContext).`when`(mockContext).createContextAsUser(any(), anyInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -141,4 +150,24 @@ class PermissionUtilsTest {
|
||||||
Assert.fail("Exception should have not been thrown with system feature enabled")
|
Assert.fail("Exception should have not been thrown with system feature enabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEnforcePackageNameMatchesUid() {
|
||||||
|
// Verify name not found throws.
|
||||||
|
doThrow(NameNotFoundException()).`when`(mockPackageManager)
|
||||||
|
.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt())
|
||||||
|
assertFailsWith<SecurityException> {
|
||||||
|
enforcePackageNameMatchesUid(mockContext, TEST_UID1, TEST_PACKAGE_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify uid mismatch throws.
|
||||||
|
doReturn(TEST_UID1).`when`(mockPackageManager)
|
||||||
|
.getPackageUid(eq(TEST_PACKAGE_NAME), anyInt())
|
||||||
|
assertFailsWith<SecurityException> {
|
||||||
|
enforcePackageNameMatchesUid(mockContext, TEST_UID2, TEST_PACKAGE_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify uid match passes.
|
||||||
|
enforcePackageNameMatchesUid(mockContext, TEST_UID1, TEST_PACKAGE_NAME)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue