1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * SafeSetID Linux Security Module 4 * 5 * Author: Micah Morton <mortonm@chromium.org> 6 * 7 * Copyright (C) 2018 The Chromium OS Authors. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2, as 11 * published by the Free Software Foundation. 12 * 13 */ 14 15 #define pr_fmt(fmt) "SafeSetID: " fmt 16 17 #include <linux/lsm_hooks.h> 18 #include <linux/module.h> 19 #include <linux/ptrace.h> 20 #include <linux/sched/task_stack.h> 21 #include <linux/security.h> 22 #include "lsm.h" 23 24 /* Flag indicating whether initialization completed */ 25 int safesetid_initialized; 26 27 struct setuid_ruleset __rcu *safesetid_setuid_rules; 28 29 /* Compute a decision for a transition from @src to @dst under @policy. */ 30 enum sid_policy_type _setuid_policy_lookup(struct setuid_ruleset *policy, 31 kuid_t src, kuid_t dst) 32 { 33 struct setuid_rule *rule; 34 enum sid_policy_type result = SIDPOL_DEFAULT; 35 36 hash_for_each_possible(policy->rules, rule, next, __kuid_val(src)) { 37 if (!uid_eq(rule->src_uid, src)) 38 continue; 39 if (uid_eq(rule->dst_uid, dst)) 40 return SIDPOL_ALLOWED; 41 result = SIDPOL_CONSTRAINED; 42 } 43 return result; 44 } 45 46 /* 47 * Compute a decision for a transition from @src to @dst under the active 48 * policy. 49 */ 50 static enum sid_policy_type setuid_policy_lookup(kuid_t src, kuid_t dst) 51 { 52 enum sid_policy_type result = SIDPOL_DEFAULT; 53 struct setuid_ruleset *pol; 54 55 rcu_read_lock(); 56 pol = rcu_dereference(safesetid_setuid_rules); 57 if (pol) 58 result = _setuid_policy_lookup(pol, src, dst); 59 rcu_read_unlock(); 60 return result; 61 } 62 63 static int safesetid_security_capable(const struct cred *cred, 64 struct user_namespace *ns, 65 int cap, 66 unsigned int opts) 67 { 68 /* We're only interested in CAP_SETUID. */ 69 if (cap != CAP_SETUID) 70 return 0; 71 72 /* 73 * If CAP_SETUID is currently used for a set*uid() syscall, we want to 74 * let it go through here; the real security check happens later, in the 75 * task_fix_setuid hook. 76 */ 77 if ((opts & CAP_OPT_INSETID) != 0) 78 return 0; 79 80 /* 81 * If no policy applies to this task, allow the use of CAP_SETUID for 82 * other purposes. 83 */ 84 if (setuid_policy_lookup(cred->uid, INVALID_UID) == SIDPOL_DEFAULT) 85 return 0; 86 87 /* 88 * Reject use of CAP_SETUID for functionality other than calling 89 * set*uid() (e.g. setting up userns uid mappings). 90 */ 91 pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions\n", 92 __kuid_val(cred->uid)); 93 return -EPERM; 94 } 95 96 /* 97 * Check whether a caller with old credentials @old is allowed to switch to 98 * credentials that contain @new_uid. 99 */ 100 static bool uid_permitted_for_cred(const struct cred *old, kuid_t new_uid) 101 { 102 bool permitted; 103 104 /* If our old creds already had this UID in it, it's fine. */ 105 if (uid_eq(new_uid, old->uid) || uid_eq(new_uid, old->euid) || 106 uid_eq(new_uid, old->suid)) 107 return true; 108 109 /* 110 * Transitions to new UIDs require a check against the policy of the old 111 * RUID. 112 */ 113 permitted = 114 setuid_policy_lookup(old->uid, new_uid) != SIDPOL_CONSTRAINED; 115 if (!permitted) { 116 pr_warn("UID transition ((%d,%d,%d) -> %d) blocked\n", 117 __kuid_val(old->uid), __kuid_val(old->euid), 118 __kuid_val(old->suid), __kuid_val(new_uid)); 119 } 120 return permitted; 121 } 122 123 /* 124 * Check whether there is either an exception for user under old cred struct to 125 * set*uid to user under new cred struct, or the UID transition is allowed (by 126 * Linux set*uid rules) even without CAP_SETUID. 127 */ 128 static int safesetid_task_fix_setuid(struct cred *new, 129 const struct cred *old, 130 int flags) 131 { 132 133 /* Do nothing if there are no setuid restrictions for our old RUID. */ 134 if (setuid_policy_lookup(old->uid, INVALID_UID) == SIDPOL_DEFAULT) 135 return 0; 136 137 if (uid_permitted_for_cred(old, new->uid) && 138 uid_permitted_for_cred(old, new->euid) && 139 uid_permitted_for_cred(old, new->suid) && 140 uid_permitted_for_cred(old, new->fsuid)) 141 return 0; 142 143 /* 144 * Kill this process to avoid potential security vulnerabilities 145 * that could arise from a missing whitelist entry preventing a 146 * privileged process from dropping to a lesser-privileged one. 147 */ 148 force_sig(SIGKILL); 149 return -EACCES; 150 } 151 152 static struct security_hook_list safesetid_security_hooks[] = { 153 LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid), 154 LSM_HOOK_INIT(capable, safesetid_security_capable) 155 }; 156 157 static int __init safesetid_security_init(void) 158 { 159 security_add_hooks(safesetid_security_hooks, 160 ARRAY_SIZE(safesetid_security_hooks), "safesetid"); 161 162 /* Report that SafeSetID successfully initialized */ 163 safesetid_initialized = 1; 164 165 return 0; 166 } 167 168 DEFINE_LSM(safesetid_security_init) = { 169 .init = safesetid_security_init, 170 .name = "safesetid", 171 }; 172