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 // These packages are not handled by AppOps, but labeling may be useful for us
48 case AID_RADIO:
49 return "telephony";
50 case AID_BLUETOOTH:
51 return "bluetooth";
52 default:
53 return std::nullopt;
54 }
55 }
56
57 // -- Begin Binder methods
populatePackagesForUids(const std::vector<UidPackageState> & initialPackageStates)58 Status NativePermissionController::populatePackagesForUids(
59 const std::vector<UidPackageState>& initialPackageStates) {
60 std::lock_guard l{m_};
61 if (!is_package_populated_) is_package_populated_ = true;
62 package_map_.clear();
63 std::transform(initialPackageStates.begin(), initialPackageStates.end(),
64 std::inserter(package_map_, package_map_.end()),
65 [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
66 return {x.uid, x.packageNames};
67 });
68 std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
69 return Status::ok();
70 }
71
updatePackagesForUid(const UidPackageState & newPackageState)72 Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
73 std::lock_guard l{m_};
74 package_map_.insert_or_assign(newPackageState.uid, newPackageState.packageNames);
75 const auto& cursor = package_map_.find(newPackageState.uid);
76
77 if (newPackageState.packageNames.empty()) {
78 if (cursor != package_map_.end()) {
79 package_map_.erase(cursor);
80 }
81 } else {
82 if (cursor != package_map_.end()) {
83 cursor->second = newPackageState.packageNames;
84 } else {
85 package_map_.insert({newPackageState.uid, newPackageState.packageNames});
86 }
87 }
88 return Status::ok();
89 }
90
populatePermissionState(PermissionEnum perm,const std::vector<int> & uids)91 Status NativePermissionController::populatePermissionState(PermissionEnum perm,
92 const std::vector<int>& uids) {
93 if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
94 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
95 }
96 std::lock_guard l{m_};
97 auto& cursor = permission_map_[static_cast<size_t>(perm)];
98 cursor = std::vector<uid_t>{uids.begin(), uids.end()};
99 // should be sorted
100 std::sort(cursor.begin(), cursor.end());
101 return Status::ok();
102 }
103
104 // -- End Binder methods
105
getPackagesForUid(uid_t uid) const106 BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
107 uid_t uid) const {
108 uid = uid % AID_USER_OFFSET;
109 const auto fixed_package_opt = getFixedPackageName(uid);
110 if (fixed_package_opt.has_value()) {
111 return BinderResult<std::vector<std::string>>{std::in_place_t{},
112 {fixed_package_opt.value()}};
113 }
114 std::lock_guard l{m_};
115 if (!is_package_populated_) {
116 return unexpectedExceptionCode(
117 Status::EX_ILLEGAL_STATE,
118 "NPC::getPackagesForUid: controller never populated by system_server");
119 }
120 const auto cursor = package_map_.find(uid);
121 if (cursor != package_map_.end()) {
122 return cursor->second;
123 } else {
124 return unexpectedExceptionCode(
125 Status::EX_ILLEGAL_ARGUMENT,
126 ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
127 }
128 }
129
validateUidPackagePair(uid_t uid,const std::string & packageName) const130 BinderResult<bool> NativePermissionController::validateUidPackagePair(
131 uid_t uid, const std::string& packageName) const {
132 uid = uid % AID_USER_OFFSET;
133 const auto fixed_package_opt = getFixedPackageName(uid);
134 if (fixed_package_opt.has_value()) {
135 return packageName == fixed_package_opt.value();
136 }
137 std::lock_guard l{m_};
138 if (!is_package_populated_) {
139 return unexpectedExceptionCode(
140 Status::EX_ILLEGAL_STATE,
141 "NPC::validatedUidPackagePair: controller never populated by system_server");
142 }
143 const auto cursor = package_map_.find(uid);
144 return (cursor != package_map_.end()) &&
145 (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
146 cursor->second.end());
147 }
148
checkPermission(PermissionEnum perm,uid_t uid) const149 BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
150 uid_t uid) const {
151 std::lock_guard l{m_};
152 const auto& uids = permission_map_[static_cast<size_t>(perm)];
153 if (!uids.empty()) {
154 return std::binary_search(uids.begin(), uids.end(), uid);
155 } else {
156 return unexpectedExceptionCode(
157 Status::EX_ILLEGAL_STATE,
158 "NPC::checkPermission: controller never populated by system_server");
159 }
160 }
161
162 } // namespace com::android::media::permission
163