2023-07-01 security patch level vulnerability details
Framework
CVE-2023-21254
getUidProcessState
这个接口的AMS对外服务版本和AMInternal进程内版本的实现不一致,对外版本中如果满足mPendingStartActivityUids.isPendingTopUid(uid)
的条件,就直接返回PROCESS_STATE_TOP
,在这种场景下会导致一次性权限无法被正常清除。ActivityManagerService#getUidProcessState
的实现:@Override public int getUidProcessState(int uid, String callingPackage) { if (!hasUsageStatsPermission(callingPackage)) { enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS, "getUidProcessState"); } // In case the caller is requesting processState of an app in a different user, // then verify the caller has INTERACT_ACROSS_USERS_FULL permission mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), UserHandle.getUserId(uid), false /* allowAll */, ALLOW_FULL_ONLY, "getUidProcessState", callingPackage); // Ignore return value synchronized (mProcLock) { if (mPendingStartActivityUids.isPendingTopUid(uid)) { return PROCESS_STATE_TOP; } return mProcessList.getUidProcStateLOSP(uid); } }
ActivityManagerInternal#getUidProcessState
的实现:// NOTE: this is an internal method used by the OnShellCommand implementation only and should // be guarded by permission checking. int getUidState(int uid) { synchronized (mProcLock) { return mProcessList.getUidProcStateLOSP(uid); } }
- 很明显的除了权限检查之外,就差了一个
mPendingStartActivityUids.isPendingTopUid(uid)
的条件判断。想让判断成立需要走PendingStartActivityUids#add
/** Returns {@code true} if the uid is put to the pending array. Otherwise it existed. */ synchronized boolean add(int uid, int pid) { if (mPendingUids.get(uid) == null) { mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime())); return true; } return false; }
- 只有一个地方可以实现,即
ActivityManagerService#addPendingTopUid
@Override public void addPendingTopUid(int uid, int pid, @Nullable IApplicationThread thread) { final boolean isNewPending = mPendingStartActivityUids.add(uid, pid); // If the next top activity is in cached and frozen mode, WM should raise its priority // to unfreeze it. This is done by calling AMS.updateOomAdj that will lower its oom adj. // However, WM cannot hold the AMS clock here so the updateOomAdj operation is performed // in a separate thread asynchronously. Therefore WM can't guarantee AMS will unfreeze // next top activity on time. This race will fail the following binder transactions WM // sends to the activity. After this race issue between WM/ATMS and AMS is solved, this // workaround can be removed. (b/213288355) if (isNewPending) { mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid, OomAdjuster.OOM_ADJ_REASON_ACTIVITY); } // We need to update the network rules for the app coming to the top state so that // it can access network when the device or the app is in a restricted state // (e.g. battery/data saver) but since waiting for updateOomAdj to complete and then // informing NetworkPolicyManager might get delayed, informing the state change as soon // as we know app is going to come to the top state. if (isNewPending && mNetworkPolicyUidObserver != null) { try { final long procStateSeq = mProcessList.getNextProcStateSeq(); mNetworkPolicyUidObserver.onUidStateChanged(uid, PROCESS_STATE_TOP, procStateSeq, PROCESS_CAPABILITY_ALL); if (thread != null && shouldWaitForNetworkRulesUpdate(uid)) { thread.setNetworkBlockSeq(procStateSeq); } } catch (RemoteException e) { Slog.d(TAG, "Error calling setNetworkBlockSeq", e); } } }
- 这个接口不是IPC接口,在system_server内部调用他的只有这里:
void onStartActivity(int topProcessState, ActivityInfo info) { String packageName = null; if ((info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(info.packageName)) { // Don't add this if it is a platform component that is marked to run in multiple // processes, because this is actually part of the framework so doesn't make sense // to track as a separate apk in the process. packageName = info.packageName; } // update ActivityManagerService.PendingStartActivityUids list. if (topProcessState == ActivityManager.PROCESS_STATE_TOP) { mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread); } prepareOomAdjustment(); // Posting the message at the front of queue so WM lock isn't held when we call into AM, // and the process state of starting activity can be updated quicker which will give it a // higher scheduling group. final Message m = PooledLambda.obtainMessage(WindowProcessListener::onStartActivity, mListener, topProcessState, shouldSetProfileProc(), packageName, info.applicationInfo.longVersionCode); mAtm.mH.sendMessageAtFrontOfQueue(m); }
- 所以就是刚启动Activity的时候就处于这个状态,想保持这个状态需要启动Activity之后马上退出,正如修复补丁中所说:
Install test app that requests permission and will exit immediately on granting, observe permission is no longer indefinitely held.