• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
25 #include <sstream>
26 
27 namespace android {
28 
29 #ifdef VENDORSERVICEMANAGER
30 constexpr bool kIsVendor = true;
31 #else
32 constexpr bool kIsVendor = false;
33 #endif
34 
35 #ifdef __ANDROID__
getPidcon(pid_t pid)36 static std::string getPidcon(pid_t pid) {
37     android_errorWriteLog(0x534e4554, "121035042");
38 
39     char* lookup = nullptr;
40     if (getpidcon(pid, &lookup) < 0) {
41         LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context";
42         return "";
43     }
44     std::string result = lookup;
45     freecon(lookup);
46     return result;
47 }
48 
getSehandle()49 static struct selabel_handle* getSehandle() {
50     static struct selabel_handle* gSehandle = nullptr;
51     if (gSehandle != nullptr && selinux_status_updated()) {
52         selabel_close(gSehandle);
53         gSehandle = nullptr;
54     }
55 
56     if (gSehandle == nullptr) {
57         gSehandle = kIsVendor
58             ? selinux_android_vendor_service_context_handle()
59             : selinux_android_service_context_handle();
60     }
61 
62     CHECK(gSehandle != nullptr);
63     return gSehandle;
64 }
65 
66 struct AuditCallbackData {
67     const Access::CallingContext* context;
68     const std::string* tname;
69 };
70 
auditCallback(void * data,security_class_t,char * buf,size_t len)71 static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
72     const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data);
73 
74     if (!ad) {
75         LOG(ERROR) << "No service manager audit data";
76         return 0;
77     }
78 
79     snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid,
80         ad->tname->c_str());
81     return 0;
82 }
83 #endif
84 
toDebugString() const85 std::string Access::CallingContext::toDebugString() const {
86     std::stringstream ss;
87     ss << "Caller(pid=" << debugPid << ",uid=" << uid << ",sid=" << sid << ")";
88     return ss.str();
89 }
90 
Access()91 Access::Access() {
92 #ifdef __ANDROID__
93     union selinux_callback cb;
94 
95     cb.func_audit = auditCallback;
96     selinux_set_callback(SELINUX_CB_AUDIT, cb);
97 
98     cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback;
99     selinux_set_callback(SELINUX_CB_LOG, cb);
100 
101     CHECK(selinux_status_open(true /*fallback*/) >= 0);
102 
103     CHECK(getcon(&mThisProcessContext) == 0);
104 #endif
105 }
106 
~Access()107 Access::~Access() {
108     freecon(mThisProcessContext);
109 }
110 
getCallingContext()111 Access::CallingContext Access::getCallingContext() {
112 #ifdef __ANDROID__
113     IPCThreadState* ipc = IPCThreadState::self();
114 
115     const char* callingSid = ipc->getCallingSid();
116     pid_t callingPid = ipc->getCallingPid();
117 
118     return CallingContext {
119         .debugPid = callingPid,
120         .uid = ipc->getCallingUid(),
121         .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
122     };
123 #else
124     return CallingContext();
125 #endif
126 }
127 
canFind(const CallingContext & ctx,const std::string & name)128 bool Access::canFind(const CallingContext& ctx,const std::string& name) {
129     return actionAllowedFromLookup(ctx, name, "find");
130 }
131 
canAdd(const CallingContext & ctx,const std::string & name)132 bool Access::canAdd(const CallingContext& ctx, const std::string& name) {
133     return actionAllowedFromLookup(ctx, name, "add");
134 }
135 
canList(const CallingContext & ctx)136 bool Access::canList(const CallingContext& ctx) {
137     return actionAllowed(ctx, mThisProcessContext, "list", "service_manager");
138 }
139 
actionAllowed(const CallingContext & sctx,const char * tctx,const char * perm,const std::string & tname)140 bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
141         const std::string& tname) {
142 #ifdef __ANDROID__
143     const char* tclass = "service_manager";
144 
145     AuditCallbackData data = {
146         .context = &sctx,
147         .tname = &tname,
148     };
149 
150     return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
151         reinterpret_cast<void*>(&data));
152 #else
153     (void)sctx;
154     (void)tctx;
155     (void)perm;
156     (void)tname;
157 
158     return true;
159 #endif
160 }
161 
actionAllowedFromLookup(const CallingContext & sctx,const std::string & name,const char * perm)162 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
163 #ifdef __ANDROID__
164     char *tctx = nullptr;
165     if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
166         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
167         return false;
168     }
169 
170     bool allowed = actionAllowed(sctx, tctx, perm, name);
171     freecon(tctx);
172     return allowed;
173 #else
174     (void)sctx;
175     (void)name;
176     (void)perm;
177     (void)kIsVendor;
178 
179     return true;
180 #endif
181 }
182 
183 }  // android
184