1 // SPDX-License-Identifier: GPL-2.0
3 * SafeSetID Linux Security Module
5 * Author: Micah Morton <mortonm@chromium.org>
7 * Copyright (C) 2018 The Chromium OS Authors.
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.
15 #define pr_fmt(fmt) "SafeSetID: " fmt
17 #include <linux/security.h>
18 #include <linux/cred.h>
22 static DEFINE_MUTEX(policy_update_lock
);
25 * In the case the input buffer contains one or more invalid UIDs, the kuid_t
26 * variables pointed to by @parent and @child will get updated but this
27 * function will return an error.
28 * Contents of @buf may be modified.
30 static int parse_policy_line(struct file
*file
, char *buf
,
31 struct setuid_rule
*rule
)
35 u32 parsed_parent
, parsed_child
;
37 /* Format of |buf| string should be <UID>:<UID>. */
38 child_str
= strchr(buf
, ':');
39 if (child_str
== NULL
)
44 ret
= kstrtou32(buf
, 0, &parsed_parent
);
48 ret
= kstrtou32(child_str
, 0, &parsed_child
);
52 rule
->src_uid
= make_kuid(file
->f_cred
->user_ns
, parsed_parent
);
53 rule
->dst_uid
= make_kuid(file
->f_cred
->user_ns
, parsed_child
);
54 if (!uid_valid(rule
->src_uid
) || !uid_valid(rule
->dst_uid
))
60 static void __release_ruleset(struct rcu_head
*rcu
)
62 struct setuid_ruleset
*pol
=
63 container_of(rcu
, struct setuid_ruleset
, rcu
);
65 struct setuid_rule
*rule
;
66 struct hlist_node
*tmp
;
68 hash_for_each_safe(pol
->rules
, bucket
, tmp
, rule
, next
)
70 kfree(pol
->policy_str
);
74 static void release_ruleset(struct setuid_ruleset
*pol
)
76 call_rcu(&pol
->rcu
, __release_ruleset
);
79 static void insert_rule(struct setuid_ruleset
*pol
, struct setuid_rule
*rule
)
81 hash_add(pol
->rules
, &rule
->next
, __kuid_val(rule
->src_uid
));
84 static int verify_ruleset(struct setuid_ruleset
*pol
)
87 struct setuid_rule
*rule
, *nrule
;
90 hash_for_each(pol
->rules
, bucket
, rule
, next
) {
91 if (_setuid_policy_lookup(pol
, rule
->dst_uid
, INVALID_UID
) ==
93 pr_warn("insecure policy detected: uid %d is constrained but transitively unconstrained through uid %d\n",
94 __kuid_val(rule
->src_uid
),
95 __kuid_val(rule
->dst_uid
));
99 nrule
= kmalloc(sizeof(struct setuid_rule
), GFP_KERNEL
);
102 nrule
->src_uid
= rule
->dst_uid
;
103 nrule
->dst_uid
= rule
->dst_uid
;
104 insert_rule(pol
, nrule
);
110 static ssize_t
handle_policy_update(struct file
*file
,
111 const char __user
*ubuf
, size_t len
)
113 struct setuid_ruleset
*pol
;
117 pol
= kmalloc(sizeof(struct setuid_ruleset
), GFP_KERNEL
);
120 pol
->policy_str
= NULL
;
121 hash_init(pol
->rules
);
123 p
= buf
= memdup_user_nul(ubuf
, len
);
128 pol
->policy_str
= kstrdup(buf
, GFP_KERNEL
);
129 if (pol
->policy_str
== NULL
) {
134 /* policy lines, including the last one, end with \n */
136 struct setuid_rule
*rule
;
138 end
= strchr(p
, '\n');
145 rule
= kmalloc(sizeof(struct setuid_rule
), GFP_KERNEL
);
151 err
= parse_policy_line(file
, p
, rule
);
155 if (_setuid_policy_lookup(pol
, rule
->src_uid
, rule
->dst_uid
) ==
157 pr_warn("bad policy: duplicate entry\n");
162 insert_rule(pol
, rule
);
171 err
= verify_ruleset(pol
);
172 /* bogus policy falls through after fixing it up */
173 if (err
&& err
!= -EINVAL
)
177 * Everything looks good, apply the policy and release the old one.
178 * What we really want here is an xchg() wrapper for RCU, but since that
179 * doesn't currently exist, just use a spinlock for now.
181 mutex_lock(&policy_update_lock
);
182 rcu_swap_protected(safesetid_setuid_rules
, pol
,
183 lockdep_is_held(&policy_update_lock
));
184 mutex_unlock(&policy_update_lock
);
190 release_ruleset(pol
);
194 static ssize_t
safesetid_file_write(struct file
*file
,
195 const char __user
*buf
,
199 if (!file_ns_capable(file
, &init_user_ns
, CAP_MAC_ADMIN
))
205 return handle_policy_update(file
, buf
, len
);
208 static ssize_t
safesetid_file_read(struct file
*file
, char __user
*buf
,
209 size_t len
, loff_t
*ppos
)
212 struct setuid_ruleset
*pol
;
215 mutex_lock(&policy_update_lock
);
216 pol
= rcu_dereference_protected(safesetid_setuid_rules
,
217 lockdep_is_held(&policy_update_lock
));
219 kbuf
= pol
->policy_str
;
220 res
= simple_read_from_buffer(buf
, len
, ppos
,
223 mutex_unlock(&policy_update_lock
);
227 static const struct file_operations safesetid_file_fops
= {
228 .read
= safesetid_file_read
,
229 .write
= safesetid_file_write
,
232 static int __init
safesetid_init_securityfs(void)
235 struct dentry
*policy_dir
;
236 struct dentry
*policy_file
;
238 if (!safesetid_initialized
)
241 policy_dir
= securityfs_create_dir("safesetid", NULL
);
242 if (IS_ERR(policy_dir
)) {
243 ret
= PTR_ERR(policy_dir
);
247 policy_file
= securityfs_create_file("whitelist_policy", 0600,
248 policy_dir
, NULL
, &safesetid_file_fops
);
249 if (IS_ERR(policy_file
)) {
250 ret
= PTR_ERR(policy_file
);
257 securityfs_remove(policy_dir
);
260 fs_initcall(safesetid_init_securityfs
);