1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os; 18 19 import android.annotation.NonNull; 20 import android.annotation.SystemService; 21 import android.app.AppOpsManager; 22 import android.content.AttributionSource; 23 import android.content.Context; 24 import android.content.PermissionChecker; 25 import android.content.pm.PackageManager; 26 import android.permission.PermissionCheckerManager; 27 28 /** 29 * PermissionEnforcer check permissions for AIDL-generated services which use 30 * the @EnforcePermission annotation. 31 * 32 * <p>AIDL services may be annotated with @EnforcePermission which will trigger 33 * the generation of permission check code. This generated code relies on 34 * PermissionEnforcer to validate the permissions. The methods available are 35 * purposely similar to the AIDL annotation syntax. 36 * 37 * @see android.permission.PermissionManager 38 * 39 * @hide 40 */ 41 @SystemService(Context.PERMISSION_ENFORCER_SERVICE) 42 public class PermissionEnforcer { 43 44 private final Context mContext; 45 private static final String ACCESS_DENIED = "Access denied, requires: "; 46 47 /** Protected constructor. Allows subclasses to instantiate an object 48 * without using a Context. 49 */ PermissionEnforcer()50 protected PermissionEnforcer() { 51 mContext = null; 52 } 53 54 /** Constructor, prefer using the fromContext static method when possible */ PermissionEnforcer(@onNull Context context)55 public PermissionEnforcer(@NonNull Context context) { 56 mContext = context; 57 } 58 59 @PermissionCheckerManager.PermissionResult checkPermission(@onNull String permission, @NonNull AttributionSource source)60 protected int checkPermission(@NonNull String permission, @NonNull AttributionSource source) { 61 return PermissionChecker.checkPermissionForDataDelivery( 62 mContext, permission, PermissionChecker.PID_UNKNOWN, source, "" /* message */); 63 } 64 65 @SuppressWarnings("AndroidFrameworkClientSidePermissionCheck") 66 @PermissionCheckerManager.PermissionResult checkPermission(@onNull String permission, int pid, int uid)67 protected int checkPermission(@NonNull String permission, int pid, int uid) { 68 if (mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) { 69 return PermissionCheckerManager.PERMISSION_GRANTED; 70 } 71 return PermissionCheckerManager.PERMISSION_HARD_DENIED; 72 } 73 anyAppOps(@onNull String[] permissions)74 private boolean anyAppOps(@NonNull String[] permissions) { 75 for (String permission : permissions) { 76 if (AppOpsManager.permissionToOpCode(permission) != AppOpsManager.OP_NONE) { 77 return true; 78 } 79 } 80 return false; 81 } 82 enforcePermission(@onNull String permission, @NonNull AttributionSource source)83 public void enforcePermission(@NonNull String permission, @NonNull 84 AttributionSource source) throws SecurityException { 85 int result = checkPermission(permission, source); 86 if (result != PermissionCheckerManager.PERMISSION_GRANTED) { 87 throw new SecurityException(ACCESS_DENIED + permission); 88 } 89 } 90 enforcePermission(@onNull String permission, int pid, int uid)91 public void enforcePermission(@NonNull String permission, int pid, int uid) 92 throws SecurityException { 93 if (AppOpsManager.permissionToOpCode(permission) != AppOpsManager.OP_NONE) { 94 AttributionSource source = new AttributionSource(uid, null, null); 95 enforcePermission(permission, source); 96 return; 97 } 98 int result = checkPermission(permission, pid, uid); 99 if (result != PermissionCheckerManager.PERMISSION_GRANTED) { 100 throw new SecurityException(ACCESS_DENIED + permission); 101 } 102 } 103 enforcePermissionAllOf(@onNull String[] permissions, @NonNull AttributionSource source)104 public void enforcePermissionAllOf(@NonNull String[] permissions, 105 @NonNull AttributionSource source) throws SecurityException { 106 for (String permission : permissions) { 107 int result = checkPermission(permission, source); 108 if (result != PermissionCheckerManager.PERMISSION_GRANTED) { 109 throw new SecurityException(ACCESS_DENIED + "allOf={" 110 + String.join(", ", permissions) + "}"); 111 } 112 } 113 } 114 enforcePermissionAllOf(@onNull String[] permissions, int pid, int uid)115 public void enforcePermissionAllOf(@NonNull String[] permissions, 116 int pid, int uid) throws SecurityException { 117 if (anyAppOps(permissions)) { 118 AttributionSource source = new AttributionSource(uid, null, null); 119 enforcePermissionAllOf(permissions, source); 120 return; 121 } 122 for (String permission : permissions) { 123 int result = checkPermission(permission, pid, uid); 124 if (result != PermissionCheckerManager.PERMISSION_GRANTED) { 125 throw new SecurityException(ACCESS_DENIED + "allOf={" 126 + String.join(", ", permissions) + "}"); 127 } 128 } 129 } 130 enforcePermissionAnyOf(@onNull String[] permissions, @NonNull AttributionSource source)131 public void enforcePermissionAnyOf(@NonNull String[] permissions, 132 @NonNull AttributionSource source) throws SecurityException { 133 for (String permission : permissions) { 134 int result = checkPermission(permission, source); 135 if (result == PermissionCheckerManager.PERMISSION_GRANTED) { 136 return; 137 } 138 } 139 throw new SecurityException(ACCESS_DENIED + "anyOf={" 140 + String.join(", ", permissions) + "}"); 141 } 142 enforcePermissionAnyOf(@onNull String[] permissions, int pid, int uid)143 public void enforcePermissionAnyOf(@NonNull String[] permissions, 144 int pid, int uid) throws SecurityException { 145 if (anyAppOps(permissions)) { 146 AttributionSource source = new AttributionSource(uid, null, null); 147 enforcePermissionAnyOf(permissions, source); 148 return; 149 } 150 for (String permission : permissions) { 151 int result = checkPermission(permission, pid, uid); 152 if (result == PermissionCheckerManager.PERMISSION_GRANTED) { 153 return; 154 } 155 } 156 throw new SecurityException(ACCESS_DENIED + "anyOf={" 157 + String.join(", ", permissions) + "}"); 158 } 159 160 /** 161 * Returns a new PermissionEnforcer based on a Context. 162 * 163 * @hide 164 */ fromContext(@onNull Context context)165 public static PermissionEnforcer fromContext(@NonNull Context context) { 166 return context.getSystemService(PermissionEnforcer.class); 167 } 168 } 169