Merge "audio policy: fix playback permission checks"

gugelfrei
Eric Laurent 5 years ago committed by Android (Google) Code Review
commit a24e36ccd5

@ -167,9 +167,16 @@ bool settingsAllowed() {
}
bool modifyAudioRoutingAllowed() {
return modifyAudioRoutingAllowed(
IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
}
bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) {
if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sModifyAudioRouting);
if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
bool ok = PermissionCache::checkPermission(sModifyAudioRouting, pid, uid);
if (!ok) ALOGE("%s(): android.permission.MODIFY_AUDIO_ROUTING denied for uid %d",
__func__, uid);
return ok;
}

@ -85,6 +85,7 @@ bool captureMediaOutputAllowed(pid_t pid, uid_t uid);
bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid);
bool modifyDefaultAudioEffectsAllowed();
bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);

@ -69,6 +69,14 @@ public:
API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
} input_type_t;
typedef enum {
API_OUTPUT_INVALID = -1,
API_OUTPUT_LEGACY = 0,// e.g. audio playing to speaker
API_OUT_MIX_PLAYBACK, // used for "remote submix" playback of audio from remote source
// to local capture
API_OUTPUT_TELEPHONY_TX, // used for playback to telephony TX path
} output_type_t;
public:
virtual ~AudioPolicyInterface() {}
//
@ -115,7 +123,8 @@ public:
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
std::vector<audio_io_handle_t> *secondaryOutputs) = 0;
std::vector<audio_io_handle_t> *secondaryOutputs,
output_type_t *outputType) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding stream.
virtual status_t startOutput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the output stops being used by corresponding stream.

@ -945,7 +945,8 @@ status_t AudioPolicyManager::getOutputForAttrInt(
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
output_type_t *outputType)
{
DeviceVector outputDevices;
const audio_port_handle_t requestedPortId = *selectedDeviceId;
@ -953,6 +954,7 @@ status_t AudioPolicyManager::getOutputForAttrInt(
const sp<DeviceDescriptor> requestedDevice =
mAvailableOutputDevices.getDeviceFromId(requestedPortId);
*outputType = API_OUTPUT_INVALID;
status_t status = getAudioAttributes(resultAttr, attr, *stream);
if (status != NO_ERROR) {
return status;
@ -991,7 +993,13 @@ status_t AudioPolicyManager::getOutputForAttrInt(
mix->mDeviceAddress,
AUDIO_FORMAT_DEFAULT);
*selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
ALOGV("getOutputForAttr() returns output %d", *output);
if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
*outputType = API_OUT_MIX_PLAYBACK;
} else {
*outputType = API_OUTPUT_LEGACY;
}
return NO_ERROR;
}
// Virtual sources must always be dynamicaly or explicitly routed
@ -1048,6 +1056,12 @@ status_t AudioPolicyManager::getOutputForAttrInt(
*selectedDeviceId = getFirstDeviceId(outputDevices);
if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
*outputType = API_OUTPUT_TELEPHONY_TX;
} else {
*outputType = API_OUTPUT_LEGACY;
}
ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId);
return NO_ERROR;
@ -1062,7 +1076,8 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
std::vector<audio_io_handle_t> *secondaryOutputs)
std::vector<audio_io_handle_t> *secondaryOutputs,
output_type_t *outputType)
{
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
if (*portId != AUDIO_PORT_HANDLE_NONE) {
@ -1082,7 +1097,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputDescs);
&secondaryOutputDescs, outputType);
if (status != NO_ERROR) {
return status;
}
@ -3909,10 +3924,11 @@ status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
bool isRequestedDeviceForExclusiveUse = false;
std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
output_type_t outputType;
getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
&attributes, &stream, sourceDesc->uid(), &config, &flags,
&selectedDeviceId, &isRequestedDeviceForExclusiveUse,
&secondaryOutputs);
&secondaryOutputs, &outputType);
if (output == AUDIO_IO_HANDLE_NONE) {
ALOGV("%s no output for device %s",
__FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());

@ -121,7 +121,8 @@ public:
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId,
std::vector<audio_io_handle_t> *secondaryOutputs) override;
std::vector<audio_io_handle_t> *secondaryOutputs,
output_type_t *outputType) override;
virtual status_t startOutput(audio_port_handle_t portId);
virtual status_t stopOutput(audio_port_handle_t portId);
virtual void releaseOutput(audio_port_handle_t portId);
@ -809,7 +810,8 @@ private:
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
bool *isRequestedDeviceForExclusiveUse,
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
output_type_t *outputType);
// internal method to return the output handle for the given device and format
audio_io_handle_t getOutputForDevices(
const DeviceVector &devices,

@ -181,13 +181,13 @@ status_t AudioPolicyService::getOutputForAttr(audio_attributes_t *attr,
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
ALOGV("getOutputForAttr()");
ALOGV("%s()", __func__);
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
"%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
uid = callingUid;
}
if (!mPackageManager.allowPlaybackCapture(uid)) {
@ -197,27 +197,39 @@ status_t AudioPolicyService::getOutputForAttr(audio_attributes_t *attr,
&& !bypassInterruptionPolicyAllowed(pid, uid)) {
attr->flags &= ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE);
}
audio_output_flags_t originalFlags = flags;
AutoCallerClear acc;
AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
config,
&flags, selectedDeviceId, portId,
secondaryOutputs);
secondaryOutputs,
&outputType);
// FIXME: Introduce a way to check for the the telephony device before opening the output
if ((result == NO_ERROR) &&
(flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) &&
!modifyPhoneStateAllowed(pid, uid)) {
// If the app tries to play music through the telephony device and doesn't have permission
// the fallback to the default output device.
mAudioPolicyManager->releaseOutput(*portId);
flags = originalFlags;
*selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
*portId = AUDIO_PORT_HANDLE_NONE;
secondaryOutputs->clear();
result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
&flags, selectedDeviceId, portId,
secondaryOutputs);
if (result == NO_ERROR) {
// enforce permission (if any) required for each type of input
switch (outputType) {
case AudioPolicyInterface::API_OUTPUT_LEGACY:
break;
case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
if (!modifyPhoneStateAllowed(pid, uid)) {
ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
__func__, uid);
result = PERMISSION_DENIED;
}
break;
case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
if (!modifyAudioRoutingAllowed(pid, uid)) {
ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
__func__, uid);
result = PERMISSION_DENIED;
}
break;
case AudioPolicyInterface::API_OUTPUT_INVALID:
default:
LOG_ALWAYS_FATAL("%s() encountered an invalid output type %d",
__func__, (int)outputType);
}
}
if (result == NO_ERROR) {
@ -434,7 +446,7 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
}
break;
case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
if (!modifyAudioRoutingAllowed()) {
if (!modifyAudioRoutingAllowed(pid, uid)) {
ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
status = PERMISSION_DENIED;
}

@ -179,9 +179,10 @@ void AudioPolicyManagerTest::getOutputForAttr(
audio_port_handle_t localPortId;
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::output_type_t outputType;
ASSERT_EQ(OK, mManager->getOutputForAttr(
&attr, output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
selectedDeviceId, portId, {}));
selectedDeviceId, portId, {}, &outputType));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
}

Loading…
Cancel
Save