blob: f4005c4dee029e80f2a0659082863c1500c9b5ce [file] [log] [blame]
Steven Moreland80e1e6d2019-06-21 12:35:59 -07001/*
2 * Copyright (C) 2019 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 "Access.h"
18
19#include <android-base/logging.h>
20#include <binder/IPCThreadState.h>
21#include <log/log_safetynet.h>
22#include <selinux/android.h>
23#include <selinux/avc.h>
24
25namespace android {
26
27#ifdef VENDORSERVICEMANAGER
28constexpr bool kIsVendor = true;
29#else
30constexpr bool kIsVendor = false;
31#endif
32
33static std::string getPidcon(pid_t pid) {
34 android_errorWriteLog(0x534e4554, "121035042");
35
36 char* lookup = nullptr;
37 if (getpidcon(pid, &lookup) < 0) {
38 LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context";
39 return "";
40 }
41 std::string result = lookup;
42 freecon(lookup);
43 return result;
44}
45
46static struct selabel_handle* getSehandle() {
47 static struct selabel_handle* gSehandle = nullptr;
48
49 if (gSehandle != nullptr && selinux_status_updated()) {
50 selabel_close(gSehandle);
51 gSehandle = nullptr;
52 }
53
54 if (gSehandle == nullptr) {
55 gSehandle = kIsVendor
56 ? selinux_android_vendor_service_context_handle()
57 : selinux_android_service_context_handle();
58 }
59
60 CHECK(gSehandle != nullptr);
61 return gSehandle;
62}
63
64static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
65 const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data);
66
67 if (!ad) {
68 LOG(ERROR) << "No service manager audit data";
69 return 0;
70 }
71
72 snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid);
73 return 0;
74}
75
76Access::Access() {
77 union selinux_callback cb;
78
79 cb.func_audit = auditCallback;
80 selinux_set_callback(SELINUX_CB_AUDIT, cb);
81
82 cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback;
83 selinux_set_callback(SELINUX_CB_LOG, cb);
84
85 CHECK(selinux_status_open(true /*fallback*/) >= 0);
86
87 CHECK(getcon(&mThisProcessContext) == 0);
88}
89
90Access::~Access() {
91 freecon(mThisProcessContext);
92}
93
94Access::CallingContext Access::getCallingContext(const std::string& name) {
95 IPCThreadState* ipc = IPCThreadState::self();
96
97 const char* callingSid = ipc->getCallingSid();
98 pid_t callingPid = ipc->getCallingPid();
99
100 return CallingContext {
101 .debugPid = callingPid,
102 .uid = ipc->getCallingUid(),
103 .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
104 .name = name,
105 };
106}
107
108bool Access::canFind(const CallingContext& ctx) {
109 return actionAllowedFromLookup(ctx, "find");
110}
111
112bool Access::canAdd(const CallingContext& ctx) {
113 return actionAllowedFromLookup(ctx, "add");
114}
115
116bool Access::canList(const CallingContext& ctx) {
117 CHECK(ctx.name == "");
118
119 return actionAllowed(ctx, mThisProcessContext, "list");
120}
121
122bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) {
123 const char* tclass = "service_manager";
124
125 return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx))));
126}
127
128bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) {
129 char *tctx = nullptr;
130 if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) {
131 LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n";
132 return false;
133 }
134
135 bool allowed = actionAllowed(sctx, tctx, perm);
136 freecon(tctx);
137 return allowed;
138}
139
140} // android