1 /* 2 * Copyright (C) 2024 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 com.android.server.am; 18 19 import android.annotation.Nullable; 20 import android.os.Process; 21 import android.os.UserHandle; 22 23 import com.android.internal.annotations.GuardedBy; 24 import com.android.server.appop.AppOpsService; 25 import com.android.server.pm.permission.AccessCheckDelegate; 26 import com.android.server.pm.permission.PermissionManagerServiceInternal; 27 28 import java.util.Collections; 29 import java.util.List; 30 31 class AccessCheckDelegateHelper { 32 private final ActivityManagerGlobalLock mProcLock; 33 34 @GuardedBy("mProcLock") 35 private final List<ActiveInstrumentation> mActiveInstrumentation; 36 37 private final AppOpsService mAppOpsService; 38 39 private final PermissionManagerServiceInternal mPermissionManagerInternal; 40 41 @GuardedBy("mProcLock") 42 private AccessCheckDelegate mAccessCheckDelegate; 43 AccessCheckDelegateHelper(ActivityManagerGlobalLock procLock, List<ActiveInstrumentation> activeInstrumentation, AppOpsService appOpsService, PermissionManagerServiceInternal permissionManagerInternal)44 AccessCheckDelegateHelper(ActivityManagerGlobalLock procLock, 45 List<ActiveInstrumentation> activeInstrumentation, AppOpsService appOpsService, 46 PermissionManagerServiceInternal permissionManagerInternal) { 47 mProcLock = procLock; 48 mActiveInstrumentation = activeInstrumentation; 49 mAppOpsService = appOpsService; 50 mPermissionManagerInternal = permissionManagerInternal; 51 } 52 53 @GuardedBy("mProcLock") getAccessCheckDelegateLPr(boolean create)54 private AccessCheckDelegate getAccessCheckDelegateLPr(boolean create) { 55 if (create && mAccessCheckDelegate == null) { 56 mAccessCheckDelegate = new AccessCheckDelegate.AccessCheckDelegateImpl(); 57 mAppOpsService.setCheckOpsDelegate(mAccessCheckDelegate); 58 mPermissionManagerInternal.setCheckPermissionDelegate(mAccessCheckDelegate); 59 } 60 61 return mAccessCheckDelegate; 62 } 63 64 @GuardedBy("mProcLock") removeAccessCheckDelegateLPr()65 private void removeAccessCheckDelegateLPr() { 66 mAccessCheckDelegate = null; 67 mAppOpsService.setCheckOpsDelegate(null); 68 mPermissionManagerInternal.setCheckPermissionDelegate(null); 69 } 70 startDelegateShellPermissionIdentity(int delegateUid, @Nullable String[] permissions)71 void startDelegateShellPermissionIdentity(int delegateUid, 72 @Nullable String[] permissions) { 73 if (UserHandle.getCallingAppId() != Process.SHELL_UID 74 && UserHandle.getCallingAppId() != Process.ROOT_UID) { 75 throw new SecurityException("Only the shell can delegate its permissions"); 76 } 77 78 synchronized (mProcLock) { 79 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 80 if (delegate != null && !delegate.isDelegateAndOwnerUid(delegateUid)) { 81 throw new SecurityException("Shell can delegate permissions only " 82 + "to one instrumentation at a time"); 83 } 84 final int instrCount = mActiveInstrumentation.size(); 85 for (int i = 0; i < instrCount; i++) { 86 final ActiveInstrumentation instr = 87 mActiveInstrumentation.get(i); 88 if (instr.mTargetInfo.uid != delegateUid) { 89 continue; 90 } 91 92 // If instrumentation started from the shell the connection is not null 93 if (instr.mUiAutomationConnection == null) { 94 throw new SecurityException("Shell can delegate its permissions" 95 + " only to an instrumentation started from the shell"); 96 } 97 98 final String packageName = instr.mTargetInfo.packageName; 99 delegate = getAccessCheckDelegateLPr(true); 100 delegate.setShellPermissionDelegate(delegateUid, packageName, permissions); 101 return; 102 } 103 } 104 } 105 stopDelegateShellPermissionIdentity()106 void stopDelegateShellPermissionIdentity() { 107 if (UserHandle.getCallingAppId() != Process.SHELL_UID 108 && UserHandle.getCallingAppId() != Process.ROOT_UID) { 109 throw new SecurityException("Only the shell can delegate its permissions"); 110 } 111 synchronized (mProcLock) { 112 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 113 if (delegate == null) { 114 return; 115 } 116 117 if (!delegate.hasShellPermissionDelegate()) { 118 return; 119 } 120 121 delegate.removeShellPermissionDelegate(); 122 123 if (!delegate.hasDelegateOrOverrides()) { 124 removeAccessCheckDelegateLPr(); 125 } 126 } 127 } 128 getDelegatedShellPermissions()129 List<String> getDelegatedShellPermissions() { 130 if (UserHandle.getCallingAppId() != Process.SHELL_UID 131 && UserHandle.getCallingAppId() != Process.ROOT_UID) { 132 throw new SecurityException("Only the shell can get delegated permissions"); 133 } 134 synchronized (mProcLock) { 135 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 136 if (delegate == null) { 137 return Collections.EMPTY_LIST; 138 } 139 140 return delegate.getDelegatedPermissionNames(); 141 } 142 } 143 addOverridePermissionState(int originatingUid, int uid, String permission, int result)144 void addOverridePermissionState(int originatingUid, int uid, String permission, int result) { 145 if (UserHandle.getCallingAppId() != Process.ROOT_UID) { 146 throw new SecurityException("Only root can override permissions"); 147 } 148 149 synchronized (mProcLock) { 150 final int instrCount = mActiveInstrumentation.size(); 151 for (int i = 0; i < instrCount; i++) { 152 final ActiveInstrumentation instr = 153 mActiveInstrumentation.get(i); 154 if (instr.mTargetInfo.uid != originatingUid) { 155 continue; 156 } 157 // If instrumentation started from the shell the connection is not null 158 if (instr.mSourceUid != Process.ROOT_UID || instr.mUiAutomationConnection == null) { 159 throw new SecurityException("Root can only override permissions only if the " 160 + "owning app was instrumented from root."); 161 } 162 163 AccessCheckDelegate delegate = 164 getAccessCheckDelegateLPr(true); 165 if (delegate.hasOverriddenPermissions() 166 && !delegate.isDelegateAndOwnerUid(originatingUid)) { 167 throw new SecurityException("Only one instrumentation to grant" 168 + " overrides is allowed at a time."); 169 } 170 171 delegate.addOverridePermissionState(originatingUid, uid, permission, result); 172 return; 173 } 174 } 175 } 176 removeOverridePermissionState(int originatingUid, int uid, String permission)177 void removeOverridePermissionState(int originatingUid, int uid, String permission) { 178 if (UserHandle.getCallingAppId() != Process.ROOT_UID) { 179 throw new SecurityException("Only root can override permissions."); 180 } 181 182 synchronized (mProcLock) { 183 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 184 if (delegate == null) { 185 return; 186 } 187 188 if (!delegate.isDelegateAndOwnerUid(originatingUid)) { 189 if (delegate.hasOverriddenPermissions()) { 190 throw new SecurityException("Only the granter of current overrides can remove " 191 + "them."); 192 } 193 return; 194 } 195 196 delegate.removeOverridePermissionState(uid, permission); 197 198 if (!delegate.hasDelegateOrOverrides()) { 199 removeAccessCheckDelegateLPr(); 200 } 201 } 202 } 203 clearOverridePermissionStates(int originatingUid, int uid)204 void clearOverridePermissionStates(int originatingUid, int uid) { 205 if (UserHandle.getCallingAppId() != Process.ROOT_UID) { 206 throw new SecurityException("Only root can override permissions."); 207 } 208 synchronized (mProcLock) { 209 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 210 if (delegate == null) { 211 return; 212 } 213 214 if (!delegate.isDelegateAndOwnerUid(originatingUid)) { 215 if (delegate.hasOverriddenPermissions()) { 216 throw new SecurityException( 217 "Only the granter of current overrides can remove them."); 218 } 219 return; 220 } 221 222 delegate.clearOverridePermissionStates(uid); 223 224 if (!delegate.hasDelegateOrOverrides()) { 225 removeAccessCheckDelegateLPr(); 226 } 227 } 228 } 229 clearAllOverridePermissionStates(int originatingUid)230 void clearAllOverridePermissionStates(int originatingUid) { 231 if (UserHandle.getCallingAppId() != Process.ROOT_UID) { 232 throw new SecurityException("Only root can override permissions."); 233 } 234 synchronized (mProcLock) { 235 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 236 if (delegate == null) { 237 return; 238 } 239 240 if (!delegate.isDelegateAndOwnerUid(originatingUid)) { 241 if (delegate.hasOverriddenPermissions()) { 242 throw new SecurityException( 243 "Only the granter of current overrides can remove them."); 244 } 245 return; 246 } 247 248 delegate.clearAllOverridePermissionStates(); 249 250 if (!delegate.hasDelegateOrOverrides()) { 251 removeAccessCheckDelegateLPr(); 252 } 253 } 254 } 255 onInstrumentationFinished(int uid, String packageName)256 void onInstrumentationFinished(int uid, String packageName) { 257 synchronized (mProcLock) { 258 AccessCheckDelegate delegate = getAccessCheckDelegateLPr(false); 259 if (delegate != null) { 260 if (delegate.isDelegatePackage(uid, packageName)) { 261 delegate.removeShellPermissionDelegate(); 262 } 263 if (delegate.isDelegateAndOwnerUid(uid)) { 264 delegate.clearAllOverridePermissionStates(); 265 } 266 if (!delegate.hasDelegateOrOverrides()) { 267 removeAccessCheckDelegateLPr(); 268 } 269 } 270 } 271 } 272 } 273