Merge tag 'spi-fix-v6.1-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[platform/kernel/linux-starfive.git] / security / device_cgroup.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * device_cgroup.c - device cgroup subsystem
4  *
5  * Copyright 2007 IBM Corp
6  */
7
8 #include <linux/bpf-cgroup.h>
9 #include <linux/device_cgroup.h>
10 #include <linux/cgroup.h>
11 #include <linux/ctype.h>
12 #include <linux/list.h>
13 #include <linux/uaccess.h>
14 #include <linux/seq_file.h>
15 #include <linux/slab.h>
16 #include <linux/rcupdate.h>
17 #include <linux/mutex.h>
18
19 #ifdef CONFIG_CGROUP_DEVICE
20
21 static DEFINE_MUTEX(devcgroup_mutex);
22
23 enum devcg_behavior {
24         DEVCG_DEFAULT_NONE,
25         DEVCG_DEFAULT_ALLOW,
26         DEVCG_DEFAULT_DENY,
27 };
28
29 /*
30  * exception list locking rules:
31  * hold devcgroup_mutex for update/read.
32  * hold rcu_read_lock() for read.
33  */
34
35 struct dev_exception_item {
36         u32 major, minor;
37         short type;
38         short access;
39         struct list_head list;
40         struct rcu_head rcu;
41 };
42
43 struct dev_cgroup {
44         struct cgroup_subsys_state css;
45         struct list_head exceptions;
46         enum devcg_behavior behavior;
47 };
48
49 static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
50 {
51         return s ? container_of(s, struct dev_cgroup, css) : NULL;
52 }
53
54 static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
55 {
56         return css_to_devcgroup(task_css(task, devices_cgrp_id));
57 }
58
59 /*
60  * called under devcgroup_mutex
61  */
62 static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
63 {
64         struct dev_exception_item *ex, *tmp, *new;
65
66         lockdep_assert_held(&devcgroup_mutex);
67
68         list_for_each_entry(ex, orig, list) {
69                 new = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
70                 if (!new)
71                         goto free_and_exit;
72                 list_add_tail(&new->list, dest);
73         }
74
75         return 0;
76
77 free_and_exit:
78         list_for_each_entry_safe(ex, tmp, dest, list) {
79                 list_del(&ex->list);
80                 kfree(ex);
81         }
82         return -ENOMEM;
83 }
84
85 /*
86  * called under devcgroup_mutex
87  */
88 static int dev_exception_add(struct dev_cgroup *dev_cgroup,
89                              struct dev_exception_item *ex)
90 {
91         struct dev_exception_item *excopy, *walk;
92
93         lockdep_assert_held(&devcgroup_mutex);
94
95         excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
96         if (!excopy)
97                 return -ENOMEM;
98
99         list_for_each_entry(walk, &dev_cgroup->exceptions, list) {
100                 if (walk->type != ex->type)
101                         continue;
102                 if (walk->major != ex->major)
103                         continue;
104                 if (walk->minor != ex->minor)
105                         continue;
106
107                 walk->access |= ex->access;
108                 kfree(excopy);
109                 excopy = NULL;
110         }
111
112         if (excopy != NULL)
113                 list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions);
114         return 0;
115 }
116
117 /*
118  * called under devcgroup_mutex
119  */
120 static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
121                              struct dev_exception_item *ex)
122 {
123         struct dev_exception_item *walk, *tmp;
124
125         lockdep_assert_held(&devcgroup_mutex);
126
127         list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) {
128                 if (walk->type != ex->type)
129                         continue;
130                 if (walk->major != ex->major)
131                         continue;
132                 if (walk->minor != ex->minor)
133                         continue;
134
135                 walk->access &= ~ex->access;
136                 if (!walk->access) {
137                         list_del_rcu(&walk->list);
138                         kfree_rcu(walk, rcu);
139                 }
140         }
141 }
142
143 static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
144 {
145         struct dev_exception_item *ex, *tmp;
146
147         list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
148                 list_del_rcu(&ex->list);
149                 kfree_rcu(ex, rcu);
150         }
151 }
152
153 /**
154  * dev_exception_clean - frees all entries of the exception list
155  * @dev_cgroup: dev_cgroup with the exception list to be cleaned
156  *
157  * called under devcgroup_mutex
158  */
159 static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
160 {
161         lockdep_assert_held(&devcgroup_mutex);
162
163         __dev_exception_clean(dev_cgroup);
164 }
165
166 static inline bool is_devcg_online(const struct dev_cgroup *devcg)
167 {
168         return (devcg->behavior != DEVCG_DEFAULT_NONE);
169 }
170
171 /**
172  * devcgroup_online - initializes devcgroup's behavior and exceptions based on
173  *                    parent's
174  * @css: css getting online
175  * returns 0 in case of success, error code otherwise
176  */
177 static int devcgroup_online(struct cgroup_subsys_state *css)
178 {
179         struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
180         struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css->parent);
181         int ret = 0;
182
183         mutex_lock(&devcgroup_mutex);
184
185         if (parent_dev_cgroup == NULL)
186                 dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
187         else {
188                 ret = dev_exceptions_copy(&dev_cgroup->exceptions,
189                                           &parent_dev_cgroup->exceptions);
190                 if (!ret)
191                         dev_cgroup->behavior = parent_dev_cgroup->behavior;
192         }
193         mutex_unlock(&devcgroup_mutex);
194
195         return ret;
196 }
197
198 static void devcgroup_offline(struct cgroup_subsys_state *css)
199 {
200         struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
201
202         mutex_lock(&devcgroup_mutex);
203         dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
204         mutex_unlock(&devcgroup_mutex);
205 }
206
207 /*
208  * called from kernel/cgroup.c with cgroup_lock() held.
209  */
210 static struct cgroup_subsys_state *
211 devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
212 {
213         struct dev_cgroup *dev_cgroup;
214
215         dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
216         if (!dev_cgroup)
217                 return ERR_PTR(-ENOMEM);
218         INIT_LIST_HEAD(&dev_cgroup->exceptions);
219         dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
220
221         return &dev_cgroup->css;
222 }
223
224 static void devcgroup_css_free(struct cgroup_subsys_state *css)
225 {
226         struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
227
228         __dev_exception_clean(dev_cgroup);
229         kfree(dev_cgroup);
230 }
231
232 #define DEVCG_ALLOW 1
233 #define DEVCG_DENY 2
234 #define DEVCG_LIST 3
235
236 #define MAJMINLEN 13
237 #define ACCLEN 4
238
239 static void set_access(char *acc, short access)
240 {
241         int idx = 0;
242         memset(acc, 0, ACCLEN);
243         if (access & DEVCG_ACC_READ)
244                 acc[idx++] = 'r';
245         if (access & DEVCG_ACC_WRITE)
246                 acc[idx++] = 'w';
247         if (access & DEVCG_ACC_MKNOD)
248                 acc[idx++] = 'm';
249 }
250
251 static char type_to_char(short type)
252 {
253         if (type == DEVCG_DEV_ALL)
254                 return 'a';
255         if (type == DEVCG_DEV_CHAR)
256                 return 'c';
257         if (type == DEVCG_DEV_BLOCK)
258                 return 'b';
259         return 'X';
260 }
261
262 static void set_majmin(char *str, unsigned m)
263 {
264         if (m == ~0)
265                 strcpy(str, "*");
266         else
267                 sprintf(str, "%u", m);
268 }
269
270 static int devcgroup_seq_show(struct seq_file *m, void *v)
271 {
272         struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m));
273         struct dev_exception_item *ex;
274         char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
275
276         rcu_read_lock();
277         /*
278          * To preserve the compatibility:
279          * - Only show the "all devices" when the default policy is to allow
280          * - List the exceptions in case the default policy is to deny
281          * This way, the file remains as a "whitelist of devices"
282          */
283         if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
284                 set_access(acc, DEVCG_ACC_MASK);
285                 set_majmin(maj, ~0);
286                 set_majmin(min, ~0);
287                 seq_printf(m, "%c %s:%s %s\n", type_to_char(DEVCG_DEV_ALL),
288                            maj, min, acc);
289         } else {
290                 list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
291                         set_access(acc, ex->access);
292                         set_majmin(maj, ex->major);
293                         set_majmin(min, ex->minor);
294                         seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
295                                    maj, min, acc);
296                 }
297         }
298         rcu_read_unlock();
299
300         return 0;
301 }
302
303 /**
304  * match_exception      - iterates the exception list trying to find a complete match
305  * @exceptions: list of exceptions
306  * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR)
307  * @major: device file major number, ~0 to match all
308  * @minor: device file minor number, ~0 to match all
309  * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD)
310  *
311  * It is considered a complete match if an exception is found that will
312  * contain the entire range of provided parameters.
313  *
314  * Return: true in case it matches an exception completely
315  */
316 static bool match_exception(struct list_head *exceptions, short type,
317                             u32 major, u32 minor, short access)
318 {
319         struct dev_exception_item *ex;
320
321         list_for_each_entry_rcu(ex, exceptions, list) {
322                 if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
323                         continue;
324                 if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
325                         continue;
326                 if (ex->major != ~0 && ex->major != major)
327                         continue;
328                 if (ex->minor != ~0 && ex->minor != minor)
329                         continue;
330                 /* provided access cannot have more than the exception rule */
331                 if (access & (~ex->access))
332                         continue;
333                 return true;
334         }
335         return false;
336 }
337
338 /**
339  * match_exception_partial - iterates the exception list trying to find a partial match
340  * @exceptions: list of exceptions
341  * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR)
342  * @major: device file major number, ~0 to match all
343  * @minor: device file minor number, ~0 to match all
344  * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD)
345  *
346  * It is considered a partial match if an exception's range is found to
347  * contain *any* of the devices specified by provided parameters. This is
348  * used to make sure no extra access is being granted that is forbidden by
349  * any of the exception list.
350  *
351  * Return: true in case the provided range mat matches an exception completely
352  */
353 static bool match_exception_partial(struct list_head *exceptions, short type,
354                                     u32 major, u32 minor, short access)
355 {
356         struct dev_exception_item *ex;
357
358         list_for_each_entry_rcu(ex, exceptions, list,
359                                 lockdep_is_held(&devcgroup_mutex)) {
360                 if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK))
361                         continue;
362                 if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR))
363                         continue;
364                 /*
365                  * We must be sure that both the exception and the provided
366                  * range aren't masking all devices
367                  */
368                 if (ex->major != ~0 && major != ~0 && ex->major != major)
369                         continue;
370                 if (ex->minor != ~0 && minor != ~0 && ex->minor != minor)
371                         continue;
372                 /*
373                  * In order to make sure the provided range isn't matching
374                  * an exception, all its access bits shouldn't match the
375                  * exception's access bits
376                  */
377                 if (!(access & ex->access))
378                         continue;
379                 return true;
380         }
381         return false;
382 }
383
384 /**
385  * verify_new_ex - verifies if a new exception is allowed by parent cgroup's permissions
386  * @dev_cgroup: dev cgroup to be tested against
387  * @refex: new exception
388  * @behavior: behavior of the exception's dev_cgroup
389  *
390  * This is used to make sure a child cgroup won't have more privileges
391  * than its parent
392  */
393 static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
394                           struct dev_exception_item *refex,
395                           enum devcg_behavior behavior)
396 {
397         bool match = false;
398
399         RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&
400                          !lockdep_is_held(&devcgroup_mutex),
401                          "device_cgroup:verify_new_ex called without proper synchronization");
402
403         if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
404                 if (behavior == DEVCG_DEFAULT_ALLOW) {
405                         /*
406                          * new exception in the child doesn't matter, only
407                          * adding extra restrictions
408                          */ 
409                         return true;
410                 } else {
411                         /*
412                          * new exception in the child will add more devices
413                          * that can be acessed, so it can't match any of
414                          * parent's exceptions, even slightly
415                          */ 
416                         match = match_exception_partial(&dev_cgroup->exceptions,
417                                                         refex->type,
418                                                         refex->major,
419                                                         refex->minor,
420                                                         refex->access);
421
422                         if (match)
423                                 return false;
424                         return true;
425                 }
426         } else {
427                 /*
428                  * Only behavior == DEVCG_DEFAULT_DENY allowed here, therefore
429                  * the new exception will add access to more devices and must
430                  * be contained completely in an parent's exception to be
431                  * allowed
432                  */
433                 match = match_exception(&dev_cgroup->exceptions, refex->type,
434                                         refex->major, refex->minor,
435                                         refex->access);
436
437                 if (match)
438                         /* parent has an exception that matches the proposed */
439                         return true;
440                 else
441                         return false;
442         }
443         return false;
444 }
445
446 /*
447  * parent_has_perm:
448  * when adding a new allow rule to a device exception list, the rule
449  * must be allowed in the parent device
450  */
451 static int parent_has_perm(struct dev_cgroup *childcg,
452                                   struct dev_exception_item *ex)
453 {
454         struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
455
456         if (!parent)
457                 return 1;
458         return verify_new_ex(parent, ex, childcg->behavior);
459 }
460
461 /**
462  * parent_allows_removal - verify if it's ok to remove an exception
463  * @childcg: child cgroup from where the exception will be removed
464  * @ex: exception being removed
465  *
466  * When removing an exception in cgroups with default ALLOW policy, it must
467  * be checked if removing it will give the child cgroup more access than the
468  * parent.
469  *
470  * Return: true if it's ok to remove exception, false otherwise
471  */
472 static bool parent_allows_removal(struct dev_cgroup *childcg,
473                                   struct dev_exception_item *ex)
474 {
475         struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
476
477         if (!parent)
478                 return true;
479
480         /* It's always allowed to remove access to devices */
481         if (childcg->behavior == DEVCG_DEFAULT_DENY)
482                 return true;
483
484         /*
485          * Make sure you're not removing part or a whole exception existing in
486          * the parent cgroup
487          */
488         return !match_exception_partial(&parent->exceptions, ex->type,
489                                         ex->major, ex->minor, ex->access);
490 }
491
492 /**
493  * may_allow_all - checks if it's possible to change the behavior to
494  *                 allow based on parent's rules.
495  * @parent: device cgroup's parent
496  * returns: != 0 in case it's allowed, 0 otherwise
497  */
498 static inline int may_allow_all(struct dev_cgroup *parent)
499 {
500         if (!parent)
501                 return 1;
502         return parent->behavior == DEVCG_DEFAULT_ALLOW;
503 }
504
505 /**
506  * revalidate_active_exceptions - walks through the active exception list and
507  *                                revalidates the exceptions based on parent's
508  *                                behavior and exceptions. The exceptions that
509  *                                are no longer valid will be removed.
510  *                                Called with devcgroup_mutex held.
511  * @devcg: cgroup which exceptions will be checked
512  *
513  * This is one of the three key functions for hierarchy implementation.
514  * This function is responsible for re-evaluating all the cgroup's active
515  * exceptions due to a parent's exception change.
516  * Refer to Documentation/admin-guide/cgroup-v1/devices.rst for more details.
517  */
518 static void revalidate_active_exceptions(struct dev_cgroup *devcg)
519 {
520         struct dev_exception_item *ex;
521         struct list_head *this, *tmp;
522
523         list_for_each_safe(this, tmp, &devcg->exceptions) {
524                 ex = container_of(this, struct dev_exception_item, list);
525                 if (!parent_has_perm(devcg, ex))
526                         dev_exception_rm(devcg, ex);
527         }
528 }
529
530 /**
531  * propagate_exception - propagates a new exception to the children
532  * @devcg_root: device cgroup that added a new exception
533  * @ex: new exception to be propagated
534  *
535  * returns: 0 in case of success, != 0 in case of error
536  */
537 static int propagate_exception(struct dev_cgroup *devcg_root,
538                                struct dev_exception_item *ex)
539 {
540         struct cgroup_subsys_state *pos;
541         int rc = 0;
542
543         rcu_read_lock();
544
545         css_for_each_descendant_pre(pos, &devcg_root->css) {
546                 struct dev_cgroup *devcg = css_to_devcgroup(pos);
547
548                 /*
549                  * Because devcgroup_mutex is held, no devcg will become
550                  * online or offline during the tree walk (see on/offline
551                  * methods), and online ones are safe to access outside RCU
552                  * read lock without bumping refcnt.
553                  */
554                 if (pos == &devcg_root->css || !is_devcg_online(devcg))
555                         continue;
556
557                 rcu_read_unlock();
558
559                 /*
560                  * in case both root's behavior and devcg is allow, a new
561                  * restriction means adding to the exception list
562                  */
563                 if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW &&
564                     devcg->behavior == DEVCG_DEFAULT_ALLOW) {
565                         rc = dev_exception_add(devcg, ex);
566                         if (rc)
567                                 return rc;
568                 } else {
569                         /*
570                          * in the other possible cases:
571                          * root's behavior: allow, devcg's: deny
572                          * root's behavior: deny, devcg's: deny
573                          * the exception will be removed
574                          */
575                         dev_exception_rm(devcg, ex);
576                 }
577                 revalidate_active_exceptions(devcg);
578
579                 rcu_read_lock();
580         }
581
582         rcu_read_unlock();
583         return rc;
584 }
585
586 /*
587  * Modify the exception list using allow/deny rules.
588  * CAP_SYS_ADMIN is needed for this.  It's at least separate from CAP_MKNOD
589  * so we can give a container CAP_MKNOD to let it create devices but not
590  * modify the exception list.
591  * It seems likely we'll want to add a CAP_CONTAINER capability to allow
592  * us to also grant CAP_SYS_ADMIN to containers without giving away the
593  * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN
594  *
595  * Taking rules away is always allowed (given CAP_SYS_ADMIN).  Granting
596  * new access is only allowed if you're in the top-level cgroup, or your
597  * parent cgroup has the access you're asking for.
598  */
599 static int devcgroup_update_access(struct dev_cgroup *devcgroup,
600                                    int filetype, char *buffer)
601 {
602         const char *b;
603         char temp[12];          /* 11 + 1 characters needed for a u32 */
604         int count, rc = 0;
605         struct dev_exception_item ex;
606         struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
607
608         if (!capable(CAP_SYS_ADMIN))
609                 return -EPERM;
610
611         memset(&ex, 0, sizeof(ex));
612         b = buffer;
613
614         switch (*b) {
615         case 'a':
616                 switch (filetype) {
617                 case DEVCG_ALLOW:
618                         if (css_has_online_children(&devcgroup->css))
619                                 return -EINVAL;
620
621                         if (!may_allow_all(parent))
622                                 return -EPERM;
623                         dev_exception_clean(devcgroup);
624                         devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
625                         if (!parent)
626                                 break;
627
628                         rc = dev_exceptions_copy(&devcgroup->exceptions,
629                                                  &parent->exceptions);
630                         if (rc)
631                                 return rc;
632                         break;
633                 case DEVCG_DENY:
634                         if (css_has_online_children(&devcgroup->css))
635                                 return -EINVAL;
636
637                         dev_exception_clean(devcgroup);
638                         devcgroup->behavior = DEVCG_DEFAULT_DENY;
639                         break;
640                 default:
641                         return -EINVAL;
642                 }
643                 return 0;
644         case 'b':
645                 ex.type = DEVCG_DEV_BLOCK;
646                 break;
647         case 'c':
648                 ex.type = DEVCG_DEV_CHAR;
649                 break;
650         default:
651                 return -EINVAL;
652         }
653         b++;
654         if (!isspace(*b))
655                 return -EINVAL;
656         b++;
657         if (*b == '*') {
658                 ex.major = ~0;
659                 b++;
660         } else if (isdigit(*b)) {
661                 memset(temp, 0, sizeof(temp));
662                 for (count = 0; count < sizeof(temp) - 1; count++) {
663                         temp[count] = *b;
664                         b++;
665                         if (!isdigit(*b))
666                                 break;
667                 }
668                 rc = kstrtou32(temp, 10, &ex.major);
669                 if (rc)
670                         return -EINVAL;
671         } else {
672                 return -EINVAL;
673         }
674         if (*b != ':')
675                 return -EINVAL;
676         b++;
677
678         /* read minor */
679         if (*b == '*') {
680                 ex.minor = ~0;
681                 b++;
682         } else if (isdigit(*b)) {
683                 memset(temp, 0, sizeof(temp));
684                 for (count = 0; count < sizeof(temp) - 1; count++) {
685                         temp[count] = *b;
686                         b++;
687                         if (!isdigit(*b))
688                                 break;
689                 }
690                 rc = kstrtou32(temp, 10, &ex.minor);
691                 if (rc)
692                         return -EINVAL;
693         } else {
694                 return -EINVAL;
695         }
696         if (!isspace(*b))
697                 return -EINVAL;
698         for (b++, count = 0; count < 3; count++, b++) {
699                 switch (*b) {
700                 case 'r':
701                         ex.access |= DEVCG_ACC_READ;
702                         break;
703                 case 'w':
704                         ex.access |= DEVCG_ACC_WRITE;
705                         break;
706                 case 'm':
707                         ex.access |= DEVCG_ACC_MKNOD;
708                         break;
709                 case '\n':
710                 case '\0':
711                         count = 3;
712                         break;
713                 default:
714                         return -EINVAL;
715                 }
716         }
717
718         switch (filetype) {
719         case DEVCG_ALLOW:
720                 /*
721                  * If the default policy is to allow by default, try to remove
722                  * an matching exception instead. And be silent about it: we
723                  * don't want to break compatibility
724                  */
725                 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
726                         /* Check if the parent allows removing it first */
727                         if (!parent_allows_removal(devcgroup, &ex))
728                                 return -EPERM;
729                         dev_exception_rm(devcgroup, &ex);
730                         break;
731                 }
732
733                 if (!parent_has_perm(devcgroup, &ex))
734                         return -EPERM;
735                 rc = dev_exception_add(devcgroup, &ex);
736                 break;
737         case DEVCG_DENY:
738                 /*
739                  * If the default policy is to deny by default, try to remove
740                  * an matching exception instead. And be silent about it: we
741                  * don't want to break compatibility
742                  */
743                 if (devcgroup->behavior == DEVCG_DEFAULT_DENY)
744                         dev_exception_rm(devcgroup, &ex);
745                 else
746                         rc = dev_exception_add(devcgroup, &ex);
747
748                 if (rc)
749                         break;
750                 /* we only propagate new restrictions */
751                 rc = propagate_exception(devcgroup, &ex);
752                 break;
753         default:
754                 rc = -EINVAL;
755         }
756         return rc;
757 }
758
759 static ssize_t devcgroup_access_write(struct kernfs_open_file *of,
760                                       char *buf, size_t nbytes, loff_t off)
761 {
762         int retval;
763
764         mutex_lock(&devcgroup_mutex);
765         retval = devcgroup_update_access(css_to_devcgroup(of_css(of)),
766                                          of_cft(of)->private, strstrip(buf));
767         mutex_unlock(&devcgroup_mutex);
768         return retval ?: nbytes;
769 }
770
771 static struct cftype dev_cgroup_files[] = {
772         {
773                 .name = "allow",
774                 .write = devcgroup_access_write,
775                 .private = DEVCG_ALLOW,
776         },
777         {
778                 .name = "deny",
779                 .write = devcgroup_access_write,
780                 .private = DEVCG_DENY,
781         },
782         {
783                 .name = "list",
784                 .seq_show = devcgroup_seq_show,
785                 .private = DEVCG_LIST,
786         },
787         { }     /* terminate */
788 };
789
790 struct cgroup_subsys devices_cgrp_subsys = {
791         .css_alloc = devcgroup_css_alloc,
792         .css_free = devcgroup_css_free,
793         .css_online = devcgroup_online,
794         .css_offline = devcgroup_offline,
795         .legacy_cftypes = dev_cgroup_files,
796 };
797
798 /**
799  * devcgroup_legacy_check_permission - checks if an inode operation is permitted
800  * @dev_cgroup: the dev cgroup to be tested against
801  * @type: device type
802  * @major: device major number
803  * @minor: device minor number
804  * @access: combination of DEVCG_ACC_WRITE, DEVCG_ACC_READ and DEVCG_ACC_MKNOD
805  *
806  * returns 0 on success, -EPERM case the operation is not permitted
807  */
808 static int devcgroup_legacy_check_permission(short type, u32 major, u32 minor,
809                                         short access)
810 {
811         struct dev_cgroup *dev_cgroup;
812         bool rc;
813
814         rcu_read_lock();
815         dev_cgroup = task_devcgroup(current);
816         if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW)
817                 /* Can't match any of the exceptions, even partially */
818                 rc = !match_exception_partial(&dev_cgroup->exceptions,
819                                               type, major, minor, access);
820         else
821                 /* Need to match completely one exception to be allowed */
822                 rc = match_exception(&dev_cgroup->exceptions, type, major,
823                                      minor, access);
824         rcu_read_unlock();
825
826         if (!rc)
827                 return -EPERM;
828
829         return 0;
830 }
831
832 #endif /* CONFIG_CGROUP_DEVICE */
833
834 #if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF)
835
836 int devcgroup_check_permission(short type, u32 major, u32 minor, short access)
837 {
838         int rc = BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(type, major, minor, access);
839
840         if (rc)
841                 return rc;
842
843         #ifdef CONFIG_CGROUP_DEVICE
844         return devcgroup_legacy_check_permission(type, major, minor, access);
845
846         #else /* CONFIG_CGROUP_DEVICE */
847         return 0;
848
849         #endif /* CONFIG_CGROUP_DEVICE */
850 }
851 EXPORT_SYMBOL(devcgroup_check_permission);
852 #endif /* defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF) */