1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #include <media/NativePermissionController.h>
18*ec779b8eSAndroid Build Coastguard Worker
19*ec779b8eSAndroid Build Coastguard Worker #include <algorithm>
20*ec779b8eSAndroid Build Coastguard Worker #include <optional>
21*ec779b8eSAndroid Build Coastguard Worker #include <utility>
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker #include <android-base/expected.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <cutils/android_filesystem_config.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <utils/Errors.h>
26*ec779b8eSAndroid Build Coastguard Worker
27*ec779b8eSAndroid Build Coastguard Worker using ::android::binder::Status;
28*ec779b8eSAndroid Build Coastguard Worker using ::android::error::BinderResult;
29*ec779b8eSAndroid Build Coastguard Worker using ::android::error::unexpectedExceptionCode;
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker namespace com::android::media::permission {
getFixedPackageName(uid_t uid)32*ec779b8eSAndroid Build Coastguard Worker static std::optional<std::string> getFixedPackageName(uid_t uid) {
33*ec779b8eSAndroid Build Coastguard Worker // These values are in sync with AppOpsService
34*ec779b8eSAndroid Build Coastguard Worker switch (uid % AID_USER_OFFSET) {
35*ec779b8eSAndroid Build Coastguard Worker case AID_ROOT:
36*ec779b8eSAndroid Build Coastguard Worker return "root";
37*ec779b8eSAndroid Build Coastguard Worker case AID_SYSTEM:
38*ec779b8eSAndroid Build Coastguard Worker return "system";
39*ec779b8eSAndroid Build Coastguard Worker case AID_SHELL:
40*ec779b8eSAndroid Build Coastguard Worker return "shell";
41*ec779b8eSAndroid Build Coastguard Worker case AID_MEDIA:
42*ec779b8eSAndroid Build Coastguard Worker return "media";
43*ec779b8eSAndroid Build Coastguard Worker case AID_AUDIOSERVER:
44*ec779b8eSAndroid Build Coastguard Worker return "audioserver";
45*ec779b8eSAndroid Build Coastguard Worker case AID_CAMERASERVER:
46*ec779b8eSAndroid Build Coastguard Worker return "cameraserver";
47*ec779b8eSAndroid Build Coastguard Worker default:
48*ec779b8eSAndroid Build Coastguard Worker return std::nullopt;
49*ec779b8eSAndroid Build Coastguard Worker }
50*ec779b8eSAndroid Build Coastguard Worker }
51*ec779b8eSAndroid Build Coastguard Worker
52*ec779b8eSAndroid Build Coastguard Worker // -- Begin Binder methods
populatePackagesForUids(const std::vector<UidPackageState> & initialPackageStates)53*ec779b8eSAndroid Build Coastguard Worker Status NativePermissionController::populatePackagesForUids(
54*ec779b8eSAndroid Build Coastguard Worker const std::vector<UidPackageState>& initialPackageStates) {
55*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
56*ec779b8eSAndroid Build Coastguard Worker if (!is_package_populated_) is_package_populated_ = true;
57*ec779b8eSAndroid Build Coastguard Worker package_map_.clear();
58*ec779b8eSAndroid Build Coastguard Worker std::transform(initialPackageStates.begin(), initialPackageStates.end(),
59*ec779b8eSAndroid Build Coastguard Worker std::inserter(package_map_, package_map_.end()),
60*ec779b8eSAndroid Build Coastguard Worker [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
61*ec779b8eSAndroid Build Coastguard Worker return {x.uid, x.packageNames};
62*ec779b8eSAndroid Build Coastguard Worker });
63*ec779b8eSAndroid Build Coastguard Worker std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
64*ec779b8eSAndroid Build Coastguard Worker return Status::ok();
65*ec779b8eSAndroid Build Coastguard Worker }
66*ec779b8eSAndroid Build Coastguard Worker
updatePackagesForUid(const UidPackageState & newPackageState)67*ec779b8eSAndroid Build Coastguard Worker Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
68*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
69*ec779b8eSAndroid Build Coastguard Worker package_map_.insert_or_assign(newPackageState.uid, newPackageState.packageNames);
70*ec779b8eSAndroid Build Coastguard Worker const auto& cursor = package_map_.find(newPackageState.uid);
71*ec779b8eSAndroid Build Coastguard Worker
72*ec779b8eSAndroid Build Coastguard Worker if (newPackageState.packageNames.empty()) {
73*ec779b8eSAndroid Build Coastguard Worker if (cursor != package_map_.end()) {
74*ec779b8eSAndroid Build Coastguard Worker package_map_.erase(cursor);
75*ec779b8eSAndroid Build Coastguard Worker }
76*ec779b8eSAndroid Build Coastguard Worker } else {
77*ec779b8eSAndroid Build Coastguard Worker if (cursor != package_map_.end()) {
78*ec779b8eSAndroid Build Coastguard Worker cursor->second = newPackageState.packageNames;
79*ec779b8eSAndroid Build Coastguard Worker } else {
80*ec779b8eSAndroid Build Coastguard Worker package_map_.insert({newPackageState.uid, newPackageState.packageNames});
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker }
83*ec779b8eSAndroid Build Coastguard Worker return Status::ok();
84*ec779b8eSAndroid Build Coastguard Worker }
85*ec779b8eSAndroid Build Coastguard Worker
populatePermissionState(PermissionEnum perm,const std::vector<int> & uids)86*ec779b8eSAndroid Build Coastguard Worker Status NativePermissionController::populatePermissionState(PermissionEnum perm,
87*ec779b8eSAndroid Build Coastguard Worker const std::vector<int>& uids) {
88*ec779b8eSAndroid Build Coastguard Worker if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
89*ec779b8eSAndroid Build Coastguard Worker return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
90*ec779b8eSAndroid Build Coastguard Worker }
91*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
92*ec779b8eSAndroid Build Coastguard Worker auto& cursor = permission_map_[static_cast<size_t>(perm)];
93*ec779b8eSAndroid Build Coastguard Worker cursor = std::vector<uid_t>{uids.begin(), uids.end()};
94*ec779b8eSAndroid Build Coastguard Worker // should be sorted
95*ec779b8eSAndroid Build Coastguard Worker std::sort(cursor.begin(), cursor.end());
96*ec779b8eSAndroid Build Coastguard Worker return Status::ok();
97*ec779b8eSAndroid Build Coastguard Worker }
98*ec779b8eSAndroid Build Coastguard Worker
99*ec779b8eSAndroid Build Coastguard Worker // -- End Binder methods
100*ec779b8eSAndroid Build Coastguard Worker
getPackagesForUid(uid_t uid) const101*ec779b8eSAndroid Build Coastguard Worker BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
102*ec779b8eSAndroid Build Coastguard Worker uid_t uid) const {
103*ec779b8eSAndroid Build Coastguard Worker uid = uid % AID_USER_OFFSET;
104*ec779b8eSAndroid Build Coastguard Worker const auto fixed_package_opt = getFixedPackageName(uid);
105*ec779b8eSAndroid Build Coastguard Worker if (fixed_package_opt.has_value()) {
106*ec779b8eSAndroid Build Coastguard Worker return BinderResult<std::vector<std::string>>{std::in_place_t{},
107*ec779b8eSAndroid Build Coastguard Worker {fixed_package_opt.value()}};
108*ec779b8eSAndroid Build Coastguard Worker }
109*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
110*ec779b8eSAndroid Build Coastguard Worker if (!is_package_populated_) {
111*ec779b8eSAndroid Build Coastguard Worker return unexpectedExceptionCode(
112*ec779b8eSAndroid Build Coastguard Worker Status::EX_ILLEGAL_STATE,
113*ec779b8eSAndroid Build Coastguard Worker "NPC::getPackagesForUid: controller never populated by system_server");
114*ec779b8eSAndroid Build Coastguard Worker }
115*ec779b8eSAndroid Build Coastguard Worker const auto cursor = package_map_.find(uid);
116*ec779b8eSAndroid Build Coastguard Worker if (cursor != package_map_.end()) {
117*ec779b8eSAndroid Build Coastguard Worker return cursor->second;
118*ec779b8eSAndroid Build Coastguard Worker } else {
119*ec779b8eSAndroid Build Coastguard Worker return unexpectedExceptionCode(
120*ec779b8eSAndroid Build Coastguard Worker Status::EX_ILLEGAL_ARGUMENT,
121*ec779b8eSAndroid Build Coastguard Worker ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
122*ec779b8eSAndroid Build Coastguard Worker }
123*ec779b8eSAndroid Build Coastguard Worker }
124*ec779b8eSAndroid Build Coastguard Worker
validateUidPackagePair(uid_t uid,const std::string & packageName) const125*ec779b8eSAndroid Build Coastguard Worker BinderResult<bool> NativePermissionController::validateUidPackagePair(
126*ec779b8eSAndroid Build Coastguard Worker uid_t uid, const std::string& packageName) const {
127*ec779b8eSAndroid Build Coastguard Worker if (uid == AID_ROOT || uid == AID_SYSTEM) return true;
128*ec779b8eSAndroid Build Coastguard Worker uid = uid % AID_USER_OFFSET;
129*ec779b8eSAndroid Build Coastguard Worker const auto fixed_package_opt = getFixedPackageName(uid);
130*ec779b8eSAndroid Build Coastguard Worker if (fixed_package_opt.has_value()) {
131*ec779b8eSAndroid Build Coastguard Worker return (uid == AID_ROOT || uid == AID_SYSTEM) ? true :
132*ec779b8eSAndroid Build Coastguard Worker packageName == fixed_package_opt.value();
133*ec779b8eSAndroid Build Coastguard Worker }
134*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
135*ec779b8eSAndroid Build Coastguard Worker if (!is_package_populated_) {
136*ec779b8eSAndroid Build Coastguard Worker return unexpectedExceptionCode(
137*ec779b8eSAndroid Build Coastguard Worker Status::EX_ILLEGAL_STATE,
138*ec779b8eSAndroid Build Coastguard Worker "NPC::validatedUidPackagePair: controller never populated by system_server");
139*ec779b8eSAndroid Build Coastguard Worker }
140*ec779b8eSAndroid Build Coastguard Worker const auto cursor = package_map_.find(uid);
141*ec779b8eSAndroid Build Coastguard Worker return (cursor != package_map_.end()) &&
142*ec779b8eSAndroid Build Coastguard Worker (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
143*ec779b8eSAndroid Build Coastguard Worker cursor->second.end());
144*ec779b8eSAndroid Build Coastguard Worker }
145*ec779b8eSAndroid Build Coastguard Worker
checkPermission(PermissionEnum perm,uid_t uid) const146*ec779b8eSAndroid Build Coastguard Worker BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
147*ec779b8eSAndroid Build Coastguard Worker uid_t uid) const {
148*ec779b8eSAndroid Build Coastguard Worker if (uid == AID_ROOT || uid == AID_SYSTEM || uid == getuid()) return true;
149*ec779b8eSAndroid Build Coastguard Worker std::lock_guard l{m_};
150*ec779b8eSAndroid Build Coastguard Worker const auto& uids = permission_map_[static_cast<size_t>(perm)];
151*ec779b8eSAndroid Build Coastguard Worker if (!uids.empty()) {
152*ec779b8eSAndroid Build Coastguard Worker return std::binary_search(uids.begin(), uids.end(), uid);
153*ec779b8eSAndroid Build Coastguard Worker } else {
154*ec779b8eSAndroid Build Coastguard Worker return unexpectedExceptionCode(
155*ec779b8eSAndroid Build Coastguard Worker Status::EX_ILLEGAL_STATE,
156*ec779b8eSAndroid Build Coastguard Worker "NPC::checkPermission: controller never populated by system_server");
157*ec779b8eSAndroid Build Coastguard Worker }
158*ec779b8eSAndroid Build Coastguard Worker }
159*ec779b8eSAndroid Build Coastguard Worker
160*ec779b8eSAndroid Build Coastguard Worker } // namespace com::android::media::permission
161