blob: 3b105e02ada4296bbbe695554fec7a171ff88462 [file] [log] [blame]
Steven Morelandfe66b732019-02-01 14:29:45 -08001/*
2 * Copyright (C) 2017 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
Martijn Coenen39247422017-09-25 15:29:06 +020017#define LOG_TAG "hwservicemanager"
18
Martijn Coenen7ce83be2017-04-07 16:19:32 -070019#include <android-base/logging.h>
20#include <hidl-util/FQName.h>
21#include <log/log.h>
22
23#include "AccessControl.h"
24
25namespace android {
26
27static const char *kPermissionAdd = "add";
28static const char *kPermissionGet = "find";
29static const char *kPermissionList = "list";
30
31struct audit_data {
32 const char* interfaceName;
33 pid_t pid;
34};
35
36using android::FQName;
Steven Moreland4034c1c2017-11-03 17:42:27 -070037using Context = AccessControl::Context;
Martijn Coenen7ce83be2017-04-07 16:19:32 -070038
39AccessControl::AccessControl() {
40 mSeHandle = selinux_android_hw_service_context_handle();
Yi Kong00892ee2018-07-31 16:50:28 -070041 LOG_ALWAYS_FATAL_IF(mSeHandle == nullptr, "Failed to acquire SELinux handle.");
Martijn Coenen7ce83be2017-04-07 16:19:32 -070042
43 if (getcon(&mSeContext) != 0) {
44 LOG_ALWAYS_FATAL("Failed to acquire hwservicemanager context.");
45 }
46
47 selinux_status_open(true);
48
49 mSeCallbacks.func_audit = AccessControl::auditCallback;
50 selinux_set_callback(SELINUX_CB_AUDIT, mSeCallbacks);
51
52 mSeCallbacks.func_log = selinux_log_callback; /* defined in libselinux */
53 selinux_set_callback(SELINUX_CB_LOG, mSeCallbacks);
54}
55
Steven Moreland4034c1c2017-11-03 17:42:27 -070056bool AccessControl::canAdd(const std::string& fqName, const Context &context, pid_t pid) {
Steven Moreland0cd38f02018-03-06 15:09:22 -080057 FQName fqIface;
Martijn Coenen7ce83be2017-04-07 16:19:32 -070058
Steven Moreland0cd38f02018-03-06 15:09:22 -080059 if (!FQName::parse(fqName, &fqIface)) {
Martijn Coenen7ce83be2017-04-07 16:19:32 -070060 return false;
61 }
62 const std::string checkName = fqIface.package() + "::" + fqIface.name();
63
Steven Moreland4034c1c2017-11-03 17:42:27 -070064 return checkPermission(context, pid, kPermissionAdd, checkName.c_str());
Martijn Coenen7ce83be2017-04-07 16:19:32 -070065}
66
67bool AccessControl::canGet(const std::string& fqName, pid_t pid) {
Steven Moreland0cd38f02018-03-06 15:09:22 -080068 FQName fqIface;
Martijn Coenen7ce83be2017-04-07 16:19:32 -070069
Steven Moreland0cd38f02018-03-06 15:09:22 -080070 if (!FQName::parse(fqName, &fqIface)) {
Martijn Coenen7ce83be2017-04-07 16:19:32 -070071 return false;
72 }
73 const std::string checkName = fqIface.package() + "::" + fqIface.name();
74
Steven Moreland4034c1c2017-11-03 17:42:27 -070075 return checkPermission(getContext(pid), pid, kPermissionGet, checkName.c_str());
Martijn Coenen7ce83be2017-04-07 16:19:32 -070076}
77
78bool AccessControl::canList(pid_t pid) {
Steven Moreland4034c1c2017-11-03 17:42:27 -070079 return checkPermission(getContext(pid), pid, mSeContext, kPermissionList, nullptr);
Martijn Coenen7ce83be2017-04-07 16:19:32 -070080}
81
Steven Moreland4034c1c2017-11-03 17:42:27 -070082Context AccessControl::getContext(pid_t sourcePid) {
Yi Kong00892ee2018-07-31 16:50:28 -070083 char *sourceContext = nullptr;
Martijn Coenen7ce83be2017-04-07 16:19:32 -070084
85 if (getpidcon(sourcePid, &sourceContext) < 0) {
Martijn Coenen39247422017-09-25 15:29:06 +020086 ALOGE("SELinux: failed to retrieve process context for pid %d", sourcePid);
Steven Moreland4034c1c2017-11-03 17:42:27 -070087 return Context(nullptr, freecon);
88 }
89
90 return Context(sourceContext, freecon);
91}
92
93bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *targetContext, const char *perm, const char *interface) {
94 if (context == nullptr) {
Martijn Coenen7ce83be2017-04-07 16:19:32 -070095 return false;
96 }
97
Steven Moreland4034c1c2017-11-03 17:42:27 -070098 bool allowed = false;
99 struct audit_data ad;
100
101 ad.pid = sourceAuditPid;
Martijn Coenen7ce83be2017-04-07 16:19:32 -0700102 ad.interfaceName = interface;
103
Steven Moreland4034c1c2017-11-03 17:42:27 -0700104 allowed = (selinux_check_access(context.get(), targetContext, "hwservice_manager",
Martijn Coenen7ce83be2017-04-07 16:19:32 -0700105 perm, (void *) &ad) == 0);
106
Martijn Coenen7ce83be2017-04-07 16:19:32 -0700107 return allowed;
108}
109
Steven Moreland4034c1c2017-11-03 17:42:27 -0700110bool AccessControl::checkPermission(const Context &context, pid_t sourceAuditPid, const char *perm, const char *interface) {
Yi Kong00892ee2018-07-31 16:50:28 -0700111 char *targetContext = nullptr;
Martijn Coenen7ce83be2017-04-07 16:19:32 -0700112 bool allowed = false;
113
114 // Lookup service in hwservice_contexts
115 if (selabel_lookup(mSeHandle, &targetContext, interface, 0) != 0) {
116 ALOGE("No match for interface %s in hwservice_contexts", interface);
117 return false;
118 }
119
Steven Moreland4034c1c2017-11-03 17:42:27 -0700120 allowed = checkPermission(context, sourceAuditPid, targetContext, perm, interface);
Martijn Coenen7ce83be2017-04-07 16:19:32 -0700121
122 freecon(targetContext);
123
124 return allowed;
125}
126
127int AccessControl::auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
128 struct audit_data *ad = (struct audit_data *)data;
129
130 if (!ad || !ad->interfaceName) {
131 ALOGE("No valid hwservicemanager audit data");
132 return 0;
133 }
134
135 snprintf(buf, len, "interface=%s pid=%d", ad->interfaceName, ad->pid);
136 return 0;
137}
138
139} // namespace android