diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 152883be65..2f67a18297 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -879,6 +879,7 @@ status_t AudioSystem::getOutputForAttr(audio_attributes_t *attr, audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, @@ -888,7 +889,7 @@ status_t AudioSystem::getOutputForAttr(audio_attributes_t *attr, const sp& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return NO_INIT; return aps->getOutputForAttr(attr, output, session, stream, pid, uid, - config, + opPackageName, config, flags, selectedDeviceId, portId, secondaryOutputs); } diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 5b3a0573e8..cccb131405 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -214,6 +214,7 @@ public: audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, @@ -252,6 +253,7 @@ public: } data.writeInt32(pid); data.writeInt32(uid); + data.writeString16(opPackageName); data.write(config, sizeof(audio_config_t)); data.writeInt32(static_cast (flags)); data.writeInt32(*selectedDeviceId); @@ -1645,6 +1647,11 @@ status_t BnAudioPolicyService::onTransact( } pid_t pid = (pid_t)data.readInt32(); uid_t uid = (uid_t)data.readInt32(); + String16 opPackageName; + status = data.readString16(&opPackageName); + if (status != NO_ERROR) { + return status; + } audio_config_t config; memset(&config, 0, sizeof(audio_config_t)); data.read(&config, sizeof(audio_config_t)); @@ -1656,7 +1663,7 @@ status_t BnAudioPolicyService::onTransact( std::vector secondaryOutputs; status = getOutputForAttr(&attr, &output, session, &stream, pid, uid, - &config, + opPackageName, &config, flags, &selectedDeviceId, &portId, &secondaryOutputs); reply->writeInt32(status); status = reply->write(&attr, sizeof(audio_attributes_t)); diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index fe211e0054..07a2292262 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -240,6 +240,7 @@ public: audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index 8bc1d83809..8658cfa4f6 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -70,6 +70,7 @@ public: if (clientInfo.readFromParcel(parcel) != NO_ERROR) { return DEAD_OBJECT; } + opPackageName = parcel->readString16(); if (parcel->readInt32() != 0) { // TODO: Using unsecurePointer() has some associated security // pitfalls (see declaration for details). @@ -97,6 +98,7 @@ public: (void)parcel->write(&attr, sizeof(audio_attributes_t)); (void)parcel->write(&config, sizeof(audio_config_t)); (void)clientInfo.writeToParcel(parcel); + (void)parcel->writeString16(opPackageName); if (sharedBuffer != 0) { (void)parcel->writeInt32(1); (void)parcel->writeStrongBinder(IInterface::asBinder(sharedBuffer)); @@ -119,6 +121,7 @@ public: audio_attributes_t attr; audio_config_t config; AudioClient clientInfo; + String16 opPackageName; sp sharedBuffer; uint32_t notificationsPerBuffer; float speed; diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index fe54dc575c..779ca4379e 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -64,6 +64,7 @@ public: audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index 87ea084811..7fd4d0af6b 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -223,6 +223,25 @@ bool modifyPhoneStateAllowed(pid_t pid, uid_t uid) { return ok; } +bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid) { + static const String16 sAccessCallAudio("android.permission.ACCESS_CALL_AUDIO"); + PermissionController permissionController; + const String16 resolvedOpPackageName = resolveCallingPackage( + permissionController, opPackageName, uid); + if (resolvedOpPackageName.size() == 0) { + ALOGE("accessCallAudioAllowed - FAIL - package not found."); + return false; + } + AppOpsManager appOps; + const int32_t op = appOps.permissionToOpCode(sAccessCallAudio); + const int32_t opResult = appOps.noteOp(op, uid, resolvedOpPackageName); + if (opResult == PermissionController::MODE_DEFAULT) { + // Only allow in case this is a system app with the proper privilege permission + return PermissionCache::checkPermission(sAccessCallAudio, pid, uid); + } + return opResult == PermissionController::MODE_ALLOWED; +} + // privileged behavior needed by Dialer, Settings, SetupWizard and CellBroadcastReceiver bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid) { static const String16 sWriteSecureSettings("android.permission.WRITE_SECURE_SETTINGS"); @@ -259,28 +278,29 @@ status_t checkIMemory(const sp& iMemory) return NO_ERROR; } -sp MediaPackageManager::retreivePackageManager() { +void MediaPackageManager::loadPackageManager() { + if (mPackageManager != nullptr) { + return; + } const sp sm = defaultServiceManager(); if (sm == nullptr) { ALOGW("%s: failed to retrieve defaultServiceManager", __func__); - return nullptr; + return; } sp packageManager = sm->checkService(String16(nativePackageManagerName)); if (packageManager == nullptr) { ALOGW("%s: failed to retrieve native package manager", __func__); - return nullptr; + return; } - return interface_cast(packageManager); + mPackageManager = interface_cast(packageManager); } std::optional MediaPackageManager::doIsAllowed(uid_t uid) { + /** Can not fetch package manager at construction it may not yet be registered. */ + loadPackageManager(); if (mPackageManager == nullptr) { - /** Can not fetch package manager at construction it may not yet be registered. */ - mPackageManager = retreivePackageManager(); - if (mPackageManager == nullptr) { - ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__); - return std::nullopt; - } + ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__); + return std::nullopt; } std::vector packageNames; diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h index 212599a159..060e8499d4 100644 --- a/media/utils/include/mediautils/ServiceUtilities.h +++ b/media/utils/include/mediautils/ServiceUtilities.h @@ -93,6 +93,7 @@ bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid); bool dumpAllowed(); bool modifyPhoneStateAllowed(pid_t pid, uid_t uid); bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid); +bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid); status_t checkIMemory(const sp& iMemory); @@ -110,7 +111,7 @@ public: private: static constexpr const char* nativePackageManagerName = "package_native"; std::optional doIsAllowed(uid_t uid); - sp retreivePackageManager(); + void loadPackageManager(); sp mPackageManager; // To check apps manifest uint_t mPackageManagerErrors = 0; struct Package { diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 5c5c5bb28f..e5a6e27fad 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -326,7 +326,7 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di ret = AudioSystem::getOutputForAttr(&localAttr, &io, actualSessionId, &streamType, client.clientPid, client.clientUid, - &fullConfig, + client.packageName, &fullConfig, (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT), deviceId, &portId, &secondaryOutputs); @@ -766,8 +766,9 @@ sp AudioFlinger::createTrack(const CreateTrackInput& input, output.outputId = AUDIO_IO_HANDLE_NONE; output.selectedDeviceId = input.selectedDeviceId; lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType, - clientPid, clientUid, &input.config, input.flags, - &output.selectedDeviceId, &portId, &secondaryOutputs); + clientPid, clientUid, input.opPackageName, + &input.config, input.flags, &output.selectedDeviceId, + &portId, &secondaryOutputs); if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) { ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 6ef20352f0..2833525cad 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -8731,6 +8731,7 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client, &stream, client.clientPid, client.clientUid, + client.packageName, &config, flags, &deviceId, diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 4d071c89be..38801ec5b2 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -211,6 +211,7 @@ status_t AudioPolicyService::getOutputForAttr(audio_attributes_t *attr, audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, @@ -257,7 +258,8 @@ status_t AudioPolicyService::getOutputForAttr(audio_attributes_t *attr, case AudioPolicyInterface::API_OUTPUT_LEGACY: break; case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX: - if (!modifyPhoneStateAllowed(pid, uid)) { + if (!modifyPhoneStateAllowed(pid, uid) && + !accessCallAudioAllowed(opPackageName, pid, uid)) { ALOGE("%s() permission denied: modify phone state not allowed for uid %d", __func__, uid); result = PERMISSION_DENIED; @@ -454,15 +456,22 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, } bool canCaptureOutput = captureAudioOutputAllowed(pid, uid); - if ((inputSource == AUDIO_SOURCE_VOICE_UPLINK || - inputSource == AUDIO_SOURCE_VOICE_DOWNLINK || - inputSource == AUDIO_SOURCE_VOICE_CALL || - inputSource == AUDIO_SOURCE_ECHO_REFERENCE|| - inputSource == AUDIO_SOURCE_FM_TUNER) && + bool canCaptureTelephonyOutput = canCaptureOutput + || accessCallAudioAllowed(opPackageName, pid, uid); + + if ((attr->source == AUDIO_SOURCE_ECHO_REFERENCE || + attr->source == AUDIO_SOURCE_FM_TUNER) && !canCaptureOutput) { return PERMISSION_DENIED; } + if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK || + attr->source == AUDIO_SOURCE_VOICE_DOWNLINK || + attr->source == AUDIO_SOURCE_VOICE_CALL) && + !canCaptureTelephonyOutput) { + return PERMISSION_DENIED; + } + bool canCaptureHotword = captureHotwordAllowed(opPackageName, pid, uid); if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) { return BAD_VALUE; @@ -494,6 +503,11 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, break; case AudioPolicyInterface::API_INPUT_TELEPHONY_RX: // FIXME: use the same permission as for remote submix for now. + if (!canCaptureTelephonyOutput) { + ALOGE("getInputForAttr() permission denied: call capture not allowed"); + status = PERMISSION_DENIED; + } + break; case AudioPolicyInterface::API_INPUT_MIX_CAPTURE: if (!canCaptureOutput) { ALOGE("getInputForAttr() permission denied: capture not allowed"); @@ -521,9 +535,13 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, return status; } + bool allowAudioCapture = canCaptureOutput || + (inputType == AudioPolicyInterface::API_INPUT_TELEPHONY_RX && + canCaptureTelephonyOutput); + sp client = new AudioRecordClient(*attr, *input, uid, pid, session, *portId, *selectedDeviceId, opPackageName, - canCaptureOutput, canCaptureHotword); + allowAudioCapture, canCaptureHotword); mAudioRecordClients.add(*portId, client); } diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index e5c36eaf65..99cec5a0a5 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -534,8 +534,8 @@ void AudioPolicyService::updateUidStates_l() // OR client has CAPTURE_AUDIO_OUTPUT privileged permission bool allowCapture = !isAssistantOnTop && ((isTopOrLatestActive && !isLatestSensitive) || isLatestSensitive) - && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureOutput)) - && !(isInCall && !current->canCaptureOutput); + && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureCallOrOutput)) + && !(isInCall && !current->canCaptureCallOrOutput); if (isVirtualSource(source)) { // Allow capture for virtual (remote submix, call audio TX or RX...) sources @@ -555,7 +555,7 @@ void AudioPolicyService::updateUidStates_l() } else { if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) || source == AUDIO_SOURCE_HOTWORD) && - (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) { + (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) { allowCapture = true; } } @@ -567,7 +567,7 @@ void AudioPolicyService::updateUidStates_l() // OR // Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD if (!isAssistantOnTop - && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) { + && (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) { allowCapture = true; } if (isA11yOnTop) { @@ -580,7 +580,7 @@ void AudioPolicyService::updateUidStates_l() // All active clients are using HOTWORD source // AND no call is active // OR client has CAPTURE_AUDIO_OUTPUT privileged permission - if (onlyHotwordActive && !(isInCall && !current->canCaptureOutput)) { + if (onlyHotwordActive && !(isInCall && !current->canCaptureCallOrOutput)) { allowCapture = true; } } diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 41a0d2bd4e..c3c87f1576 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -82,6 +82,7 @@ public: audio_stream_type_t *stream, pid_t pid, uid_t uid, + const String16& opPackageName, const audio_config_t *config, audio_output_flags_t flags, audio_port_handle_t *selectedDeviceId, @@ -807,15 +808,16 @@ private: const audio_io_handle_t io, uid_t uid, pid_t pid, const audio_session_t session, audio_port_handle_t portId, const audio_port_handle_t deviceId, const String16& opPackageName, - bool canCaptureOutput, bool canCaptureHotword) : + bool canCaptureCallOrOutput, bool canCaptureHotword) : AudioClient(attributes, io, uid, pid, session, portId, deviceId), opPackageName(opPackageName), startTimeNs(0), - canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {} + canCaptureCallOrOutput(canCaptureCallOrOutput), + canCaptureHotword(canCaptureHotword) {} ~AudioRecordClient() override = default; const String16 opPackageName; // client package name nsecs_t startTimeNs; - const bool canCaptureOutput; + const bool canCaptureCallOrOutput; const bool canCaptureHotword; };