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