1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #include "Access.h"
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <log/log_safetynet.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <selinux/android.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <selinux/avc.h>
24*38e8c45fSAndroid Build Coastguard Worker
25*38e8c45fSAndroid Build Coastguard Worker #include <sstream>
26*38e8c45fSAndroid Build Coastguard Worker
27*38e8c45fSAndroid Build Coastguard Worker namespace android {
28*38e8c45fSAndroid Build Coastguard Worker
29*38e8c45fSAndroid Build Coastguard Worker #ifdef VENDORSERVICEMANAGER
30*38e8c45fSAndroid Build Coastguard Worker constexpr bool kIsVendor = true;
31*38e8c45fSAndroid Build Coastguard Worker #else
32*38e8c45fSAndroid Build Coastguard Worker constexpr bool kIsVendor = false;
33*38e8c45fSAndroid Build Coastguard Worker #endif
34*38e8c45fSAndroid Build Coastguard Worker
35*38e8c45fSAndroid Build Coastguard Worker #ifdef __ANDROID__
getPidcon(pid_t pid)36*38e8c45fSAndroid Build Coastguard Worker static std::string getPidcon(pid_t pid) {
37*38e8c45fSAndroid Build Coastguard Worker android_errorWriteLog(0x534e4554, "121035042");
38*38e8c45fSAndroid Build Coastguard Worker
39*38e8c45fSAndroid Build Coastguard Worker char* lookup = nullptr;
40*38e8c45fSAndroid Build Coastguard Worker if (getpidcon(pid, &lookup) < 0) {
41*38e8c45fSAndroid Build Coastguard Worker LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context";
42*38e8c45fSAndroid Build Coastguard Worker return "";
43*38e8c45fSAndroid Build Coastguard Worker }
44*38e8c45fSAndroid Build Coastguard Worker std::string result = lookup;
45*38e8c45fSAndroid Build Coastguard Worker freecon(lookup);
46*38e8c45fSAndroid Build Coastguard Worker return result;
47*38e8c45fSAndroid Build Coastguard Worker }
48*38e8c45fSAndroid Build Coastguard Worker
getSehandle()49*38e8c45fSAndroid Build Coastguard Worker static struct selabel_handle* getSehandle() {
50*38e8c45fSAndroid Build Coastguard Worker static struct selabel_handle* gSehandle = nullptr;
51*38e8c45fSAndroid Build Coastguard Worker if (gSehandle != nullptr && selinux_status_updated()) {
52*38e8c45fSAndroid Build Coastguard Worker selabel_close(gSehandle);
53*38e8c45fSAndroid Build Coastguard Worker gSehandle = nullptr;
54*38e8c45fSAndroid Build Coastguard Worker }
55*38e8c45fSAndroid Build Coastguard Worker
56*38e8c45fSAndroid Build Coastguard Worker if (gSehandle == nullptr) {
57*38e8c45fSAndroid Build Coastguard Worker gSehandle = kIsVendor
58*38e8c45fSAndroid Build Coastguard Worker ? selinux_android_vendor_service_context_handle()
59*38e8c45fSAndroid Build Coastguard Worker : selinux_android_service_context_handle();
60*38e8c45fSAndroid Build Coastguard Worker }
61*38e8c45fSAndroid Build Coastguard Worker
62*38e8c45fSAndroid Build Coastguard Worker CHECK(gSehandle != nullptr);
63*38e8c45fSAndroid Build Coastguard Worker return gSehandle;
64*38e8c45fSAndroid Build Coastguard Worker }
65*38e8c45fSAndroid Build Coastguard Worker
66*38e8c45fSAndroid Build Coastguard Worker struct AuditCallbackData {
67*38e8c45fSAndroid Build Coastguard Worker const Access::CallingContext* context;
68*38e8c45fSAndroid Build Coastguard Worker const std::string* tname;
69*38e8c45fSAndroid Build Coastguard Worker };
70*38e8c45fSAndroid Build Coastguard Worker
auditCallback(void * data,security_class_t,char * buf,size_t len)71*38e8c45fSAndroid Build Coastguard Worker static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
72*38e8c45fSAndroid Build Coastguard Worker const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data);
73*38e8c45fSAndroid Build Coastguard Worker
74*38e8c45fSAndroid Build Coastguard Worker if (!ad) {
75*38e8c45fSAndroid Build Coastguard Worker LOG(ERROR) << "No service manager audit data";
76*38e8c45fSAndroid Build Coastguard Worker return 0;
77*38e8c45fSAndroid Build Coastguard Worker }
78*38e8c45fSAndroid Build Coastguard Worker
79*38e8c45fSAndroid Build Coastguard Worker snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid,
80*38e8c45fSAndroid Build Coastguard Worker ad->tname->c_str());
81*38e8c45fSAndroid Build Coastguard Worker return 0;
82*38e8c45fSAndroid Build Coastguard Worker }
83*38e8c45fSAndroid Build Coastguard Worker #endif
84*38e8c45fSAndroid Build Coastguard Worker
toDebugString() const85*38e8c45fSAndroid Build Coastguard Worker std::string Access::CallingContext::toDebugString() const {
86*38e8c45fSAndroid Build Coastguard Worker std::stringstream ss;
87*38e8c45fSAndroid Build Coastguard Worker ss << "Caller(pid=" << debugPid << ",uid=" << uid << ",sid=" << sid << ")";
88*38e8c45fSAndroid Build Coastguard Worker return ss.str();
89*38e8c45fSAndroid Build Coastguard Worker }
90*38e8c45fSAndroid Build Coastguard Worker
Access()91*38e8c45fSAndroid Build Coastguard Worker Access::Access() {
92*38e8c45fSAndroid Build Coastguard Worker #ifdef __ANDROID__
93*38e8c45fSAndroid Build Coastguard Worker union selinux_callback cb;
94*38e8c45fSAndroid Build Coastguard Worker
95*38e8c45fSAndroid Build Coastguard Worker cb.func_audit = auditCallback;
96*38e8c45fSAndroid Build Coastguard Worker selinux_set_callback(SELINUX_CB_AUDIT, cb);
97*38e8c45fSAndroid Build Coastguard Worker
98*38e8c45fSAndroid Build Coastguard Worker cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback;
99*38e8c45fSAndroid Build Coastguard Worker selinux_set_callback(SELINUX_CB_LOG, cb);
100*38e8c45fSAndroid Build Coastguard Worker
101*38e8c45fSAndroid Build Coastguard Worker CHECK(selinux_status_open(true /*fallback*/) >= 0);
102*38e8c45fSAndroid Build Coastguard Worker
103*38e8c45fSAndroid Build Coastguard Worker CHECK(getcon(&mThisProcessContext) == 0);
104*38e8c45fSAndroid Build Coastguard Worker #endif
105*38e8c45fSAndroid Build Coastguard Worker }
106*38e8c45fSAndroid Build Coastguard Worker
~Access()107*38e8c45fSAndroid Build Coastguard Worker Access::~Access() {
108*38e8c45fSAndroid Build Coastguard Worker freecon(mThisProcessContext);
109*38e8c45fSAndroid Build Coastguard Worker }
110*38e8c45fSAndroid Build Coastguard Worker
getCallingContext()111*38e8c45fSAndroid Build Coastguard Worker Access::CallingContext Access::getCallingContext() {
112*38e8c45fSAndroid Build Coastguard Worker #ifdef __ANDROID__
113*38e8c45fSAndroid Build Coastguard Worker IPCThreadState* ipc = IPCThreadState::self();
114*38e8c45fSAndroid Build Coastguard Worker
115*38e8c45fSAndroid Build Coastguard Worker const char* callingSid = ipc->getCallingSid();
116*38e8c45fSAndroid Build Coastguard Worker pid_t callingPid = ipc->getCallingPid();
117*38e8c45fSAndroid Build Coastguard Worker
118*38e8c45fSAndroid Build Coastguard Worker return CallingContext {
119*38e8c45fSAndroid Build Coastguard Worker .debugPid = callingPid,
120*38e8c45fSAndroid Build Coastguard Worker .uid = ipc->getCallingUid(),
121*38e8c45fSAndroid Build Coastguard Worker .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
122*38e8c45fSAndroid Build Coastguard Worker };
123*38e8c45fSAndroid Build Coastguard Worker #else
124*38e8c45fSAndroid Build Coastguard Worker return CallingContext();
125*38e8c45fSAndroid Build Coastguard Worker #endif
126*38e8c45fSAndroid Build Coastguard Worker }
127*38e8c45fSAndroid Build Coastguard Worker
canFind(const CallingContext & ctx,const std::string & name)128*38e8c45fSAndroid Build Coastguard Worker bool Access::canFind(const CallingContext& ctx,const std::string& name) {
129*38e8c45fSAndroid Build Coastguard Worker return actionAllowedFromLookup(ctx, name, "find");
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker
canAdd(const CallingContext & ctx,const std::string & name)132*38e8c45fSAndroid Build Coastguard Worker bool Access::canAdd(const CallingContext& ctx, const std::string& name) {
133*38e8c45fSAndroid Build Coastguard Worker return actionAllowedFromLookup(ctx, name, "add");
134*38e8c45fSAndroid Build Coastguard Worker }
135*38e8c45fSAndroid Build Coastguard Worker
canList(const CallingContext & ctx)136*38e8c45fSAndroid Build Coastguard Worker bool Access::canList(const CallingContext& ctx) {
137*38e8c45fSAndroid Build Coastguard Worker return actionAllowed(ctx, mThisProcessContext, "list", "service_manager");
138*38e8c45fSAndroid Build Coastguard Worker }
139*38e8c45fSAndroid Build Coastguard Worker
actionAllowed(const CallingContext & sctx,const char * tctx,const char * perm,const std::string & tname)140*38e8c45fSAndroid Build Coastguard Worker bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
141*38e8c45fSAndroid Build Coastguard Worker const std::string& tname) {
142*38e8c45fSAndroid Build Coastguard Worker #ifdef __ANDROID__
143*38e8c45fSAndroid Build Coastguard Worker const char* tclass = "service_manager";
144*38e8c45fSAndroid Build Coastguard Worker
145*38e8c45fSAndroid Build Coastguard Worker AuditCallbackData data = {
146*38e8c45fSAndroid Build Coastguard Worker .context = &sctx,
147*38e8c45fSAndroid Build Coastguard Worker .tname = &tname,
148*38e8c45fSAndroid Build Coastguard Worker };
149*38e8c45fSAndroid Build Coastguard Worker
150*38e8c45fSAndroid Build Coastguard Worker return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
151*38e8c45fSAndroid Build Coastguard Worker reinterpret_cast<void*>(&data));
152*38e8c45fSAndroid Build Coastguard Worker #else
153*38e8c45fSAndroid Build Coastguard Worker (void)sctx;
154*38e8c45fSAndroid Build Coastguard Worker (void)tctx;
155*38e8c45fSAndroid Build Coastguard Worker (void)perm;
156*38e8c45fSAndroid Build Coastguard Worker (void)tname;
157*38e8c45fSAndroid Build Coastguard Worker
158*38e8c45fSAndroid Build Coastguard Worker return true;
159*38e8c45fSAndroid Build Coastguard Worker #endif
160*38e8c45fSAndroid Build Coastguard Worker }
161*38e8c45fSAndroid Build Coastguard Worker
actionAllowedFromLookup(const CallingContext & sctx,const std::string & name,const char * perm)162*38e8c45fSAndroid Build Coastguard Worker bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
163*38e8c45fSAndroid Build Coastguard Worker #ifdef __ANDROID__
164*38e8c45fSAndroid Build Coastguard Worker char *tctx = nullptr;
165*38e8c45fSAndroid Build Coastguard Worker if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
166*38e8c45fSAndroid Build Coastguard Worker LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
167*38e8c45fSAndroid Build Coastguard Worker return false;
168*38e8c45fSAndroid Build Coastguard Worker }
169*38e8c45fSAndroid Build Coastguard Worker
170*38e8c45fSAndroid Build Coastguard Worker bool allowed = actionAllowed(sctx, tctx, perm, name);
171*38e8c45fSAndroid Build Coastguard Worker freecon(tctx);
172*38e8c45fSAndroid Build Coastguard Worker return allowed;
173*38e8c45fSAndroid Build Coastguard Worker #else
174*38e8c45fSAndroid Build Coastguard Worker (void)sctx;
175*38e8c45fSAndroid Build Coastguard Worker (void)name;
176*38e8c45fSAndroid Build Coastguard Worker (void)perm;
177*38e8c45fSAndroid Build Coastguard Worker (void)kIsVendor;
178*38e8c45fSAndroid Build Coastguard Worker
179*38e8c45fSAndroid Build Coastguard Worker return true;
180*38e8c45fSAndroid Build Coastguard Worker #endif
181*38e8c45fSAndroid Build Coastguard Worker }
182*38e8c45fSAndroid Build Coastguard Worker
183*38e8c45fSAndroid Build Coastguard Worker } // android
184