From ec0d763059888ac017b48d07748ef9460107fa66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Wed, 29 Jun 2022 14:02:13 +1000 Subject: [PATCH 1/2] Add PermissionEnforcer class Defines a new PermissionEnforcer class used to check permission as part of the @EnforcePermission AIDL annotation. It is registered as a system service to avoid the cost of creating a new object for each new client. Bug: 234083358 Test: TH Change-Id: I2bd23f62a0d207ddac6bbe69666ced96e77ba16f Merged-In: I2bd23f62a0d207ddac6bbe69666ced96e77ba16f --- .../android/app/SystemServiceRegistry.java | 9 ++ core/java/android/content/Context.java | 8 ++ core/java/android/os/PermissionEnforcer.java | 101 ++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 core/java/android/os/PermissionEnforcer.java diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index bdecca379b202..8bbddbf136b93 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -171,6 +171,7 @@ import android.os.IThermalService; import android.os.IUserManager; import android.os.IncidentManager; import android.os.PerformanceHintManager; +import android.os.PermissionEnforcer; import android.os.PowerManager; import android.os.RecoverySystem; import android.os.ServiceManager; @@ -1351,6 +1352,14 @@ public final class SystemServiceRegistry { return new PermissionCheckerManager(ctx.getOuterContext()); }}); + registerService(Context.PERMISSION_ENFORCER_SERVICE, PermissionEnforcer.class, + new CachedServiceFetcher() { + @Override + public PermissionEnforcer createService(ContextImpl ctx) + throws ServiceNotFoundException { + return new PermissionEnforcer(ctx.getOuterContext()); + }}); + registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class, new CachedServiceFetcher() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index fce23cf6819a1..0735532ce0373 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5134,6 +5134,14 @@ public abstract class Context { */ public static final String PERMISSION_CHECKER_SERVICE = "permission_checker"; + /** + * Official published name of the (internal) permission enforcer service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String PERMISSION_ENFORCER_SERVICE = "permission_enforcer"; + /** * Use with {@link #getSystemService(String) to retrieve an * {@link android.apphibernation.AppHibernationManager}} for diff --git a/core/java/android/os/PermissionEnforcer.java b/core/java/android/os/PermissionEnforcer.java new file mode 100644 index 0000000000000..221e89a6a76f7 --- /dev/null +++ b/core/java/android/os/PermissionEnforcer.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.annotation.NonNull; +import android.annotation.SystemService; +import android.content.AttributionSource; +import android.content.Context; +import android.content.PermissionChecker; +import android.permission.PermissionCheckerManager; + +/** + * PermissionEnforcer check permissions for AIDL-generated services which use + * the @EnforcePermission annotation. + * + *

AIDL services may be annotated with @EnforcePermission which will trigger + * the generation of permission check code. This generated code relies on + * PermissionEnforcer to validate the permissions. The methods available are + * purposely similar to the AIDL annotation syntax. + * + * @see android.permission.PermissionManager + * + * @hide + */ +@SystemService(Context.PERMISSION_ENFORCER_SERVICE) +public class PermissionEnforcer { + + private final Context mContext; + + /** Protected constructor. Allows subclasses to instantiate an object + * without using a Context. + */ + protected PermissionEnforcer() { + mContext = null; + } + + /** Constructor, prefer using the fromContext static method when possible */ + public PermissionEnforcer(@NonNull Context context) { + mContext = context; + } + + @PermissionCheckerManager.PermissionResult + protected int checkPermission(@NonNull String permission, @NonNull AttributionSource source) { + return PermissionChecker.checkPermissionForDataDelivery( + mContext, permission, PermissionChecker.PID_UNKNOWN, source, "" /* message */); + } + + public void enforcePermission(@NonNull String permission, @NonNull + AttributionSource source) throws SecurityException { + int result = checkPermission(permission, source); + if (result != PermissionCheckerManager.PERMISSION_GRANTED) { + throw new SecurityException("Access denied, requires: " + permission); + } + } + + public void enforcePermissionAllOf(@NonNull String[] permissions, + @NonNull AttributionSource source) throws SecurityException { + for (String permission : permissions) { + int result = checkPermission(permission, source); + if (result != PermissionCheckerManager.PERMISSION_GRANTED) { + throw new SecurityException("Access denied, requires: allOf={" + + String.join(", ", permissions) + "}"); + } + } + } + + public void enforcePermissionAnyOf(@NonNull String[] permissions, + @NonNull AttributionSource source) throws SecurityException { + for (String permission : permissions) { + int result = checkPermission(permission, source); + if (result == PermissionCheckerManager.PERMISSION_GRANTED) { + return; + } + } + throw new SecurityException("Access denied, requires: anyOf={" + + String.join(", ", permissions) + "}"); + } + + /** + * Returns a new PermissionEnforcer based on a Context. + * + * @hide + */ + public static PermissionEnforcer fromContext(@NonNull Context context) { + return context.getSystemService(PermissionEnforcer.class); + } +} From 0e318f1938dfa0c7a9ef789e8ca4fe1273e429f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Thu, 27 Oct 2022 11:08:08 +1100 Subject: [PATCH 2/2] Add OWNER entry for android.os.PermissionEnforcer Bug: 241171714 Bug: 243724362 Test: Gerrit OWNERS validation plugin Change-Id: I72f810a75ebee3813fc7ad87f8187a0ebc135bc7 --- core/java/android/os/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index d84037f666481..9d8df7e62bce9 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -70,3 +70,7 @@ per-file Vintf* = file:/platform/system/libvintf:/OWNERS # Tracing per-file Trace.java = file:/TRACE_OWNERS + +# PermissionEnforcer +per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com +per-file PermissionEnforcer.java = file:/core/java/android/permission/OWNERS