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(uid_policy_update_lock
);
23 static DEFINE_MUTEX(gid_policy_update_lock
);
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.
31 static int parse_policy_line(struct file
*file
, char *buf
,
32 struct setid_rule
*rule
)
36 u32 parsed_parent
, parsed_child
;
38 /* Format of |buf| string should be <UID>:<UID> or <GID>:<GID> */
39 child_str
= strchr(buf
, ':');
40 if (child_str
== NULL
)
45 ret
= kstrtou32(buf
, 0, &parsed_parent
);
49 ret
= kstrtou32(child_str
, 0, &parsed_child
);
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
))
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
))
64 /* Error, rule->type is an invalid type */
70 static void __release_ruleset(struct rcu_head
*rcu
)
72 struct setid_ruleset
*pol
=
73 container_of(rcu
, struct setid_ruleset
, rcu
);
75 struct setid_rule
*rule
;
76 struct hlist_node
*tmp
;
78 hash_for_each_safe(pol
->rules
, bucket
, tmp
, rule
, next
)
80 kfree(pol
->policy_str
);
84 static void release_ruleset(struct setid_ruleset
*pol
){
85 call_rcu(&pol
->rcu
, __release_ruleset
);
88 static void insert_rule(struct setid_ruleset
*pol
, struct setid_rule
*rule
)
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 */
98 static int verify_ruleset(struct setid_ruleset
*pol
)
101 struct setid_rule
*rule
, *nrule
;
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 */
121 nrule
= kmalloc(sizeof(struct setid_rule
), GFP_KERNEL
);
124 if (pol
->type
== UID
){
125 nrule
->src_id
.uid
= rule
->dst_id
.uid
;
126 nrule
->dst_id
.uid
= rule
->dst_id
.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
;
133 insert_rule(pol
, nrule
);
139 static ssize_t
handle_policy_update(struct file
*file
,
140 const char __user
*ubuf
, size_t len
, enum setid_type policy_type
)
142 struct setid_ruleset
*pol
;
146 pol
= kmalloc(sizeof(struct setid_ruleset
), GFP_KERNEL
);
149 pol
->policy_str
= NULL
;
150 pol
->type
= policy_type
;
151 hash_init(pol
->rules
);
153 p
= buf
= memdup_user_nul(ubuf
, len
);
158 pol
->policy_str
= kstrdup(buf
, GFP_KERNEL
);
159 if (pol
->policy_str
== NULL
) {
164 /* policy lines, including the last one, end with \n */
166 struct setid_rule
*rule
;
168 end
= strchr(p
, '\n');
175 rule
= kmalloc(sizeof(struct setid_rule
), GFP_KERNEL
);
181 rule
->type
= policy_type
;
182 err
= parse_policy_line(file
, p
, rule
);
186 if (_setid_policy_lookup(pol
, rule
->src_id
, rule
->dst_id
) == SIDPOL_ALLOWED
) {
187 pr_warn("bad policy: duplicate entry\n");
192 insert_rule(pol
, rule
);
201 err
= verify_ruleset(pol
);
202 /* bogus policy falls through after fixing it up */
203 if (err
&& err
!= -EINVAL
)
207 * Everything looks good, apply the policy and release the old one.
208 * What we really want here is an xchg() wrapper for RCU, but since that
209 * doesn't currently exist, just use a spinlock for now.
211 if (policy_type
== UID
) {
212 mutex_lock(&uid_policy_update_lock
);
213 pol
= rcu_replace_pointer(safesetid_setuid_rules
, pol
,
214 lockdep_is_held(&uid_policy_update_lock
));
215 mutex_unlock(&uid_policy_update_lock
);
216 } else if (policy_type
== GID
) {
217 mutex_lock(&gid_policy_update_lock
);
218 pol
= rcu_replace_pointer(safesetid_setgid_rules
, pol
,
219 lockdep_is_held(&gid_policy_update_lock
));
220 mutex_unlock(&gid_policy_update_lock
);
222 /* Error, policy type is neither UID or GID */
223 pr_warn("error: bad policy type");
231 release_ruleset(pol
);
235 static ssize_t
safesetid_uid_file_write(struct file
*file
,
236 const char __user
*buf
,
240 if (!file_ns_capable(file
, &init_user_ns
, CAP_MAC_ADMIN
))
246 return handle_policy_update(file
, buf
, len
, UID
);
249 static ssize_t
safesetid_gid_file_write(struct file
*file
,
250 const char __user
*buf
,
254 if (!file_ns_capable(file
, &init_user_ns
, CAP_MAC_ADMIN
))
260 return handle_policy_update(file
, buf
, len
, GID
);
263 static ssize_t
safesetid_file_read(struct file
*file
, char __user
*buf
,
264 size_t len
, loff_t
*ppos
, struct mutex
*policy_update_lock
, struct __rcu setid_ruleset
* ruleset
)
267 struct setid_ruleset
*pol
;
270 mutex_lock(policy_update_lock
);
271 pol
= rcu_dereference_protected(ruleset
, lockdep_is_held(policy_update_lock
));
273 kbuf
= pol
->policy_str
;
274 res
= simple_read_from_buffer(buf
, len
, ppos
,
277 mutex_unlock(policy_update_lock
);
282 static ssize_t
safesetid_uid_file_read(struct file
*file
, char __user
*buf
,
283 size_t len
, loff_t
*ppos
)
285 return safesetid_file_read(file
, buf
, len
, ppos
,
286 &uid_policy_update_lock
, safesetid_setuid_rules
);
289 static ssize_t
safesetid_gid_file_read(struct file
*file
, char __user
*buf
,
290 size_t len
, loff_t
*ppos
)
292 return safesetid_file_read(file
, buf
, len
, ppos
,
293 &gid_policy_update_lock
, safesetid_setgid_rules
);
298 static const struct file_operations safesetid_uid_file_fops
= {
299 .read
= safesetid_uid_file_read
,
300 .write
= safesetid_uid_file_write
,
303 static const struct file_operations safesetid_gid_file_fops
= {
304 .read
= safesetid_gid_file_read
,
305 .write
= safesetid_gid_file_write
,
308 static int __init
safesetid_init_securityfs(void)
311 struct dentry
*policy_dir
;
312 struct dentry
*uid_policy_file
;
313 struct dentry
*gid_policy_file
;
315 if (!safesetid_initialized
)
318 policy_dir
= securityfs_create_dir("safesetid", NULL
);
319 if (IS_ERR(policy_dir
)) {
320 ret
= PTR_ERR(policy_dir
);
324 uid_policy_file
= securityfs_create_file("uid_allowlist_policy", 0600,
325 policy_dir
, NULL
, &safesetid_uid_file_fops
);
326 if (IS_ERR(uid_policy_file
)) {
327 ret
= PTR_ERR(uid_policy_file
);
331 gid_policy_file
= securityfs_create_file("gid_allowlist_policy", 0600,
332 policy_dir
, NULL
, &safesetid_gid_file_fops
);
333 if (IS_ERR(gid_policy_file
)) {
334 ret
= PTR_ERR(gid_policy_file
);
342 securityfs_remove(policy_dir
);
345 fs_initcall(safesetid_init_securityfs
);