Loading services/audiopolicy/permission/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ cc_library { srcs: [ "NativePermissionController.cpp", "ValidatedAttributionSourceState.cpp", ], export_include_dirs: [ "include", Loading @@ -22,6 +23,7 @@ cc_library { ], static_libs: [ "audio-permission-aidl-cpp", "framework-permission-aidl-cpp", ], shared_libs: [ "libbase", Loading Loading @@ -94,6 +96,7 @@ cc_test { ], srcs: [ "tests/NativePermissionControllerTest.cpp", "tests/ValidatedAttributionSourceStateTest.cpp", ], test_options: { unit_test: true, Loading services/audiopolicy/permission/ValidatedAttributionSourceState.cpp 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <media/ValidatedAttributionSourceState.h> #include <binder/IPCThreadState.h> #include <error/expected_utils.h> #include <utils/Log.h> namespace com::android::media::permission { using ::android::base::unexpected; Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromBinderContext( AttributionSourceState attr, const IPermissionProvider& provider) { attr.pid = ::android::IPCThreadState::self()->getCallingPid(); attr.uid = ::android::IPCThreadState::self()->getCallingUid(); return createFromTrustedUidNoPackage(std::move(attr), provider); } Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromTrustedUidNoPackage( AttributionSourceState attr, const IPermissionProvider& provider) { if (attr.packageName.has_value() && attr.packageName->size() != 0) { if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) { return ValidatedAttributionSourceState{std::move(attr)}; } else { return unexpected{::android::PERMISSION_DENIED}; } } else { // For APIs which don't appropriately pass attribution sources or packages, we need // to populate the package name with our best guess. const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid)); LOG_ALWAYS_FATAL_IF(packageNames.empty()); attr.packageName = std::move(packageNames[0]); return ValidatedAttributionSourceState{std::move(attr)}; } } } // namespace com::android::media::permission services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/content/AttributionSourceState.h> #include <error/Result.h> #include "IPermissionProvider.h" namespace com::android::media::permission { using ::android::content::AttributionSourceState; using ::android::error::Result; class ValidatedAttributionSourceState { public: /** * Validates an attribution source from within the context of a binder transaction. * Overwrites the uid/pid and validates the packageName */ static Result<ValidatedAttributionSourceState> createFromBinderContext( AttributionSourceState attr, const IPermissionProvider& provider); /** * Creates a ValidatedAttributionSourceState in cases where the source is passed from a * trusted entity which already performed validation. */ static ValidatedAttributionSourceState createFromTrustedSource(AttributionSourceState attr) { return ValidatedAttributionSourceState(attr); } /** * Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the * packages have not been validated. Proper use of the previous two methods should avoid the * necessity of this, but it is useful for migration purposes as well as testing this class. */ static Result<ValidatedAttributionSourceState> createFromTrustedUidNoPackage( AttributionSourceState attr, const IPermissionProvider& provider); operator AttributionSourceState() const { return state_; } operator const AttributionSourceState&() const { return state_; } AttributionSourceState unwrapInto() && { return std::move(state_); } bool operator==(const ValidatedAttributionSourceState& other) const { return operator==(other.state_); } bool operator==(const AttributionSourceState& other) const { return state_ == other; } private: ValidatedAttributionSourceState(AttributionSourceState attr) : state_(attr) {} AttributionSourceState state_; }; } // namespace com::android::media::permission services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <media/ValidatedAttributionSourceState.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <android-base/expected.h> #include <media/IPermissionProvider.h> using ::android::base::unexpected; using ::android::binder::Status; using ::android::content::AttributionSourceState; using ::android::error::Result; using ::com::android::media::permission::IPermissionProvider; using ::com::android::media::permission::ValidatedAttributionSourceState; using ::testing::Return; class MockPermissionProvider : public IPermissionProvider { public: MOCK_METHOD(Result<std::vector<std::string>>, getPackagesForUid, (uid_t uid), (override, const)); MOCK_METHOD(Result<bool>, validateUidPackagePair, (uid_t uid, const std::string&), (override, const)); }; class ValidatedAttributionSourceStateTest : public ::testing::Test { protected: MockPermissionProvider mMockProvider; const uid_t mUid = 10001; const std::vector<std::string> mPackageList{"com.package1", "com.package2"}; }; #define UNWRAP_EQ(expr, desired_expr) \ do { \ auto tmp_ = (expr); \ EXPECT_TRUE(tmp_.has_value()); \ if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \ } while (0) TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) { const std::string package = "com.package1"; EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = package; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), attr); } TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) { const std::string package = "com.package.spoof"; EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(false)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = package; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::PERMISSION_DENIED); } TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList)); AttributionSourceState attr; attr.uid = mUid; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), expectedAttr); } TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), expectedAttr); } TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)) .WillOnce(Return(unexpected{::android::NO_INIT})); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::NO_INIT); } TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)) .WillOnce(Return(unexpected{::android::BAD_VALUE})); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::BAD_VALUE); } Loading
services/audiopolicy/permission/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ cc_library { srcs: [ "NativePermissionController.cpp", "ValidatedAttributionSourceState.cpp", ], export_include_dirs: [ "include", Loading @@ -22,6 +23,7 @@ cc_library { ], static_libs: [ "audio-permission-aidl-cpp", "framework-permission-aidl-cpp", ], shared_libs: [ "libbase", Loading Loading @@ -94,6 +96,7 @@ cc_test { ], srcs: [ "tests/NativePermissionControllerTest.cpp", "tests/ValidatedAttributionSourceStateTest.cpp", ], test_options: { unit_test: true, Loading
services/audiopolicy/permission/ValidatedAttributionSourceState.cpp 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <media/ValidatedAttributionSourceState.h> #include <binder/IPCThreadState.h> #include <error/expected_utils.h> #include <utils/Log.h> namespace com::android::media::permission { using ::android::base::unexpected; Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromBinderContext( AttributionSourceState attr, const IPermissionProvider& provider) { attr.pid = ::android::IPCThreadState::self()->getCallingPid(); attr.uid = ::android::IPCThreadState::self()->getCallingUid(); return createFromTrustedUidNoPackage(std::move(attr), provider); } Result<ValidatedAttributionSourceState> ValidatedAttributionSourceState::createFromTrustedUidNoPackage( AttributionSourceState attr, const IPermissionProvider& provider) { if (attr.packageName.has_value() && attr.packageName->size() != 0) { if (VALUE_OR_RETURN(provider.validateUidPackagePair(attr.uid, attr.packageName.value()))) { return ValidatedAttributionSourceState{std::move(attr)}; } else { return unexpected{::android::PERMISSION_DENIED}; } } else { // For APIs which don't appropriately pass attribution sources or packages, we need // to populate the package name with our best guess. const auto packageNames = VALUE_OR_RETURN(provider.getPackagesForUid(attr.uid)); LOG_ALWAYS_FATAL_IF(packageNames.empty()); attr.packageName = std::move(packageNames[0]); return ValidatedAttributionSourceState{std::move(attr)}; } } } // namespace com::android::media::permission
services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h 0 → 100644 +71 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/content/AttributionSourceState.h> #include <error/Result.h> #include "IPermissionProvider.h" namespace com::android::media::permission { using ::android::content::AttributionSourceState; using ::android::error::Result; class ValidatedAttributionSourceState { public: /** * Validates an attribution source from within the context of a binder transaction. * Overwrites the uid/pid and validates the packageName */ static Result<ValidatedAttributionSourceState> createFromBinderContext( AttributionSourceState attr, const IPermissionProvider& provider); /** * Creates a ValidatedAttributionSourceState in cases where the source is passed from a * trusted entity which already performed validation. */ static ValidatedAttributionSourceState createFromTrustedSource(AttributionSourceState attr) { return ValidatedAttributionSourceState(attr); } /** * Create a ValidatedAttribubtionSourceState in cases where the uid/pid is trusted, but the * packages have not been validated. Proper use of the previous two methods should avoid the * necessity of this, but it is useful for migration purposes as well as testing this class. */ static Result<ValidatedAttributionSourceState> createFromTrustedUidNoPackage( AttributionSourceState attr, const IPermissionProvider& provider); operator AttributionSourceState() const { return state_; } operator const AttributionSourceState&() const { return state_; } AttributionSourceState unwrapInto() && { return std::move(state_); } bool operator==(const ValidatedAttributionSourceState& other) const { return operator==(other.state_); } bool operator==(const AttributionSourceState& other) const { return state_ == other; } private: ValidatedAttributionSourceState(AttributionSourceState attr) : state_(attr) {} AttributionSourceState state_; }; } // namespace com::android::media::permission
services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <media/ValidatedAttributionSourceState.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <android-base/expected.h> #include <media/IPermissionProvider.h> using ::android::base::unexpected; using ::android::binder::Status; using ::android::content::AttributionSourceState; using ::android::error::Result; using ::com::android::media::permission::IPermissionProvider; using ::com::android::media::permission::ValidatedAttributionSourceState; using ::testing::Return; class MockPermissionProvider : public IPermissionProvider { public: MOCK_METHOD(Result<std::vector<std::string>>, getPackagesForUid, (uid_t uid), (override, const)); MOCK_METHOD(Result<bool>, validateUidPackagePair, (uid_t uid, const std::string&), (override, const)); }; class ValidatedAttributionSourceStateTest : public ::testing::Test { protected: MockPermissionProvider mMockProvider; const uid_t mUid = 10001; const std::vector<std::string> mPackageList{"com.package1", "com.package2"}; }; #define UNWRAP_EQ(expr, desired_expr) \ do { \ auto tmp_ = (expr); \ EXPECT_TRUE(tmp_.has_value()); \ if (tmp_.has_value()) EXPECT_EQ(*tmp_, desired_expr); \ } while (0) TEST_F(ValidatedAttributionSourceStateTest, providedPackageValid) { const std::string package = "com.package1"; EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(true)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = package; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), attr); } TEST_F(ValidatedAttributionSourceStateTest, providedPackageInvalid) { const std::string package = "com.package.spoof"; EXPECT_CALL(mMockProvider, validateUidPackagePair(mUid, package)).WillOnce(Return(false)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = package; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::PERMISSION_DENIED); } TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenMissingPackage) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList)); AttributionSourceState attr; attr.uid = mUid; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), expectedAttr); } TEST_F(ValidatedAttributionSourceStateTest, packageLookup_whenEmptyPackage) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)).WillOnce(Return(mPackageList)); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; UNWRAP_EQ(ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider), expectedAttr); } TEST_F(ValidatedAttributionSourceStateTest, controllerNotInitialized) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)) .WillOnce(Return(unexpected{::android::NO_INIT})); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; AttributionSourceState expectedAttr; expectedAttr.uid = mUid; expectedAttr.packageName = "com.package1"; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::NO_INIT); } TEST_F(ValidatedAttributionSourceStateTest, uidNotFound) { EXPECT_CALL(mMockProvider, getPackagesForUid(mUid)) .WillOnce(Return(unexpected{::android::BAD_VALUE})); AttributionSourceState attr; attr.uid = mUid; attr.packageName = std::string{}; const auto res = ValidatedAttributionSourceState::createFromTrustedUidNoPackage(attr, mMockProvider); ASSERT_FALSE(res.has_value()); EXPECT_EQ(res.error(), ::android::BAD_VALUE); }