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