1 /*
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 
17 #define LOG_TAG "hwservicemanager"
18 
19 #include <android-base/logging.h>
20 #include <hidl-util/FQName.h>
21 #include <log/log.h>
22 
23 #include "AccessControl.h"
24 
25 namespace android {
26 
27 static const char *kPermissionAdd = "add";
28 static const char *kPermissionGet = "find";
29 static const char *kPermissionList = "list";
30 
31 struct audit_data {
32     const char* interfaceName;
33     const char* sid;
34     pid_t       pid;
35 };
36 
37 using android::FQName;
38 
AccessControl()39 AccessControl::AccessControl() {
40     mSeHandle = selinux_android_hw_service_context_handle();
41     LOG_ALWAYS_FATAL_IF(mSeHandle == nullptr, "Failed to acquire SELinux handle.");
42 
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 
canAdd(const std::string & fqName,const CallingContext & callingContext)56 bool AccessControl::canAdd(const std::string& fqName, const CallingContext& callingContext) {
57     FQName fqIface;
58 
59     if (!FQName::parse(fqName, &fqIface)) {
60         return false;
61     }
62     const std::string checkName = fqIface.package() + "::" + fqIface.name();
63 
64     return checkPermission(callingContext, kPermissionAdd, checkName.c_str());
65 }
66 
canGet(const std::string & fqName,const CallingContext & callingContext)67 bool AccessControl::canGet(const std::string& fqName, const CallingContext& callingContext) {
68     FQName fqIface;
69 
70     if (!FQName::parse(fqName, &fqIface)) {
71         return false;
72     }
73     const std::string checkName = fqIface.package() + "::" + fqIface.name();
74 
75     return checkPermission(callingContext, kPermissionGet, checkName.c_str());
76 }
77 
canList(const CallingContext & callingContext)78 bool AccessControl::canList(const CallingContext& callingContext) {
79     return checkPermission(callingContext, mSeContext, kPermissionList, nullptr);
80 }
81 
getCallingContext(pid_t sourcePid)82 AccessControl::CallingContext AccessControl::getCallingContext(pid_t sourcePid) {
83     char *sourceContext = nullptr;
84 
85     if (getpidcon(sourcePid, &sourceContext) < 0) {
86         ALOGE("SELinux: failed to retrieve process context for pid %d", sourcePid);
87         return { false, "", sourcePid };
88     }
89 
90     std::string context = sourceContext;
91     freecon(sourceContext);
92     return { true, context, sourcePid };
93 }
94 
checkPermission(const CallingContext & source,const char * targetContext,const char * perm,const char * interface)95 bool AccessControl::checkPermission(const CallingContext& source, const char *targetContext, const char *perm, const char *interface) {
96     if (!source.sidPresent) {
97         return false;
98     }
99 
100     bool allowed = false;
101 
102     struct audit_data ad;
103     ad.pid = source.pid;
104     ad.sid = source.sid.c_str();
105     ad.interfaceName = interface;
106 
107     allowed = (selinux_check_access(source.sid.c_str(), targetContext, "hwservice_manager",
108                                     perm, (void *) &ad) == 0);
109 
110     return allowed;
111 }
112 
checkPermission(const CallingContext & source,const char * perm,const char * interface)113 bool AccessControl::checkPermission(const CallingContext& source, const char *perm, const char *interface) {
114     char *targetContext = nullptr;
115     bool allowed = false;
116 
117     // Lookup service in hwservice_contexts
118     if (selabel_lookup(mSeHandle, &targetContext, interface, 0) != 0) {
119         ALOGE("No match for interface %s in hwservice_contexts", interface);
120         return false;
121     }
122 
123     allowed = checkPermission(source, targetContext, perm, interface);
124 
125     freecon(targetContext);
126 
127     return allowed;
128 }
129 
auditCallback(void * data,security_class_t,char * buf,size_t len)130 int AccessControl::auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
131     struct audit_data *ad = (struct audit_data *)data;
132 
133     if (!ad || !ad->interfaceName) {
134         ALOGE("No valid hwservicemanager audit data");
135         return 0;
136     }
137 
138     const char* sid = ad->sid ? ad->sid : "N/A";
139 
140     snprintf(buf, len, "interface=%s sid=%s pid=%d", ad->interfaceName, sid, ad->pid);
141     return 0;
142 }
143 
144 } // namespace android
145