From 9a7467f77500bed398f216cc824a0e5e2f68c79d Mon Sep 17 00:00:00 2001 From: pkarandikar Date: Fri, 5 Aug 2022 18:58:33 +0000 Subject: [PATCH 1/2] Add security policies for checking device owner/profile owner. --- binder/build.gradle | 4 +- .../java/io/grpc/binder/SecurityPolicies.java | 83 +++++++++++++++++-- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/binder/build.gradle b/binder/build.gradle index 24dd0d9015d..ada6cca4434 100644 --- a/binder/build.gradle +++ b/binder/build.gradle @@ -23,14 +23,14 @@ android { } } } - compileSdkVersion 29 + compileSdkVersion 30 compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 } defaultConfig { minSdkVersion 19 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java index 25f215be696..e46fca5f622 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java @@ -17,11 +17,15 @@ package io.grpc.binder; import android.annotation.SuppressLint; +import android.app.admin.DevicePolicyManager; +import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.os.Build; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Process; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; @@ -173,11 +177,61 @@ public Status checkAuthorization(int uid) { }; } - private static Status checkUidSignature( - PackageManager packageManager, - int uid, - String packageName, - ImmutableList requiredSignatures) { + /** + * Creates {@link SecurityPolicy} which checks if the app is a device owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isDeviceOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, devicePolicyManager::isDeviceOwnerApp, + "Rejected by device owner policy. No packages found for UID.", + "Rejected by device owner policy"); + } + + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isProfileOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && devicePolicyManager.isProfileOwnerApp( + pkg), "Rejected by profile owner policy. No packages found for UID.", + "Rejected by profile owner policy"); + } + + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isDeviceOwnerOrProfileOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> devicePolicyManager.isDeviceOwnerApp(pkg) || ( + VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && devicePolicyManager.isProfileOwnerApp( + pkg)), "Rejected by profile owner policy. No packages found for UID.", + "Rejected by profile owner policy"); + } + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app on an + * organization-owned device. See {@link DevicePolicyManager}. + */ + public static SecurityPolicy isProfileOwnerOnOrganizationOwnedDevice(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> VERSION.SDK_INT >= VERSION_CODES.R && devicePolicyManager.isProfileOwnerApp(pkg) + && devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile(), + "Rejected by profile owner on organization-owned device policy." + + " No packages found for UID.", + "Rejected by profile owner on organization-owned device policy"); + } + + private static Status checkUidSignature(PackageManager packageManager, int uid, + String packageName, ImmutableList requiredSignatures) { String[] packages = packageManager.getPackagesForUid(uid); if (packages == null) { return Status.UNAUTHENTICATED.withDescription( @@ -406,6 +460,25 @@ private static Status checkPermissions( return Status.OK; } + private static SecurityPolicy anyPackageWithUidSatisfies(Context applicationContext, + Predicate condition, String errorMessageForNoPackages, String errorMessageForDenied) { + return new SecurityPolicy() { + @Override + public Status checkAuthorization(int uid) { + String[] packages = applicationContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + return Status.UNAUTHENTICATED.withDescription(errorMessageForNoPackages); + } + for (String pkg : packages) { + if (condition.apply(pkg)) { + return Status.OK; + } + } + return Status.PERMISSION_DENIED.withDescription(errorMessageForDenied); + } + }; + } + /** * Checks if the SHA-256 hash of the {@code signature} matches one of the {@code * expectedSignatureSha256Hashes}. From 693b44405d4122108ace6c85b584850e3a388f2c Mon Sep 17 00:00:00 2001 From: pkarandikar Date: Fri, 5 Aug 2022 18:58:33 +0000 Subject: [PATCH 2/2] Add security policies for checking device owner/profile owner. --- binder/build.gradle | 4 +- .../java/io/grpc/binder/SecurityPolicies.java | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/binder/build.gradle b/binder/build.gradle index 24dd0d9015d..ada6cca4434 100644 --- a/binder/build.gradle +++ b/binder/build.gradle @@ -23,14 +23,14 @@ android { } } } - compileSdkVersion 29 + compileSdkVersion 30 compileOptions { sourceCompatibility 1.8 targetCompatibility 1.8 } defaultConfig { minSdkVersion 19 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java index 25f215be696..e42baaa5f04 100644 --- a/binder/src/main/java/io/grpc/binder/SecurityPolicies.java +++ b/binder/src/main/java/io/grpc/binder/SecurityPolicies.java @@ -17,11 +17,15 @@ package io.grpc.binder; import android.annotation.SuppressLint; +import android.app.admin.DevicePolicyManager; +import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.os.Build; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Process; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; @@ -173,6 +177,59 @@ public Status checkAuthorization(int uid) { }; } + /** + * Creates {@link SecurityPolicy} which checks if the app is a device owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isDeviceOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, devicePolicyManager::isDeviceOwnerApp, + "Rejected by device owner policy. No packages found for UID.", + "Rejected by device owner policy"); + } + + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isProfileOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && devicePolicyManager.isProfileOwnerApp( + pkg), "Rejected by profile owner policy. No packages found for UID.", + "Rejected by profile owner policy"); + } + + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app. See + * {@link DevicePolicyManager}. + */ + public static SecurityPolicy isDeviceOwnerOrProfileOwner(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> devicePolicyManager.isDeviceOwnerApp(pkg) || ( + VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && devicePolicyManager.isProfileOwnerApp( + pkg)), "Rejected by profile owner policy. No packages found for UID.", + "Rejected by profile owner policy"); + } + /** + * Creates {@link SecurityPolicy} which checks if the app is a profile owner app on an + * organization-owned device. See {@link DevicePolicyManager}. + */ + public static SecurityPolicy isProfileOwnerOnOrganizationOwnedDevice(Context applicationContext) { + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) applicationContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return anyPackageWithUidSatisfies(applicationContext, + pkg -> VERSION.SDK_INT >= VERSION_CODES.R && devicePolicyManager.isProfileOwnerApp(pkg) + && devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile(), + "Rejected by profile owner on organization-owned device policy." + + " No packages found for UID.", + "Rejected by profile owner on organization-owned device policy"); + } + private static Status checkUidSignature( PackageManager packageManager, int uid, @@ -406,6 +463,25 @@ private static Status checkPermissions( return Status.OK; } + private static SecurityPolicy anyPackageWithUidSatisfies(Context applicationContext, + Predicate condition, String errorMessageForNoPackages, String errorMessageForDenied) { + return new SecurityPolicy() { + @Override + public Status checkAuthorization(int uid) { + String[] packages = applicationContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + return Status.UNAUTHENTICATED.withDescription(errorMessageForNoPackages); + } + for (String pkg : packages) { + if (condition.apply(pkg)) { + return Status.OK; + } + } + return Status.PERMISSION_DENIED.withDescription(errorMessageForDenied); + } + }; + } + /** * Checks if the SHA-256 hash of the {@code signature} matches one of the {@code * expectedSignatureSha256Hashes}.