~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/safesetid/securityfs.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /security/safesetid/securityfs.c (Version linux-6.11-rc3) and /security/safesetid/securityfs.c (Version linux-5.4.281)


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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php