| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2016 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 "keystore" | 
|  | 18 |  | 
|  | 19 | #include "permissions.h" | 
|  | 20 |  | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 21 | #include <cutils/sockets.h> | 
| Logan Chien | cdc813f | 2018-04-23 13:52:28 +0800 | [diff] [blame] | 22 | #include <log/log.h> | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 23 | #include <private/android_filesystem_config.h> | 
|  | 24 |  | 
|  | 25 | #include <selinux/android.h> | 
|  | 26 |  | 
|  | 27 | #include "keystore_utils.h" | 
|  | 28 |  | 
|  | 29 | /* perm_labels associcated with keystore_key SELinux class verbs. */ | 
|  | 30 | const char* perm_labels[] = { | 
| Shawn Willden | e2a7b52 | 2017-04-11 09:27:40 -0600 | [diff] [blame] | 31 | "get_state", | 
|  | 32 | "get", | 
|  | 33 | "insert", | 
|  | 34 | "delete", | 
|  | 35 | "exist", | 
|  | 36 | "list", | 
|  | 37 | "reset", | 
|  | 38 | "password", | 
|  | 39 | "lock", | 
|  | 40 | "unlock", | 
|  | 41 | "is_empty", | 
|  | 42 | "sign", | 
|  | 43 | "verify", | 
|  | 44 | "grant", | 
|  | 45 | "duplicate", | 
|  | 46 | "clear_uid", | 
|  | 47 | "add_auth", | 
|  | 48 | "user_changed", | 
|  | 49 | "gen_unique_id", | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 50 | }; | 
|  | 51 |  | 
|  | 52 | struct user_euid { | 
|  | 53 | uid_t uid; | 
|  | 54 | uid_t euid; | 
|  | 55 | }; | 
|  | 56 |  | 
| Branden Archer | 84e7231 | 2019-01-04 10:33:16 -0800 | [diff] [blame] | 57 | user_euid user_euids[] = {{AID_VPN, AID_SYSTEM}, | 
|  | 58 | {AID_WIFI, AID_SYSTEM}, | 
|  | 59 | {AID_ROOT, AID_SYSTEM}, | 
| Victor Hsieh | 58c10ac | 2019-09-05 14:25:54 -0700 | [diff] [blame] | 60 | {AID_FSVERITY_CERT, AID_ROOT}, | 
|  | 61 | {AID_FSVERITY_CERT, AID_SYSTEM}, | 
| Branden Archer | 84e7231 | 2019-01-04 10:33:16 -0800 | [diff] [blame] | 62 |  | 
|  | 63 | #ifdef GRANT_ROOT_ALL_PERMISSIONS | 
|  | 64 | // Allow VTS tests to act on behalf of the wifi user | 
|  | 65 | {AID_WIFI, AID_ROOT} | 
|  | 66 | #endif | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 67 | }; | 
|  | 68 |  | 
|  | 69 | struct user_perm { | 
|  | 70 | uid_t uid; | 
|  | 71 | perm_t perms; | 
|  | 72 | }; | 
|  | 73 |  | 
|  | 74 | static user_perm user_perms[] = { | 
|  | 75 | {AID_SYSTEM, static_cast<perm_t>((uint32_t)(~0))}, | 
|  | 76 | {AID_VPN, static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY)}, | 
|  | 77 | {AID_WIFI, static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY)}, | 
| Branden Archer | a930c14 | 2019-02-21 14:42:30 -0800 | [diff] [blame] | 78 | {AID_BLUETOOTH, static_cast<perm_t>(P_GET | P_INSERT | P_DELETE | P_EXIST | P_SIGN | P_VERIFY)}, | 
| Branden Archer | 84e7231 | 2019-01-04 10:33:16 -0800 | [diff] [blame] | 79 |  | 
|  | 80 | #ifdef GRANT_ROOT_ALL_PERMISSIONS | 
|  | 81 | // Allow VTS tests running as root to perform all operations | 
|  | 82 | {AID_ROOT, static_cast<perm_t>((uint32_t)(~0))}, | 
|  | 83 | #else | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 84 | {AID_ROOT, static_cast<perm_t>(P_GET)}, | 
| Branden Archer | 84e7231 | 2019-01-04 10:33:16 -0800 | [diff] [blame] | 85 | #endif | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 86 | }; | 
|  | 87 |  | 
| Shawn Willden | e2a7b52 | 2017-04-11 09:27:40 -0600 | [diff] [blame] | 88 | static const perm_t DEFAULT_PERMS = static_cast<perm_t>( | 
|  | 89 | P_GET_STATE | P_GET | P_INSERT | P_DELETE | P_EXIST | P_LIST | P_SIGN | P_VERIFY | | 
|  | 90 | P_GEN_UNIQUE_ID /* Only privileged apps can do this, but enforcement is done by SELinux */); | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 91 |  | 
|  | 92 | struct audit_data { | 
|  | 93 | pid_t pid; | 
|  | 94 | uid_t uid; | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 95 | const char* sid; | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 96 | }; | 
|  | 97 |  | 
|  | 98 | const char* get_perm_label(perm_t perm) { | 
|  | 99 | unsigned int index = ffs(perm); | 
|  | 100 | if (index > 0 && index <= (sizeof(perm_labels) / sizeof(perm_labels[0]))) { | 
|  | 101 | return perm_labels[index - 1]; | 
|  | 102 | } else { | 
|  | 103 | ALOGE("Keystore: Failed to retrieve permission label.\n"); | 
|  | 104 | abort(); | 
|  | 105 | } | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | static int audit_callback(void* data, security_class_t /* cls */, char* buf, size_t len) { | 
|  | 109 | struct audit_data* ad = reinterpret_cast<struct audit_data*>(data); | 
|  | 110 | if (!ad) { | 
|  | 111 | ALOGE("No keystore audit data"); | 
|  | 112 | return 0; | 
|  | 113 | } | 
|  | 114 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 115 | const char* sid = ad->sid ? ad->sid : "N/A"; | 
|  | 116 | snprintf(buf, len, "pid=%d uid=%d sid=%s", ad->pid, ad->uid, sid); | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 117 | return 0; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | static char* tctx; | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 121 |  | 
|  | 122 | int configure_selinux() { | 
| Nick Kralevich | d13eef0 | 2016-12-09 17:11:22 -0800 | [diff] [blame] | 123 | union selinux_callback cb; | 
|  | 124 | cb.func_audit = audit_callback; | 
|  | 125 | selinux_set_callback(SELINUX_CB_AUDIT, cb); | 
|  | 126 | cb.func_log = selinux_log_callback; | 
|  | 127 | selinux_set_callback(SELINUX_CB_LOG, cb); | 
|  | 128 | if (getcon(&tctx) != 0) { | 
|  | 129 | ALOGE("SELinux: Could not acquire target context. Aborting keystore.\n"); | 
|  | 130 | return -1; | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 131 | } | 
|  | 132 |  | 
|  | 133 | return 0; | 
|  | 134 | } | 
|  | 135 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 136 | static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid, const char* ssid) { | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 137 | audit_data ad; | 
| Yi Kong | d291675 | 2018-07-26 17:44:27 -0700 | [diff] [blame] | 138 | char* sctx = nullptr; | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 139 | const char* selinux_class = "keystore_key"; | 
|  | 140 | const char* str_perm = get_perm_label(perm); | 
|  | 141 |  | 
|  | 142 | if (!str_perm) { | 
|  | 143 | return false; | 
|  | 144 | } | 
|  | 145 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 146 | if (ssid == nullptr && getpidcon(spid, &sctx) != 0) { | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 147 | ALOGE("SELinux: Failed to get source pid context.\n"); | 
|  | 148 | return false; | 
|  | 149 | } | 
|  | 150 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 151 | const char* use_sid = ssid ? ssid : sctx; | 
|  | 152 |  | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 153 | ad.pid = spid; | 
|  | 154 | ad.uid = uid; | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 155 | ad.sid = use_sid; | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 156 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 157 | bool allowed = selinux_check_access(use_sid, tctx, selinux_class, str_perm, | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 158 | reinterpret_cast<void*>(&ad)) == 0; | 
|  | 159 | freecon(sctx); | 
|  | 160 | return allowed; | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | /** | 
|  | 164 | * Returns the UID that the callingUid should act as. This is here for | 
|  | 165 | * legacy support of the WiFi and VPN systems and should be removed | 
|  | 166 | * when WiFi can operate in its own namespace. | 
|  | 167 | */ | 
|  | 168 | uid_t get_keystore_euid(uid_t uid) { | 
|  | 169 | for (size_t i = 0; i < sizeof(user_euids) / sizeof(user_euids[0]); i++) { | 
|  | 170 | struct user_euid user = user_euids[i]; | 
|  | 171 | if (user.uid == uid) { | 
|  | 172 | return user.euid; | 
|  | 173 | } | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | return uid; | 
|  | 177 | } | 
|  | 178 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 179 | bool has_permission(uid_t uid, perm_t perm, pid_t spid, const char* sid) { | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 180 | // All system users are equivalent for multi-user support. | 
|  | 181 | if (get_app_id(uid) == AID_SYSTEM) { | 
|  | 182 | uid = AID_SYSTEM; | 
|  | 183 | } | 
|  | 184 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 185 | if (sid == nullptr) { | 
|  | 186 | android_errorWriteLog(0x534e4554, "121035042"); | 
|  | 187 | } | 
|  | 188 |  | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 189 | for (size_t i = 0; i < sizeof(user_perms) / sizeof(user_perms[0]); i++) { | 
|  | 190 | struct user_perm user = user_perms[i]; | 
|  | 191 | if (user.uid == uid) { | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 192 | return (user.perms & perm) && keystore_selinux_check_access(uid, perm, spid, sid); | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 193 | } | 
|  | 194 | } | 
|  | 195 |  | 
| Steven Moreland | 23115b0 | 2019-01-10 16:20:20 -0800 | [diff] [blame] | 196 | return (DEFAULT_PERMS & perm) && keystore_selinux_check_access(uid, perm, spid, sid); | 
| Shawn Willden | c1d1fee | 2016-01-26 22:44:56 -0700 | [diff] [blame] | 197 | } | 
|  | 198 |  | 
|  | 199 | /** | 
|  | 200 | * Returns true if the callingUid is allowed to interact in the targetUid's | 
|  | 201 | * namespace. | 
|  | 202 | */ | 
|  | 203 | bool is_granted_to(uid_t callingUid, uid_t targetUid) { | 
|  | 204 | if (callingUid == targetUid) { | 
|  | 205 | return true; | 
|  | 206 | } | 
|  | 207 | for (size_t i = 0; i < sizeof(user_euids) / sizeof(user_euids[0]); i++) { | 
|  | 208 | struct user_euid user = user_euids[i]; | 
|  | 209 | if (user.euid == callingUid && user.uid == targetUid) { | 
|  | 210 | return true; | 
|  | 211 | } | 
|  | 212 | } | 
|  | 213 |  | 
|  | 214 | return false; | 
|  | 215 | } |