Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 136f638e authored by Mohammed Althaf T's avatar Mohammed Althaf T 😊
Browse files

Merge branch '3571-a14-sept' into 'v3.1-a14'

[a14] Add September security patches

See merge request !8
parents 0327eca4 5730d9b2
Loading
Loading
Loading
Loading
Loading
+105 −38
Original line number Diff line number Diff line
@@ -40,6 +40,11 @@

namespace android {

namespace {
constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
}

using content::AttributionSourceState;

static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
@@ -71,19 +76,33 @@ static String16 resolveCallingPackage(PermissionController& permissionController

int32_t getOpForSource(audio_source_t source) {
  switch (source) {
    case AUDIO_SOURCE_HOTWORD:
      return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
    case AUDIO_SOURCE_FM_TUNER:
        return AppOpsManager::OP_NONE;
    case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
    case AUDIO_SOURCE_REMOTE_SUBMIX:
      return AppOpsManager::OP_RECORD_AUDIO_OUTPUT;
    case AUDIO_SOURCE_VOICE_DOWNLINK:
      return AppOpsManager::OP_RECORD_INCOMING_PHONE_AUDIO;
    case AUDIO_SOURCE_HOTWORD:
      return AppOpsManager::OP_RECORD_AUDIO_HOTWORD;
    case AUDIO_SOURCE_DEFAULT:
    default:
      return AppOpsManager::OP_RECORD_AUDIO;
  }
}

bool isRecordOpRequired(audio_source_t source) {
  switch (source) {
    case AUDIO_SOURCE_FM_TUNER:
    case AUDIO_SOURCE_ECHO_REFERENCE: // fallthrough
    case AUDIO_SOURCE_REMOTE_SUBMIX:
    case AUDIO_SOURCE_VOICE_DOWNLINK:
        return false;
    default:
      return true;
  }
}

std::optional<AttributionSourceState> resolveAttributionSource(
        const AttributionSourceState& callerAttributionSource) {
    AttributionSourceState nextAttributionSource = callerAttributionSource;
@@ -113,7 +132,7 @@ std::optional<AttributionSourceState> resolveAttributionSource(
    return std::optional<AttributionSourceState>{myAttributionSource};
}

static bool checkRecordingInternal(const AttributionSourceState& attributionSource,
static int checkRecordingInternal(const AttributionSourceState& attributionSource,
        const String16& msg, bool start, audio_source_t source) {
    // Okay to not track in app ops as audio server or media server is us and if
    // device is rooted security model is considered compromised.
@@ -121,39 +140,74 @@ static bool checkRecordingInternal(const AttributionSourceState& attributionSour
    // user is active, but it is a core system service so let it through.
    // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
    if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true;
    if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return PERMISSION_GRANTED;

    const int32_t attributedOpCode = getOpForSource(source);
    if (isRecordOpRequired(source)) {
        // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
        // may open a record track on behalf of a client. Note that pid may be a tid.
        // IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
    const std::optional<AttributionSourceState> resolvedAttributionSource =
        std::optional<AttributionSourceState> resolvedAttributionSource =
                resolveAttributionSource(attributionSource);
        if (!resolvedAttributionSource.has_value()) {
        return false;
            return PERMISSION_HARD_DENIED;
        }

    const int32_t attributedOpCode = getOpForSource(source);

        permission::PermissionChecker permissionChecker;
    bool permitted = false;
        int permitted;
        if (start) {
        permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
            // Do a double-check, where we first check without actually starting in order to handle
            // the behavior of AppOps where ops are sometimes started but paused for SOFT_DENIED.
            // Since there is no way to maintain reference consensus due to this behavior, avoid
            // starting an op when a restriction is in place by first checking. In the case where we
            // startOp would fail, call a noteOp (which will also fail) instead. This preserves
            // behavior that is reliant on listening to op rejected events (such as the hint
            // dialogue to unmute the microphone). Technically racy, but very unlikely.
            //
            // TODO(b/294609684) To be removed when the pause state for an OP is removed.
            permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
                    sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
                    attributedOpCode);
            if (permitted == PERMISSION_GRANTED) {
                permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
                        sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
                        attributedOpCode);
            } else {
        permitted = (permissionChecker.checkPermissionForPreflightFromDatasource(
                // intentionally don't set permitted
                permissionChecker.checkPermissionForDataDeliveryFromDatasource(
                            sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
                attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
                            attributedOpCode);
            }
        } else {
            permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
                    sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
                    attributedOpCode);
        }

        return permitted;
    } else {
        if (attributedOpCode == AppOpsManager::OP_NONE) return PERMISSION_GRANTED;  // nothing to do
        AppOpsManager ap{};
        PermissionController pc{};
        return ap.startOpNoThrow(
                attributedOpCode, attributionSource.uid,
                resolveCallingPackage(pc,
                                      String16{attributionSource.packageName.value_or("").c_str()},
                                      attributionSource.uid),
                false,
                attributionSource.attributionTag.has_value()
                        ? String16{attributionSource.attributionTag.value().c_str()}
                        : String16{},
                msg);
    }
}

bool recordingAllowed(const AttributionSourceState& attributionSource, audio_source_t source) {
    return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source);
    return checkRecordingInternal(attributionSource, String16(), /*start*/ false, source) !=
            PERMISSION_HARD_DENIED;
}

bool startRecording(const AttributionSourceState& attributionSource, const String16& msg,
int startRecording(const AttributionSourceState& attributionSource, const String16& msg,
        audio_source_t source) {
    return checkRecordingInternal(attributionSource, msg, /*start*/ true, source);
}
@@ -164,6 +218,8 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour
    uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
    if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return;

    const int32_t attributedOpCode = getOpForSource(source);
    if (isRecordOpRequired(source)) {
        // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
        // may open a record track on behalf of a client. Note that pid may be a tid.
        // IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
@@ -173,10 +229,21 @@ void finishRecording(const AttributionSourceState& attributionSource, audio_sour
            return;
        }

    const int32_t attributedOpCode = getOpForSource(source);
        permission::PermissionChecker permissionChecker;
        permissionChecker.finishDataDeliveryFromDatasource(attributedOpCode,
                resolvedAttributionSource.value());
    } else {
        if (attributedOpCode == AppOpsManager::OP_NONE) return;  // nothing to do
        AppOpsManager ap{};
        PermissionController pc{};
        ap.finishOp(attributedOpCode, attributionSource.uid,
                    resolveCallingPackage(
                            pc, String16{attributionSource.packageName.value_or("").c_str()},
                            attributionSource.uid),
                    attributionSource.attributionTag.has_value()
                            ? String16{attributionSource.attributionTag.value().c_str()}
                            : String16{});
    }
}

bool captureAudioOutputAllowed(const AttributionSourceState& attributionSource) {
+3 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ static inline bool isAudioServerOrMediaServerUid(uid_t uid) {

bool recordingAllowed(const AttributionSourceState& attributionSource,
        audio_source_t source = AUDIO_SOURCE_DEFAULT);
bool startRecording(const AttributionSourceState& attributionSource,
int startRecording(const AttributionSourceState& attributionSource,
    const String16& msg, audio_source_t source);
void finishRecording(const AttributionSourceState& attributionSource, audio_source_t source);
std::optional<AttributionSourceState> resolveAttributionSource(
@@ -114,6 +114,8 @@ void anonymizeBluetoothAddress(char *address);

int32_t getOpForSource(audio_source_t source);

bool isRecordOpRequired(audio_source_t source);

AttributionSourceState getCallingAttributionSource();

status_t checkIMemory(const sp<IMemory>& iMemory);
+25 −13
Original line number Diff line number Diff line
@@ -62,6 +62,11 @@ using media::audio::common::AudioUsage;
using media::audio::common::AudioUuid;
using media::audio::common::Int;

namespace {
constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
}

const std::vector<audio_usage_t>& SYSTEM_USAGES = {
    AUDIO_USAGE_CALL_ASSISTANT,
    AUDIO_USAGE_EMERGENCY,
@@ -807,13 +812,12 @@ Status AudioPolicyService::startInput(int32_t portIdAidl)
    std::stringstream msg;
    msg << "Audio recording on session " << client->session;

    const auto permitted = startRecording(client->attributionSource, String16(msg.str().c_str()),
            client->attributes.source);

    // check calling permissions
    if (!isAudioServerOrMediaServerUid(client->attributionSource.uid)
            && !(startRecording(client->attributionSource, String16(msg.str().c_str()),
                         client->attributes.source)
            || client->attributes.source == AUDIO_SOURCE_FM_TUNER
            || client->attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX
            || client->attributes.source == AUDIO_SOURCE_ECHO_REFERENCE)) {
            && permitted == PERMISSION_HARD_DENIED) {
        ALOGE("%s permission denied: recording not allowed for attribution source %s",
                __func__, client->attributionSource.toString().c_str());
        return binderStatusFromStatusT(PERMISSION_DENIED);
@@ -832,13 +836,17 @@ Status AudioPolicyService::startInput(int32_t portIdAidl)
        return binderStatusFromStatusT(INVALID_OPERATION);
    }

    // Force the possibly silenced client to be unsilenced since we just called
    // startRecording (i.e. we have assumed it is unsilenced).
    // At this point in time, the client is inactive, so no calls to appops are sent in
    // setAppState_l.
    // This ensures existing clients have the same behavior as new clients (starting unsilenced).
    // Force the possibly silenced client to match the state on the appops side
    // following the call to startRecording (i.e. unsilenced iff call succeeded)
    // At this point in time, the client is inactive, so no calls to appops are
    // sent in setAppState_l. This ensures existing clients have the same
    // behavior as new clients.
    // TODO(b/282076713)
    if (permitted == PERMISSION_GRANTED) {
        setAppState_l(client, APP_STATE_TOP);
    } else {
        setAppState_l(client, APP_STATE_IDLE);
    }

    client->active = true;
    client->startTimeNs = systemTime();
@@ -924,8 +932,10 @@ Status AudioPolicyService::startInput(int32_t portIdAidl)
        client->active = false;
        client->startTimeNs = 0;
        updateUidStates_l();
        if (!client->silenced) {
            finishRecording(client->attributionSource, client->attributes.source);
        }
    }

    return binderStatusFromStatusT(status);
}
@@ -953,7 +963,9 @@ Status AudioPolicyService::stopInput(int32_t portIdAidl)
    updateUidStates_l();

    // finish the recording app op
    if (!client->silenced) {
        finishRecording(client->attributionSource, client->attributes.source);
    }
    AutoCallerClear acc;
    return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
}
+7 −3
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@ static const nsecs_t kAudioCommandTimeoutNs = seconds(3); // 3 seconds

static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");

namespace {
constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
}

// Creates an association between Binder code to name for IAudioPolicyService.
#define IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST \
BINDER_METHOD_ENTRY(onNewAudioModulesAvailable) \
@@ -1196,9 +1200,9 @@ void AudioPolicyService::setAppState_l(sp<AudioRecordClient> client, app_state_t
                } else {
                    std::stringstream msg;
                    msg << "Audio recording un-silenced on session " << client->session;
                    if (!startRecording(client->attributionSource, String16(msg.str().c_str()),
                            client->attributes.source)) {
                        silenced = true;
                    if (startRecording(client->attributionSource, String16(msg.str().c_str()),
                                client->attributes.source) != PERMISSION_GRANTED) {
                        return;
                    }
                }
            }
+90 −30
Original line number Diff line number Diff line
@@ -18,14 +18,17 @@

#include "AudioRecordClient.h"
#include "AudioPolicyService.h"
#include "binder/AppOpsManager.h"
#include "mediautils/ServiceUtilities.h"

#include <algorithm>

namespace android::media::audiopolicy {

using android::AudioPolicyService;

namespace {
bool isAppOpSource(audio_source_t source)
{
bool isAppOpSource(audio_source_t source) {
    switch (source) {
        case AUDIO_SOURCE_FM_TUNER:
        case AUDIO_SOURCE_ECHO_REFERENCE:
@@ -45,7 +48,7 @@ int getTargetSdkForPackageName(std::string_view packageName) {
        if (pm != nullptr) {
            const auto status = pm->getTargetSdkVersionForPackage(
                    String16{packageName.data(), packageName.size()}, &targetSdk);
            return status.isOk() ? targetSdk : -1;
            return status.isOk() ? targetSdk : __ANDROID_API_FUTURE__;
        }
    }
    return targetSdk;
@@ -54,8 +57,47 @@ int getTargetSdkForPackageName(std::string_view packageName) {
bool doesPackageTargetAtLeastU(std::string_view packageName) {
    return getTargetSdkForPackageName(packageName) >= __ANDROID_API_U__;
}

class AttrSourceItr {
  public:
    using iterator_category = std::forward_iterator_tag;
    using difference_type = std::ptrdiff_t;
    using value_type = AttributionSourceState;
    using pointer = const value_type*;
    using reference = const value_type&;

    AttrSourceItr() : mAttr(nullptr) {}

    AttrSourceItr(const AttributionSourceState& attr) : mAttr(&attr) {}

    reference operator*() const { return *mAttr; }
    pointer operator->() const { return mAttr; }

    AttrSourceItr& operator++() {
        mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
        return *this;
    }

    AttrSourceItr operator++(int) {
        AttrSourceItr tmp = *this;
        ++(*this);
        return tmp;
    }

    friend bool operator==(const AttrSourceItr& a, const AttrSourceItr& b) {
        return a.mAttr == b.mAttr;
    }

    friend bool operator!=(const AttrSourceItr& a, const AttrSourceItr& b) {
        return !operator==(a, b);
    }

    static AttrSourceItr end() { return AttrSourceItr{}; }
private:
    const AttributionSourceState * mAttr;
};
} // anonymous

// static
sp<OpRecordAudioMonitor>
OpRecordAudioMonitor::createIfNeeded(
@@ -78,16 +120,19 @@ OpRecordAudioMonitor::createIfNeeded(
            || attributionSource.packageName.value().size() == 0) {
        return nullptr;
    }
    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source), commandThread);
    return new OpRecordAudioMonitor(attributionSource, getOpForSource(attr.source),
                                    isRecordOpRequired(attr.source),
                                    commandThread);
}

OpRecordAudioMonitor::OpRecordAudioMonitor(
        const AttributionSourceState& attributionSource, int32_t appOp,
        wp<AudioPolicyService::AudioCommandThread> commandThread) :
            mHasOp(true), mAttributionSource(attributionSource), mAppOp(appOp),
            mCommandThread(commandThread)
{
}
OpRecordAudioMonitor::OpRecordAudioMonitor(const AttributionSourceState& attributionSource,
                                           int32_t appOp, bool shouldMonitorRecord,
                                           wp<AudioPolicyService::AudioCommandThread> commandThread)
    : mHasOp(true),
      mAttributionSource(attributionSource),
      mAppOp(appOp),
      mShouldMonitorRecord(shouldMonitorRecord),
      mCommandThread(commandThread) {}

OpRecordAudioMonitor::~OpRecordAudioMonitor()
{
@@ -103,15 +148,24 @@ void OpRecordAudioMonitor::onFirstRef()
    mOpCallback = new RecordAudioOpCallback(this);
    ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());

    int flags = doesPackageTargetAtLeastU(
            mAttributionSource.packageName.value_or("")) ?
            AppOpsManager::WATCH_FOREGROUND_CHANGES : 0;
    // TODO: We need to always watch AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    mAppOpsManager.startWatchingMode(mAppOp, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
        mAttributionSource.packageName.value_or(""))),
        flags,
        mOpCallback);
    int flags = doesPackageTargetAtLeastU(mAttributionSource.packageName.value_or(""))
                        ? AppOpsManager::WATCH_FOREGROUND_CHANGES
                        : 0;

    const auto reg = [&](int32_t op) {
        std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(),
                      [&](const auto& attr) {
                          mAppOpsManager.startWatchingMode(
                                  op,
                                  VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                                          attr.packageName.value_or(""))),
                                  flags, mOpCallback);
                      });
    };
    reg(mAppOp);
    if (mAppOp != AppOpsManager::OP_RECORD_AUDIO && mShouldMonitorRecord) {
        reg(AppOpsManager::OP_RECORD_AUDIO);
    }
}

bool OpRecordAudioMonitor::hasOp() const {
@@ -124,14 +178,20 @@ bool OpRecordAudioMonitor::hasOp() const {
// due to the UID in createIfNeeded(). As a result for those record track, it's:
// - not called from constructor,
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void OpRecordAudioMonitor::checkOp(bool updateUidStates)
{
    // TODO: We need to always check AppOpsManager::OP_RECORD_AUDIO too
    // since it controls the mic permission for legacy apps.
    const int32_t mode = mAppOpsManager.checkOp(mAppOp,
            mAttributionSource.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                mAttributionSource.packageName.value_or(""))));
    const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
void OpRecordAudioMonitor::checkOp(bool updateUidStates) {
    const auto check = [&](int32_t op) -> bool {
        return std::all_of(
                AttrSourceItr{mAttributionSource}, AttrSourceItr::end(), [&](const auto& x) {
                    return mAppOpsManager.checkOp(op, x.uid,
                                                  VALUE_OR_FATAL(aidl2legacy_string_view_String16(
                                                          x.packageName.value_or("")))) ==
                           AppOpsManager::MODE_ALLOWED;
                });
    };
    bool hasIt = check(mAppOp);
    if (mAppOp != AppOpsManager::OP_RECORD_AUDIO && mShouldMonitorRecord) {
        hasIt = hasIt && check(AppOpsManager::OP_RECORD_AUDIO);
    }
    // verbose logging only log when appOp changed
    ALOGI_IF(hasIt != mHasOp.load(),
            "App op %d missing, %ssilencing record %s",
@@ -161,4 +221,4 @@ void OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
    }
}

} // android::media::audiopolicy::internal
}  // namespace android::media::audiopolicy
Loading