• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // #define LOG_NDEBUG 0
18 #define LOG_TAG "NativePermissionController"
19 
20 #include <media/NativePermissionController.h>
21 
22 #include <algorithm>
23 #include <optional>
24 #include <utility>
25 
26 #include <android-base/expected.h>
27 #include <cutils/android_filesystem_config.h>
28 #include <utils/Errors.h>
29 #include <utils/Log.h>
30 
31 using ::android::binder::Status;
32 using ::android::error::BinderResult;
33 using ::android::error::unexpectedExceptionCode;
34 
35 namespace com::android::media::permission {
getFixedPackageName(uid_t uid)36 static std::optional<std::string> getFixedPackageName(uid_t uid) {
37     // These values are in sync with AppOpsService
38     switch (uid % AID_USER_OFFSET) {
39         case AID_ROOT:
40             return "root";
41         case AID_SYSTEM:
42             return "android";
43         case AID_SHELL:
44             return "com.android.shell";
45         case AID_MEDIA:
46             return "media";
47         case AID_AUDIOSERVER:
48             return "audioserver";
49         case AID_CAMERASERVER:
50             return "cameraserver";
51         default:
52             return std::nullopt;
53     }
54 }
55 
56 // -- Begin Binder methods
populatePackagesForUids(const std::vector<UidPackageState> & initialPackageStates)57 Status NativePermissionController::populatePackagesForUids(
58         const std::vector<UidPackageState>& initialPackageStates) {
59     std::lock_guard l{m_};
60     if (!is_package_populated_) is_package_populated_ = true;
61     package_map_.clear();
62     std::transform(initialPackageStates.begin(), initialPackageStates.end(),
63                    std::inserter(package_map_, package_map_.end()),
64                    [](const auto& x) -> std::pair<uid_t, std::vector<std::string>> {
65                        return {x.uid, x.packageNames};
66                    });
67     std::erase_if(package_map_, [](const auto& x) { return x.second.empty(); });
68     return Status::ok();
69 }
70 
updatePackagesForUid(const UidPackageState & newPackageState)71 Status NativePermissionController::updatePackagesForUid(const UidPackageState& newPackageState) {
72     std::lock_guard l{m_};
73     ALOGD("%s, %s", __func__, newPackageState.toString().c_str());
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     ALOGV("%s, %d", __func__, static_cast<int>(perm));
94     if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
95         return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
96     }
97     std::lock_guard l{m_};
98     auto& cursor = permission_map_[static_cast<size_t>(perm)];
99     cursor = std::vector<uid_t>{uids.begin(), uids.end()};
100     // should be sorted
101     std::sort(cursor.begin(), cursor.end());
102     return Status::ok();
103 }
104 
105 // -- End Binder methods
106 
getPackagesForUid(uid_t uid) const107 BinderResult<std::vector<std::string>> NativePermissionController::getPackagesForUid(
108         uid_t uid) const {
109     uid = uid % AID_USER_OFFSET;
110     const auto fixed_package_opt = getFixedPackageName(uid);
111     if (fixed_package_opt.has_value()) {
112         return BinderResult<std::vector<std::string>>{std::in_place_t{},
113                                                       {fixed_package_opt.value()}};
114     }
115     std::lock_guard l{m_};
116     if (!is_package_populated_) {
117         return unexpectedExceptionCode(
118                 Status::EX_ILLEGAL_STATE,
119                 "NPC::getPackagesForUid: controller never populated by system_server");
120     }
121     const auto cursor = package_map_.find(uid);
122     if (cursor != package_map_.end()) {
123         return cursor->second;
124     } else {
125         return unexpectedExceptionCode(
126                 Status::EX_ILLEGAL_ARGUMENT,
127                 ("NPC::getPackagesForUid: uid not found: " + std::to_string(uid)).c_str());
128     }
129 }
130 
validateUidPackagePair(uid_t uid,const std::string & packageName) const131 BinderResult<bool> NativePermissionController::validateUidPackagePair(
132         uid_t uid, const std::string& packageName) const {
133     if (uid == AID_ROOT || uid == AID_SYSTEM) return true;
134     uid = uid % AID_USER_OFFSET;
135     const auto fixed_package_opt = getFixedPackageName(uid);
136     if (fixed_package_opt.has_value()) {
137         return (uid == AID_ROOT || uid == AID_SYSTEM) ? true
138                                                       : packageName == fixed_package_opt.value();
139     }
140     std::lock_guard l{m_};
141     if (!is_package_populated_) {
142         return unexpectedExceptionCode(
143                 Status::EX_ILLEGAL_STATE,
144                 "NPC::validatedUidPackagePair: controller never populated by system_server");
145     }
146     const auto cursor = package_map_.find(uid);
147     if (cursor == package_map_.end()) {
148         return unexpectedExceptionCode(
149                 Status::EX_ILLEGAL_ARGUMENT,
150                 "NPC::validatedUidPackagePair: unknown uid");
151     }
152     return (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
153             cursor->second.end());
154 }
155 
checkPermission(PermissionEnum perm,uid_t uid) const156 BinderResult<bool> NativePermissionController::checkPermission(PermissionEnum perm,
157                                                                uid_t uid) const {
158     ALOGV("%s: checking %d for %u", __func__, static_cast<int>(perm), uid);
159     if (uid == AID_ROOT || uid == AID_SYSTEM || uid == getuid()) return true;
160     std::lock_guard l{m_};
161     const auto& uids = permission_map_[static_cast<size_t>(perm)];
162     if (!uids.empty()) {
163         const bool ret = std::binary_search(uids.begin(), uids.end(), uid);
164         // Log locally until all call-sites log errors well
165         ALOGD_IF(!ret, "%s: missing %d for %u", __func__, static_cast<int>(perm), uid);
166         return ret;
167     } else {
168         return unexpectedExceptionCode(
169                 Status::EX_ILLEGAL_STATE,
170                 "NPC::checkPermission: controller never populated by system_server");
171     }
172 }
173 
174 }  // namespace com::android::media::permission
175