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/security.h> 18 #include <linux/cred.h> 19 20 #include "lsm.h" 21 22 static DEFINE_MUTEX(uid_policy_update_lock); 23 static DEFINE_MUTEX(gid_policy_update_lock); 24 25 /* 26 * In the case the input buffer contains one or more invalid IDs, the kid_t 27 * variables pointed to by @parent and @child will get updated but this 28 * function will return an error. 29 * Contents of @buf may be modified. 30 */ 31 static int parse_policy_line(struct file *file, char *buf, 32 struct setid_rule *rule) 33 { 34 char *child_str; 35 int ret; 36 u32 parsed_parent, parsed_child; 37 38 /* Format of |buf| string should be <UID>:<UID> or <GID>:<GID> */ 39 child_str = strchr(buf, ':'); 40 if (child_str == NULL) 41 return -EINVAL; 42 *child_str = '\0'; 43 child_str++; 44 45 ret = kstrtou32(buf, 0, &parsed_parent); 46 if (ret) 47 return ret; 48 49 ret = kstrtou32(child_str, 0, &parsed_child); 50 if (ret) 51 return ret; 52 53 if (rule->type == UID){ 54 rule->src_id.uid = make_kuid(file->f_cred->user_ns, parsed_parent); 55 rule->dst_id.uid = make_kuid(file->f_cred->user_ns, parsed_child); 56 if (!uid_valid(rule->src_id.uid) || !uid_valid(rule->dst_id.uid)) 57 return -EINVAL; 58 } else if (rule->type == GID){ 59 rule->src_id.gid = make_kgid(file->f_cred->user_ns, parsed_parent); 60 rule->dst_id.gid = make_kgid(file->f_cred->user_ns, parsed_child); 61 if (!gid_valid(rule->src_id.gid) || !gid_valid(rule->dst_id.gid)) 62 return -EINVAL; 63 } else { 64 /* Error, rule->type is an invalid type */ 65 return -EINVAL; 66 } 67 return 0; 68 } 69 70 static void __release_ruleset(struct rcu_head *rcu) 71 { 72 struct setid_ruleset *pol = 73 container_of(rcu, struct setid_ruleset, rcu); 74 int bucket; 75 struct setid_rule *rule; 76 struct hlist_node *tmp; 77 78 hash_for_each_safe(pol->rules, bucket, tmp, rule, next) 79 kfree(rule); 80 kfree(pol->policy_str); 81 kfree(pol); 82 } 83 84 static void release_ruleset(struct setid_ruleset *pol){ 85 call_rcu(&pol->rcu, __release_ruleset); 86 } 87 88 static void insert_rule(struct setid_ruleset *pol, struct setid_rule *rule) 89 { 90 if (pol->type == UID) 91 hash_add(pol->rules, &rule->next, __kuid_val(rule->src_id.uid)); 92 else if (pol->type == GID) 93 hash_add(pol->rules, &rule->next, __kgid_val(rule->src_id.gid)); 94 else /* Error, pol->type is neither UID or GID */ 95 return; 96 } 97 98 static int verify_ruleset(struct setid_ruleset *pol) 99 { 100 int bucket; 101 struct setid_rule *rule, *nrule; 102 int res = 0; 103 104 hash_for_each(pol->rules, bucket, rule, next) { 105 if (_setid_policy_lookup(pol, rule->dst_id, INVALID_ID) == SIDPOL_DEFAULT) { 106 if (pol->type == UID) { 107 pr_warn("insecure policy detected: uid %d is constrained but transitively unconstrained through uid %d\n", 108 __kuid_val(rule->src_id.uid), 109 __kuid_val(rule->dst_id.uid)); 110 } else if (pol->type == GID) { 111 pr_warn("insecure policy detected: gid %d is constrained but transitively unconstrained through gid %d\n", 112 __kgid_val(rule->src_id.gid), 113 __kgid_val(rule->dst_id.gid)); 114 } else { /* pol->type is an invalid type */ 115 res = -EINVAL; 116 return res; 117 } 118 res = -EINVAL; 119 120 /* fix it up */ 121 nrule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL); 122 if (!nrule) 123 return -ENOMEM; 124 if (pol->type == UID){ 125 nrule->src_id.uid = rule->dst_id.uid; 126 nrule->dst_id.uid = rule->dst_id.uid; 127 nrule->type = UID; 128 } else { /* pol->type must be GID if we've made it to here */ 129 nrule->src_id.gid = rule->dst_id.gid; 130 nrule->dst_id.gid = rule->dst_id.gid; 131 nrule->type = GID; 132 } 133 insert_rule(pol, nrule); 134 } 135 } 136 return res; 137 } 138 139 static ssize_t handle_policy_update(struct file *file, 140 const char __user *ubuf, size_t len, enum setid_type policy_type) 141 { 142 struct setid_ruleset *pol; 143 char *buf, *p, *end; 144 int err; 145 146 if (len >= KMALLOC_MAX_SIZE) 147 return -EINVAL; 148 149 pol = kmalloc(sizeof(struct setid_ruleset), GFP_KERNEL); 150 if (!pol) 151 return -ENOMEM; 152 pol->policy_str = NULL; 153 pol->type = policy_type; 154 hash_init(pol->rules); 155 156 p = buf = memdup_user_nul(ubuf, len); 157 if (IS_ERR(buf)) { 158 err = PTR_ERR(buf); 159 goto out_free_pol; 160 } 161 pol->policy_str = kstrdup(buf, GFP_KERNEL); 162 if (pol->policy_str == NULL) { 163 err = -ENOMEM; 164 goto out_free_buf; 165 } 166 167 /* policy lines, including the last one, end with \n */ 168 while (*p != '\0') { 169 struct setid_rule *rule; 170 171 end = strchr(p, '\n'); 172 if (end == NULL) { 173 err = -EINVAL; 174 goto out_free_buf; 175 } 176 *end = '\0'; 177 178 rule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL); 179 if (!rule) { 180 err = -ENOMEM; 181 goto out_free_buf; 182 } 183 184 rule->type = policy_type; 185 err = parse_policy_line(file, p, rule); 186 if (err) 187 goto out_free_rule; 188 189 if (_setid_policy_lookup(pol, rule->src_id, rule->dst_id) == SIDPOL_ALLOWED) { 190 pr_warn("bad policy: duplicate entry\n"); 191 err = -EEXIST; 192 goto out_free_rule; 193 } 194 195 insert_rule(pol, rule); 196 p = end + 1; 197 continue; 198 199 out_free_rule: 200 kfree(rule); 201 goto out_free_buf; 202 } 203 204 err = verify_ruleset(pol); 205 /* bogus policy falls through after fixing it up */ 206 if (err && err != -EINVAL) 207 goto out_free_buf; 208 209 /* 210 * Everything looks good, apply the policy and release the old one. 211 * What we really want here is an xchg() wrapper for RCU, but since that 212 * doesn't currently exist, just use a spinlock for now. 213 */ 214 if (policy_type == UID) { 215 mutex_lock(&uid_policy_update_lock); 216 pol = rcu_replace_pointer(safesetid_setuid_rules, pol, 217 lockdep_is_held(&uid_policy_update_lock)); 218 mutex_unlock(&uid_policy_update_lock); 219 } else if (policy_type == GID) { 220 mutex_lock(&gid_policy_update_lock); 221 pol = rcu_replace_pointer(safesetid_setgid_rules, pol, 222 lockdep_is_held(&gid_policy_update_lock)); 223 mutex_unlock(&gid_policy_update_lock); 224 } else { 225 /* Error, policy type is neither UID or GID */ 226 pr_warn("error: bad policy type"); 227 } 228 err = len; 229 230 out_free_buf: 231 kfree(buf); 232 out_free_pol: 233 if (pol) 234 release_ruleset(pol); 235 return err; 236 } 237 238 static ssize_t safesetid_uid_file_write(struct file *file, 239 const char __user *buf, 240 size_t len, 241 loff_t *ppos) 242 { 243 if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN)) 244 return -EPERM; 245 246 if (*ppos != 0) 247 return -EINVAL; 248 249 return handle_policy_update(file, buf, len, UID); 250 } 251 252 static ssize_t safesetid_gid_file_write(struct file *file, 253 const char __user *buf, 254 size_t len, 255 loff_t *ppos) 256 { 257 if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN)) 258 return -EPERM; 259 260 if (*ppos != 0) 261 return -EINVAL; 262 263 return handle_policy_update(file, buf, len, GID); 264 } 265 266 static ssize_t safesetid_file_read(struct file *file, char __user *buf, 267 size_t len, loff_t *ppos, struct mutex *policy_update_lock, struct __rcu setid_ruleset* ruleset) 268 { 269 ssize_t res = 0; 270 struct setid_ruleset *pol; 271 const char *kbuf; 272 273 mutex_lock(policy_update_lock); 274 pol = rcu_dereference_protected(ruleset, lockdep_is_held(policy_update_lock)); 275 if (pol) { 276 kbuf = pol->policy_str; 277 res = simple_read_from_buffer(buf, len, ppos, 278 kbuf, strlen(kbuf)); 279 } 280 mutex_unlock(policy_update_lock); 281 282 return res; 283 } 284 285 static ssize_t safesetid_uid_file_read(struct file *file, char __user *buf, 286 size_t len, loff_t *ppos) 287 { 288 return safesetid_file_read(file, buf, len, ppos, 289 &uid_policy_update_lock, safesetid_setuid_rules); 290 } 291 292 static ssize_t safesetid_gid_file_read(struct file *file, char __user *buf, 293 size_t len, loff_t *ppos) 294 { 295 return safesetid_file_read(file, buf, len, ppos, 296 &gid_policy_update_lock, safesetid_setgid_rules); 297 } 298 299 300 301 static const struct file_operations safesetid_uid_file_fops = { 302 .read = safesetid_uid_file_read, 303 .write = safesetid_uid_file_write, 304 }; 305 306 static const struct file_operations safesetid_gid_file_fops = { 307 .read = safesetid_gid_file_read, 308 .write = safesetid_gid_file_write, 309 }; 310 311 static int __init safesetid_init_securityfs(void) 312 { 313 int ret; 314 struct dentry *policy_dir; 315 struct dentry *uid_policy_file; 316 struct dentry *gid_policy_file; 317 318 if (!safesetid_initialized) 319 return 0; 320 321 policy_dir = securityfs_create_dir("safesetid", NULL); 322 if (IS_ERR(policy_dir)) { 323 ret = PTR_ERR(policy_dir); 324 goto error; 325 } 326 327 uid_policy_file = securityfs_create_file("uid_allowlist_policy", 0600, 328 policy_dir, NULL, &safesetid_uid_file_fops); 329 if (IS_ERR(uid_policy_file)) { 330 ret = PTR_ERR(uid_policy_file); 331 goto error; 332 } 333 334 gid_policy_file = securityfs_create_file("gid_allowlist_policy", 0600, 335 policy_dir, NULL, &safesetid_gid_file_fops); 336 if (IS_ERR(gid_policy_file)) { 337 ret = PTR_ERR(gid_policy_file); 338 goto error; 339 } 340 341 342 return 0; 343 344 error: 345 securityfs_remove(policy_dir); 346 return ret; 347 } 348 fs_initcall(safesetid_init_securityfs); 349