Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SafeSetID Linux Security Module
0004  *
0005  * Author: Micah Morton <mortonm@chromium.org>
0006  *
0007  * Copyright (C) 2018 The Chromium OS Authors.
0008  *
0009  * This program is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License version 2, as
0011  * published by the Free Software Foundation.
0012  *
0013  */
0014 
0015 #define pr_fmt(fmt) "SafeSetID: " fmt
0016 
0017 #include <linux/lsm_hooks.h>
0018 #include <linux/module.h>
0019 #include <linux/ptrace.h>
0020 #include <linux/sched/task_stack.h>
0021 #include <linux/security.h>
0022 #include "lsm.h"
0023 
0024 /* Flag indicating whether initialization completed */
0025 int safesetid_initialized __initdata;
0026 
0027 struct setid_ruleset __rcu *safesetid_setuid_rules;
0028 struct setid_ruleset __rcu *safesetid_setgid_rules;
0029 
0030 
0031 /* Compute a decision for a transition from @src to @dst under @policy. */
0032 enum sid_policy_type _setid_policy_lookup(struct setid_ruleset *policy,
0033         kid_t src, kid_t dst)
0034 {
0035     struct setid_rule *rule;
0036     enum sid_policy_type result = SIDPOL_DEFAULT;
0037 
0038     if (policy->type == UID) {
0039         hash_for_each_possible(policy->rules, rule, next, __kuid_val(src.uid)) {
0040             if (!uid_eq(rule->src_id.uid, src.uid))
0041                 continue;
0042             if (uid_eq(rule->dst_id.uid, dst.uid))
0043                 return SIDPOL_ALLOWED;
0044             result = SIDPOL_CONSTRAINED;
0045         }
0046     } else if (policy->type == GID) {
0047         hash_for_each_possible(policy->rules, rule, next, __kgid_val(src.gid)) {
0048             if (!gid_eq(rule->src_id.gid, src.gid))
0049                 continue;
0050             if (gid_eq(rule->dst_id.gid, dst.gid)){
0051                 return SIDPOL_ALLOWED;
0052             }
0053             result = SIDPOL_CONSTRAINED;
0054         }
0055     } else {
0056         /* Should not reach here, report the ID as contrainsted */
0057         result = SIDPOL_CONSTRAINED;
0058     }
0059     return result;
0060 }
0061 
0062 /*
0063  * Compute a decision for a transition from @src to @dst under the active
0064  * policy.
0065  */
0066 static enum sid_policy_type setid_policy_lookup(kid_t src, kid_t dst, enum setid_type new_type)
0067 {
0068     enum sid_policy_type result = SIDPOL_DEFAULT;
0069     struct setid_ruleset *pol;
0070 
0071     rcu_read_lock();
0072     if (new_type == UID)
0073         pol = rcu_dereference(safesetid_setuid_rules);
0074     else if (new_type == GID)
0075         pol = rcu_dereference(safesetid_setgid_rules);
0076     else { /* Should not reach here */
0077         result = SIDPOL_CONSTRAINED;
0078         rcu_read_unlock();
0079         return result;
0080     }
0081 
0082     if (pol) {
0083         pol->type = new_type;
0084         result = _setid_policy_lookup(pol, src, dst);
0085     }
0086     rcu_read_unlock();
0087     return result;
0088 }
0089 
0090 static int safesetid_security_capable(const struct cred *cred,
0091                       struct user_namespace *ns,
0092                       int cap,
0093                       unsigned int opts)
0094 {
0095     /* We're only interested in CAP_SETUID and CAP_SETGID. */
0096     if (cap != CAP_SETUID && cap != CAP_SETGID)
0097         return 0;
0098 
0099     /*
0100      * If CAP_SET{U/G}ID is currently used for a setid or setgroups syscall, we
0101      * want to let it go through here; the real security check happens later, in
0102      * the task_fix_set{u/g}id or task_fix_setgroups hooks.
0103      */
0104     if ((opts & CAP_OPT_INSETID) != 0)
0105         return 0;
0106 
0107     switch (cap) {
0108     case CAP_SETUID:
0109         /*
0110         * If no policy applies to this task, allow the use of CAP_SETUID for
0111         * other purposes.
0112         */
0113         if (setid_policy_lookup((kid_t){.uid = cred->uid}, INVALID_ID, UID) == SIDPOL_DEFAULT)
0114             return 0;
0115         /*
0116          * Reject use of CAP_SETUID for functionality other than calling
0117          * set*uid() (e.g. setting up userns uid mappings).
0118          */
0119         pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions\n",
0120             __kuid_val(cred->uid));
0121         return -EPERM;
0122     case CAP_SETGID:
0123         /*
0124         * If no policy applies to this task, allow the use of CAP_SETGID for
0125         * other purposes.
0126         */
0127         if (setid_policy_lookup((kid_t){.gid = cred->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT)
0128             return 0;
0129         /*
0130          * Reject use of CAP_SETUID for functionality other than calling
0131          * set*gid() (e.g. setting up userns gid mappings).
0132          */
0133         pr_warn("Operation requires CAP_SETGID, which is not available to GID %u for operations besides approved set*gid transitions\n",
0134             __kuid_val(cred->uid));
0135         return -EPERM;
0136     default:
0137         /* Error, the only capabilities were checking for is CAP_SETUID/GID */
0138         return 0;
0139     }
0140     return 0;
0141 }
0142 
0143 /*
0144  * Check whether a caller with old credentials @old is allowed to switch to
0145  * credentials that contain @new_id.
0146  */
0147 static bool id_permitted_for_cred(const struct cred *old, kid_t new_id, enum setid_type new_type)
0148 {
0149     bool permitted;
0150 
0151     /* If our old creds already had this ID in it, it's fine. */
0152     if (new_type == UID) {
0153         if (uid_eq(new_id.uid, old->uid) || uid_eq(new_id.uid, old->euid) ||
0154             uid_eq(new_id.uid, old->suid))
0155             return true;
0156     } else if (new_type == GID){
0157         if (gid_eq(new_id.gid, old->gid) || gid_eq(new_id.gid, old->egid) ||
0158             gid_eq(new_id.gid, old->sgid))
0159             return true;
0160     } else /* Error, new_type is an invalid type */
0161         return false;
0162 
0163     /*
0164      * Transitions to new UIDs require a check against the policy of the old
0165      * RUID.
0166      */
0167     permitted =
0168         setid_policy_lookup((kid_t){.uid = old->uid}, new_id, new_type) != SIDPOL_CONSTRAINED;
0169 
0170     if (!permitted) {
0171         if (new_type == UID) {
0172             pr_warn("UID transition ((%d,%d,%d) -> %d) blocked\n",
0173                 __kuid_val(old->uid), __kuid_val(old->euid),
0174                 __kuid_val(old->suid), __kuid_val(new_id.uid));
0175         } else if (new_type == GID) {
0176             pr_warn("GID transition ((%d,%d,%d) -> %d) blocked\n",
0177                 __kgid_val(old->gid), __kgid_val(old->egid),
0178                 __kgid_val(old->sgid), __kgid_val(new_id.gid));
0179         } else /* Error, new_type is an invalid type */
0180             return false;
0181     }
0182     return permitted;
0183 }
0184 
0185 /*
0186  * Check whether there is either an exception for user under old cred struct to
0187  * set*uid to user under new cred struct, or the UID transition is allowed (by
0188  * Linux set*uid rules) even without CAP_SETUID.
0189  */
0190 static int safesetid_task_fix_setuid(struct cred *new,
0191                      const struct cred *old,
0192                      int flags)
0193 {
0194 
0195     /* Do nothing if there are no setuid restrictions for our old RUID. */
0196     if (setid_policy_lookup((kid_t){.uid = old->uid}, INVALID_ID, UID) == SIDPOL_DEFAULT)
0197         return 0;
0198 
0199     if (id_permitted_for_cred(old, (kid_t){.uid = new->uid}, UID) &&
0200         id_permitted_for_cred(old, (kid_t){.uid = new->euid}, UID) &&
0201         id_permitted_for_cred(old, (kid_t){.uid = new->suid}, UID) &&
0202         id_permitted_for_cred(old, (kid_t){.uid = new->fsuid}, UID))
0203         return 0;
0204 
0205     /*
0206      * Kill this process to avoid potential security vulnerabilities
0207      * that could arise from a missing allowlist entry preventing a
0208      * privileged process from dropping to a lesser-privileged one.
0209      */
0210     force_sig(SIGKILL);
0211     return -EACCES;
0212 }
0213 
0214 static int safesetid_task_fix_setgid(struct cred *new,
0215                      const struct cred *old,
0216                      int flags)
0217 {
0218 
0219     /* Do nothing if there are no setgid restrictions for our old RGID. */
0220     if (setid_policy_lookup((kid_t){.gid = old->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT)
0221         return 0;
0222 
0223     if (id_permitted_for_cred(old, (kid_t){.gid = new->gid}, GID) &&
0224         id_permitted_for_cred(old, (kid_t){.gid = new->egid}, GID) &&
0225         id_permitted_for_cred(old, (kid_t){.gid = new->sgid}, GID) &&
0226         id_permitted_for_cred(old, (kid_t){.gid = new->fsgid}, GID))
0227         return 0;
0228 
0229     /*
0230      * Kill this process to avoid potential security vulnerabilities
0231      * that could arise from a missing allowlist entry preventing a
0232      * privileged process from dropping to a lesser-privileged one.
0233      */
0234     force_sig(SIGKILL);
0235     return -EACCES;
0236 }
0237 
0238 static int safesetid_task_fix_setgroups(struct cred *new, const struct cred *old)
0239 {
0240     int i;
0241 
0242     /* Do nothing if there are no setgid restrictions for our old RGID. */
0243     if (setid_policy_lookup((kid_t){.gid = old->gid}, INVALID_ID, GID) == SIDPOL_DEFAULT)
0244         return 0;
0245 
0246     get_group_info(new->group_info);
0247     for (i = 0; i < new->group_info->ngroups; i++) {
0248         if (!id_permitted_for_cred(old, (kid_t){.gid = new->group_info->gid[i]}, GID)) {
0249             put_group_info(new->group_info);
0250             /*
0251              * Kill this process to avoid potential security vulnerabilities
0252              * that could arise from a missing allowlist entry preventing a
0253              * privileged process from dropping to a lesser-privileged one.
0254              */
0255             force_sig(SIGKILL);
0256             return -EACCES;
0257         }
0258     }
0259 
0260     put_group_info(new->group_info);
0261     return 0;
0262 }
0263 
0264 static struct security_hook_list safesetid_security_hooks[] = {
0265     LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
0266     LSM_HOOK_INIT(task_fix_setgid, safesetid_task_fix_setgid),
0267     LSM_HOOK_INIT(task_fix_setgroups, safesetid_task_fix_setgroups),
0268     LSM_HOOK_INIT(capable, safesetid_security_capable)
0269 };
0270 
0271 static int __init safesetid_security_init(void)
0272 {
0273     security_add_hooks(safesetid_security_hooks,
0274                ARRAY_SIZE(safesetid_security_hooks), "safesetid");
0275 
0276     /* Report that SafeSetID successfully initialized */
0277     safesetid_initialized = 1;
0278 
0279     return 0;
0280 }
0281 
0282 DEFINE_LSM(safesetid_security_init) = {
0283     .init = safesetid_security_init,
0284     .name = "safesetid",
0285 };