Android security tags, read closely by Lightrion

CVE-2025-48548 AI-generated analysis

platform/frameworks/av (audiopolicy service, media/utils ServiceUtilities) and platform/frameworks/base (PermissionManagerService AppOps checks, SystemUI AppOpsControllerImpl)

AI-generated: written from the bulletin and the fixing diffs by claude-fable-5-1, then checked against the code by claude-opus-5-5 (11 corrections). Verify against the commit before relying on it.

Makes audioserver's silencing of a recording client match the AppOps op state. startRecording now returns the exact permission result (granted/soft/hard denied). startInput un-silences a client only when the op was granted. finishRecording is called only for clients that were not silenced. Sources that do not need the record op are checked against their own op instead of having their result ignored. Companion frameworks/base changes fix AppOps attribution-chain preflight and cleanup, and the SystemUI mic indicator suppression logic.

Root cause

In media/utils/ServiceUtilities.cpp, checkRecordingInternal reduced the PermissionChecker result to a bool that was true for anything other than PERMISSION_HARD_DENIED, so a soft-denied result looked like success. AudioPolicyService::startInput (AudioPolicyInterfaceImpl.cpp) then always called setAppState_l(client, APP_STATE_TOP), forcing the client un-silenced whatever the real op state was. stopInput and the startInput failure path always called finishRecording, even for silenced clients, so op start/finish counts did not match. startInput also ignored a failing startRecording result for AUDIO_SOURCE_FM_TUNER, REMOTE_SUBMIX and ECHO_REFERENCE through an OR condition. In setAppState_l, a failed startRecording only set a local silenced flag and the function carried on. In AudioRecordClient.cpp, OpRecordAudioMonitor also monitored OP_RECORD_AUDIO whenever its op was different, even for sources that do not need it. A failed target SDK lookup returned -1, which was treated as pre-U, so WATCH_FOREGROUND_CHANGES was not used. On the frameworks/base side, the attribution-chain loop in PermissionManagerService did not finish proxy ops it had already started when a later link failed during startDataDelivery. The preflight path in performOpTransaction checked the first chain entry (the datasource, e.g. audioserver), so preflight could fail where delivery would succeed. SystemUI AppOpsControllerImpl suppressed the microphone indicator if any recording for a UID was paused, rather than only when all of them were.

How the fix works

Completeness

Behavior changes

Per major

Unknowns

Back to September 2025 · Findings