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