Combine getInputForAttr perm checks
Push all permission checks to a single function, which is called in
the middle of the APM function after the mix (and virtualdeviceid) is
selected.
This ensures that we don't incorrectly check perms for default vdi.
To enable this, add a method in the AudioPolicyClient which
evaluates perms for a particular input request to keep the perm checks
out of APM.
Test: CtsMediaAudioTestCases
Bug: 374870131
Fixes: 343523722
Flag: EXEMPT infeasible bugfix
Change-Id: I0f83d26fb7ad3b08a5a89d3ee58701315a91ae6d
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 88bced6..e299007 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2935,8 +2935,7 @@
audio_input_flags_t flags,
audio_unique_id_t riid,
audio_session_t session,
- const AttributionSourceState& attributionSource,
- input_type_t *inputType)
+ const AttributionSourceState& attributionSource)
{
ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
"flags %#x attributes=%s requested device ID %d",
@@ -2957,6 +2956,17 @@
attributes.source = AUDIO_SOURCE_MIC;
}
+ using PermissionReqs = AudioPolicyClientInterface::PermissionReqs;
+ using MixType = AudioPolicyClientInterface::MixType;
+ PermissionReqs permReq {
+ .source = legacy2aidl_audio_source_t_AudioSource(attributes.source).value(),
+ .mixType = MixType::NONE, // can be modified
+ .virtualDeviceId = 0, // can be modified
+ .isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
+ AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0,
+ .isCallRedir = (attributes.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0,
+ };
+
// Explicit routing?
sp<DeviceDescriptor> explicitRoutingDevice =
mAvailableInputDevices.getDeviceFromId(requestedDeviceId);
@@ -3000,13 +3010,9 @@
}
}
}
- *inputType = API_INPUT_LEGACY;
device = inputDesc->getDevice();
ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
- // TODO perm check
} else {
- *inputType = API_INPUT_INVALID;
-
if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
extractAddressFromAudioAttributes(attributes).has_value()) {
status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3027,12 +3033,12 @@
}
if (is_mix_loopback_render(policyMix->mRouteFlags)) {
- *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
+ permReq.mixType = MixType::PUBLIC_CAPTURE_PLAYBACK;
} else {
- *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+ permReq.mixType = MixType::EXT_POLICY_REROUTE;
}
// TODO is this correct?
- vdi = policyMix->mVirtualDeviceId;
+ permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
} else {
if (explicitRoutingDevice != nullptr) {
device = explicitRoutingDevice;
@@ -3050,24 +3056,35 @@
attributes.source))};
}
if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
- *inputType = API_INPUT_MIX_CAPTURE;
+ permReq.mixType = MixType::CAPTURE;
} else if (policyMix) {
ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
// there is an external policy, but this input is attached to a mix of recorders,
// meaning it receives audio injected into the framework, so the recorder doesn't
// know about it and is therefore considered "legacy"
- *inputType = API_INPUT_LEGACY;
- vdi = policyMix->mVirtualDeviceId;
+ permReq.mixType = MixType::NONE;
+ permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
} else if (audio_is_remote_submix_device(device->type())) {
- *inputType = API_INPUT_MIX_CAPTURE;
+ permReq.mixType = MixType::CAPTURE;
} else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
- *inputType = API_INPUT_TELEPHONY_RX;
+ permReq.mixType = MixType::TELEPHONY_RX_CAPTURE;
} else {
- *inputType = API_INPUT_LEGACY;
+ permReq.mixType = MixType::NONE;
}
}
- // TODO perm check
+ auto permRes = mpClientInterface->checkPermissionForInput(attributionSource, permReq);
+ if (!permRes.has_value()) return base::unexpected {permRes.error()};
+ if (!permRes.value()) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_SECURITY, String8::format("%s: %s missing perms for source %d mix %d vdi %d"
+ "hotword? %d callredir? %d", __func__, attributionSource.toString().c_str(),
+ static_cast<int>(permReq.source),
+ static_cast<int>(permReq.mixType),
+ permReq.virtualDeviceId,
+ permReq.isHotword,
+ permReq.isCallRedir))};
+ }
input = getInputForDevice(device, session, attributes, config, flags, policyMix);
if (input == AUDIO_IO_HANDLE_NONE) {
@@ -3108,14 +3125,14 @@
mEffects.moveEffectsForIo(session, input, &mInputs, mpClientInterface);
inputDesc->addClient(clientDesc);
- ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
- input, *inputType, selectedDeviceId, allocatedPortId);
+ ALOGV("getInputForAttr() returns input %d selectedDeviceId %d vdi %d for port ID %d",
+ input, selectedDeviceId, permReq.virtualDeviceId, allocatedPortId);
auto ret = media::GetInputForAttrResponse {};
ret.input = input;
ret.selectedDeviceId = selectedDeviceId;
ret.portId = allocatedPortId;
- ret.virtualDeviceId = vdi;
+ ret.virtualDeviceId = permReq.virtualDeviceId;
ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
return ret;
}