| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 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 | namespace android { | 
|  | 26 |  | 
|  | 27 | #ifdef VENDORSERVICEMANAGER | 
|  | 28 | constexpr bool kIsVendor = true; | 
|  | 29 | #else | 
|  | 30 | constexpr bool kIsVendor = false; | 
|  | 31 | #endif | 
|  | 32 |  | 
|  | 33 | static std::string getPidcon(pid_t pid) { | 
| Yifan Hong | ba7fcc3 | 2020-06-03 16:53:07 +0000 | [diff] [blame] | 34 | android_errorWriteLog(0x534e4554, "121035042"); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 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 |  | 
|  | 46 | static 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 |  | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 64 | struct AuditCallbackData { | 
|  | 65 | const Access::CallingContext* context; | 
|  | 66 | const std::string* tname; | 
|  | 67 | }; | 
|  | 68 |  | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 69 | static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 70 | const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 71 |  | 
|  | 72 | if (!ad) { | 
|  | 73 | LOG(ERROR) << "No service manager audit data"; | 
|  | 74 | return 0; | 
|  | 75 | } | 
|  | 76 |  | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 77 | snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid, | 
|  | 78 | ad->tname->c_str()); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 79 | return 0; | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | Access::Access() { | 
|  | 83 | union selinux_callback cb; | 
|  | 84 |  | 
|  | 85 | cb.func_audit = auditCallback; | 
|  | 86 | selinux_set_callback(SELINUX_CB_AUDIT, cb); | 
|  | 87 |  | 
|  | 88 | cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; | 
|  | 89 | selinux_set_callback(SELINUX_CB_LOG, cb); | 
|  | 90 |  | 
|  | 91 | CHECK(selinux_status_open(true /*fallback*/) >= 0); | 
|  | 92 |  | 
|  | 93 | CHECK(getcon(&mThisProcessContext) == 0); | 
|  | 94 | } | 
|  | 95 |  | 
|  | 96 | Access::~Access() { | 
|  | 97 | freecon(mThisProcessContext); | 
|  | 98 | } | 
|  | 99 |  | 
| Steven Moreland | a9fe474 | 2019-07-18 14:45:20 -0700 | [diff] [blame] | 100 | Access::CallingContext Access::getCallingContext() { | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 101 | IPCThreadState* ipc = IPCThreadState::self(); | 
|  | 102 |  | 
|  | 103 | const char* callingSid = ipc->getCallingSid(); | 
|  | 104 | pid_t callingPid = ipc->getCallingPid(); | 
|  | 105 |  | 
|  | 106 | return CallingContext { | 
|  | 107 | .debugPid = callingPid, | 
|  | 108 | .uid = ipc->getCallingUid(), | 
|  | 109 | .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 110 | }; | 
|  | 111 | } | 
|  | 112 |  | 
| Steven Moreland | a9fe474 | 2019-07-18 14:45:20 -0700 | [diff] [blame] | 113 | bool Access::canFind(const CallingContext& ctx,const std::string& name) { | 
|  | 114 | return actionAllowedFromLookup(ctx, name, "find"); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 115 | } | 
|  | 116 |  | 
| Steven Moreland | a9fe474 | 2019-07-18 14:45:20 -0700 | [diff] [blame] | 117 | bool Access::canAdd(const CallingContext& ctx, const std::string& name) { | 
|  | 118 | return actionAllowedFromLookup(ctx, name, "add"); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
|  | 121 | bool Access::canList(const CallingContext& ctx) { | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 122 | return actionAllowed(ctx, mThisProcessContext, "list", "service_manager"); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 123 | } | 
|  | 124 |  | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 125 | bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm, | 
|  | 126 | const std::string& tname) { | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 127 | const char* tclass = "service_manager"; | 
|  | 128 |  | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 129 | AuditCallbackData data = { | 
|  | 130 | .context = &sctx, | 
|  | 131 | .tname = &tname, | 
|  | 132 | }; | 
|  | 133 |  | 
|  | 134 | return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, | 
|  | 135 | reinterpret_cast<void*>(&data)); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 136 | } | 
|  | 137 |  | 
| Steven Moreland | a9fe474 | 2019-07-18 14:45:20 -0700 | [diff] [blame] | 138 | bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) { | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 139 | char *tctx = nullptr; | 
| Tri Vo | 6ea2698 | 2019-10-04 12:34:53 -0700 | [diff] [blame] | 140 | if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) { | 
| Steven Moreland | a9fe474 | 2019-07-18 14:45:20 -0700 | [diff] [blame] | 141 | LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n"; | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 142 | return false; | 
|  | 143 | } | 
|  | 144 |  | 
| Steven Moreland | 68039a1 | 2019-07-31 19:44:16 -0700 | [diff] [blame] | 145 | bool allowed = actionAllowed(sctx, tctx, perm, name); | 
| Steven Moreland | 80e1e6d | 2019-06-21 12:35:59 -0700 | [diff] [blame] | 146 | freecon(tctx); | 
|  | 147 | return allowed; | 
|  | 148 | } | 
|  | 149 |  | 
|  | 150 | }  // android |