From 8fdc4318c7ad8a22deb3eed806807f407112bbd9 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 16 Jan 2024 11:19:43 +0800 Subject: [PATCH] Add helper method to enfore a package name belongs to an uid This is no-op refactor to move utility methods from ConnectivityService to a common place. Test: atest NetworkStaticLibTests#com.android.net.moduletests.util.PermissionUtilsTest#testEnforcePackageNameMatchesUid Bug: N/A Change-Id: I5802dedcc91fa6e130a5c534bba5080ca37dbeec --- .../android/server/ConnectivityService.java | 23 ++------------ .../net/module/util/PermissionUtils.java | 31 +++++++++++++++++++ .../net/module/util/PermissionUtilsTest.kt | 29 +++++++++++++++++ 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 7339d083ba..66e10a2ca1 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -3004,26 +3004,6 @@ public class ConnectivityService extends IConnectivityManager.Stub 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 * host via the specified network interface. @@ -3039,7 +3019,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (disallowedBecauseSystemCaller()) { return false; } - verifyCallingUidAndPackage(callingPackageName, mDeps.getCallingUid()); + PermissionUtils.enforcePackageNameMatchesUid( + mContext, mDeps.getCallingUid(), callingPackageName); enforceChangePermission(callingPackageName, callingAttributionTag); if (mProtectedNetworks.contains(networkType)) { enforceConnectivityRestrictedNetworksPermission(true /* checkUidsAllowedList */); diff --git a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java index 8315b8f6f5..f167d3d25e 100644 --- a/staticlibs/framework/com/android/net/module/util/PermissionUtils.java +++ b/staticlibs/framework/com/android/net/module/util/PermissionUtils.java @@ -27,7 +27,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Binder; +import android.os.UserHandle; import java.io.PrintWriter; import java.util.ArrayList; @@ -183,4 +185,33 @@ public final class PermissionUtils { } 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); + } + } } diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt index c5a91a4928..d5b43fb10b 100644 --- a/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt +++ b/staticlibs/tests/unit/src/com/android/net/module/util/PermissionUtilsTest.kt @@ -19,6 +19,7 @@ package com.android.net.module.util import android.Manifest.permission.NETWORK_STACK import android.content.Context import android.content.pm.PackageManager +import android.content.pm.PackageManager.NameNotFoundException import android.content.pm.PackageManager.PERMISSION_DENIED import android.content.pm.PackageManager.PERMISSION_GRANTED 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.enforceNetworkStackPermission 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.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRunner @@ -42,7 +44,10 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.doReturn +import org.mockito.Mockito.doThrow import org.mockito.Mockito.mock /** Tests for PermissionUtils */ @@ -53,6 +58,9 @@ class PermissionUtilsTest { val ignoreRule = DevSdkIgnoreRule() private val TEST_PERMISSION1 = "android.permission.TEST_PERMISSION1" 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 mockPackageManager = mock(PackageManager::class.java) @@ -61,6 +69,7 @@ class PermissionUtilsTest { @Before fun setup() { doReturn(mockPackageManager).`when`(mockContext).packageManager + doReturn(mockContext).`when`(mockContext).createContextAsUser(any(), anyInt()) } @Test @@ -141,4 +150,24 @@ class PermissionUtilsTest { 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 { + enforcePackageNameMatchesUid(mockContext, TEST_UID1, TEST_PACKAGE_NAME) + } + + // Verify uid mismatch throws. + doReturn(TEST_UID1).`when`(mockPackageManager) + .getPackageUid(eq(TEST_PACKAGE_NAME), anyInt()) + assertFailsWith { + enforcePackageNameMatchesUid(mockContext, TEST_UID2, TEST_PACKAGE_NAME) + } + + // Verify uid match passes. + enforcePackageNameMatchesUid(mockContext, TEST_UID1, TEST_PACKAGE_NAME) + } }