devcg: prepare may_access() for hierarchy support
[linux-2.6-block.git] / security / device_cgroup.c
1 /*
2  * device_cgroup.c - device cgroup subsystem
3  *
4  * Copyright 2007 IBM Corp
5  */
6
7 #include <linux/device_cgroup.h>
8 #include <linux/cgroup.h>
9 #include <linux/ctype.h>
10 #include <linux/list.h>
11 #include <linux/uaccess.h>
12 #include <linux/seq_file.h>
13 #include <linux/slab.h>
14 #include <linux/rcupdate.h>
15 #include <linux/mutex.h>
16
17 #define ACC_MKNOD 1
18 #define ACC_READ  2
19 #define ACC_WRITE 4
20 #define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
21
22 #define DEV_BLOCK 1
23 #define DEV_CHAR  2
24 #define DEV_ALL   4  /* this represents all devices */
25
26 static DEFINE_MUTEX(devcgroup_mutex);
27
28 enum devcg_behavior {
29         DEVCG_DEFAULT_NONE,
30         DEVCG_DEFAULT_ALLOW,
31         DEVCG_DEFAULT_DENY,
32 };
33
34 /*
35  * exception list locking rules:
36  * hold devcgroup_mutex for update/read.
37  * hold rcu_read_lock() for read.
38  */
39
40 struct dev_exception_item {
41         u32 major, minor;
42         short type;
43         short access;
44         struct list_head list;
45         struct rcu_head rcu;
46 };
47
48 struct dev_cgroup {
49         struct cgroup_subsys_state css;
50         struct list_head exceptions;
51         enum devcg_behavior behavior;
52 };
53
54 static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
55 {
56         return container_of(s, struct dev_cgroup, css);
57 }
58
59 static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup)
60 {
61         return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id));
62 }
63
64 static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
65 {
66         return css_to_devcgroup(task_subsys_state(task, devices_subsys_id));
67 }
68
69 struct cgroup_subsys devices_subsys;
70
71 static int devcgroup_can_attach(struct cgroup *new_cgrp,
72                                 struct cgroup_taskset *set)
73 {
74         struct task_struct *task = cgroup_taskset_first(set);
75
76         if (current != task && !capable(CAP_SYS_ADMIN))
77                 return -EPERM;
78         return 0;
79 }
80
81 /*
82  * called under devcgroup_mutex
83  */
84 static int dev_exceptions_copy(struct list_head *dest, struct list_head *orig)
85 {
86         struct dev_exception_item *ex, *tmp, *new;
87
88         lockdep_assert_held(&devcgroup_mutex);
89
90         list_for_each_entry(ex, orig, list) {
91                 new = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
92                 if (!new)
93                         goto free_and_exit;
94                 list_add_tail(&new->list, dest);
95         }
96
97         return 0;
98
99 free_and_exit:
100         list_for_each_entry_safe(ex, tmp, dest, list) {
101                 list_del(&ex->list);
102                 kfree(ex);
103         }
104         return -ENOMEM;
105 }
106
107 /*
108  * called under devcgroup_mutex
109  */
110 static int dev_exception_add(struct dev_cgroup *dev_cgroup,
111                              struct dev_exception_item *ex)
112 {
113         struct dev_exception_item *excopy, *walk;
114
115         lockdep_assert_held(&devcgroup_mutex);
116
117         excopy = kmemdup(ex, sizeof(*ex), GFP_KERNEL);
118         if (!excopy)
119                 return -ENOMEM;
120
121         list_for_each_entry(walk, &dev_cgroup->exceptions, list) {
122                 if (walk->type != ex->type)
123                         continue;
124                 if (walk->major != ex->major)
125                         continue;
126                 if (walk->minor != ex->minor)
127                         continue;
128
129                 walk->access |= ex->access;
130                 kfree(excopy);
131                 excopy = NULL;
132         }
133
134         if (excopy != NULL)
135                 list_add_tail_rcu(&excopy->list, &dev_cgroup->exceptions);
136         return 0;
137 }
138
139 /*
140  * called under devcgroup_mutex
141  */
142 static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
143                              struct dev_exception_item *ex)
144 {
145         struct dev_exception_item *walk, *tmp;
146
147         lockdep_assert_held(&devcgroup_mutex);
148
149         list_for_each_entry_safe(walk, tmp, &dev_cgroup->exceptions, list) {
150                 if (walk->type != ex->type)
151                         continue;
152                 if (walk->major != ex->major)
153                         continue;
154                 if (walk->minor != ex->minor)
155                         continue;
156
157                 walk->access &= ~ex->access;
158                 if (!walk->access) {
159                         list_del_rcu(&walk->list);
160                         kfree_rcu(walk, rcu);
161                 }
162         }
163 }
164
165 static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
166 {
167         struct dev_exception_item *ex, *tmp;
168
169         list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
170                 list_del_rcu(&ex->list);
171                 kfree_rcu(ex, rcu);
172         }
173 }
174
175 /**
176  * dev_exception_clean - frees all entries of the exception list
177  * @dev_cgroup: dev_cgroup with the exception list to be cleaned
178  *
179  * called under devcgroup_mutex
180  */
181 static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
182 {
183         lockdep_assert_held(&devcgroup_mutex);
184
185         __dev_exception_clean(dev_cgroup);
186 }
187
188 /*
189  * called from kernel/cgroup.c with cgroup_lock() held.
190  */
191 static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup)
192 {
193         struct dev_cgroup *dev_cgroup, *parent_dev_cgroup;
194         struct cgroup *parent_cgroup;
195         int ret;
196
197         dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
198         if (!dev_cgroup)
199                 return ERR_PTR(-ENOMEM);
200         INIT_LIST_HEAD(&dev_cgroup->exceptions);
201         parent_cgroup = cgroup->parent;
202
203         if (parent_cgroup == NULL)
204                 dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
205         else {
206                 parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
207                 mutex_lock(&devcgroup_mutex);
208                 ret = dev_exceptions_copy(&dev_cgroup->exceptions,
209                                           &parent_dev_cgroup->exceptions);
210                 dev_cgroup->behavior = parent_dev_cgroup->behavior;
211                 mutex_unlock(&devcgroup_mutex);
212                 if (ret) {
213                         kfree(dev_cgroup);
214                         return ERR_PTR(ret);
215                 }
216         }
217
218         return &dev_cgroup->css;
219 }
220
221 static void devcgroup_css_free(struct cgroup *cgroup)
222 {
223         struct dev_cgroup *dev_cgroup;
224
225         dev_cgroup = cgroup_to_devcgroup(cgroup);
226         __dev_exception_clean(dev_cgroup);
227         kfree(dev_cgroup);
228 }
229
230 #define DEVCG_ALLOW 1
231 #define DEVCG_DENY 2
232 #define DEVCG_LIST 3
233
234 #define MAJMINLEN 13
235 #define ACCLEN 4
236
237 static void set_access(char *acc, short access)
238 {
239         int idx = 0;
240         memset(acc, 0, ACCLEN);
241         if (access & ACC_READ)
242                 acc[idx++] = 'r';
243         if (access & ACC_WRITE)
244                 acc[idx++] = 'w';
245         if (access & ACC_MKNOD)
246                 acc[idx++] = 'm';
247 }
248
249 static char type_to_char(short type)
250 {
251         if (type == DEV_ALL)
252                 return 'a';
253         if (type == DEV_CHAR)
254                 return 'c';
255         if (type == DEV_BLOCK)
256                 return 'b';
257         return 'X';
258 }
259
260 static void set_majmin(char *str, unsigned m)
261 {
262         if (m == ~0)
263                 strcpy(str, "*");
264         else
265                 sprintf(str, "%u", m);
266 }
267
268 static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
269                                 struct seq_file *m)
270 {
271         struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
272         struct dev_exception_item *ex;
273         char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
274
275         rcu_read_lock();
276         /*
277          * To preserve the compatibility:
278          * - Only show the "all devices" when the default policy is to allow
279          * - List the exceptions in case the default policy is to deny
280          * This way, the file remains as a "whitelist of devices"
281          */
282         if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
283                 set_access(acc, ACC_MASK);
284                 set_majmin(maj, ~0);
285                 set_majmin(min, ~0);
286                 seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL),
287                            maj, min, acc);
288         } else {
289                 list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) {
290                         set_access(acc, ex->access);
291                         set_majmin(maj, ex->major);
292                         set_majmin(min, ex->minor);
293                         seq_printf(m, "%c %s:%s %s\n", type_to_char(ex->type),
294                                    maj, min, acc);
295                 }
296         }
297         rcu_read_unlock();
298
299         return 0;
300 }
301
302 /**
303  * may_access - verifies if a new exception is part of what is allowed
304  *              by a dev cgroup based on the default policy +
305  *              exceptions. This is used to make sure a child cgroup
306  *              won't have more privileges than its parent or to
307  *              verify if a certain access is allowed.
308  * @dev_cgroup: dev cgroup to be tested against
309  * @refex: new exception
310  * @behavior: behavior of the exception
311  */
312 static bool may_access(struct dev_cgroup *dev_cgroup,
313                        struct dev_exception_item *refex,
314                        enum devcg_behavior behavior)
315 {
316         struct dev_exception_item *ex;
317         bool match = false;
318
319         rcu_lockdep_assert(rcu_read_lock_held() ||
320                            lockdep_is_held(&devcgroup_mutex),
321                            "device_cgroup::may_access() called without proper synchronization");
322
323         list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
324                 if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
325                         continue;
326                 if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
327                         continue;
328                 if (ex->major != ~0 && ex->major != refex->major)
329                         continue;
330                 if (ex->minor != ~0 && ex->minor != refex->minor)
331                         continue;
332                 if (refex->access & (~ex->access))
333                         continue;
334                 match = true;
335                 break;
336         }
337
338         if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
339                 if (behavior == DEVCG_DEFAULT_ALLOW) {
340                         /* the exception will deny access to certain devices */
341                         return true;
342                 } else {
343                         /* the exception will allow access to certain devices */
344                         if (match)
345                                 /*
346                                  * a new exception allowing access shouldn't
347                                  * match an parent's exception
348                                  */
349                                 return false;
350                         return true;
351                 }
352         } else {
353                 /* only behavior == DEVCG_DEFAULT_DENY allowed here */
354                 if (match)
355                         /* parent has an exception that matches the proposed */
356                         return true;
357                 else
358                         return false;
359         }
360         return false;
361 }
362
363 /*
364  * parent_has_perm:
365  * when adding a new allow rule to a device exception list, the rule
366  * must be allowed in the parent device
367  */
368 static int parent_has_perm(struct dev_cgroup *childcg,
369                                   struct dev_exception_item *ex)
370 {
371         struct cgroup *pcg = childcg->css.cgroup->parent;
372         struct dev_cgroup *parent;
373
374         if (!pcg)
375                 return 1;
376         parent = cgroup_to_devcgroup(pcg);
377         return may_access(parent, ex, childcg->behavior);
378 }
379
380 /**
381  * may_allow_all - checks if it's possible to change the behavior to
382  *                 allow based on parent's rules.
383  * @parent: device cgroup's parent
384  * returns: != 0 in case it's allowed, 0 otherwise
385  */
386 static inline int may_allow_all(struct dev_cgroup *parent)
387 {
388         if (!parent)
389                 return 1;
390         return parent->behavior == DEVCG_DEFAULT_ALLOW;
391 }
392
393 /*
394  * Modify the exception list using allow/deny rules.
395  * CAP_SYS_ADMIN is needed for this.  It's at least separate from CAP_MKNOD
396  * so we can give a container CAP_MKNOD to let it create devices but not
397  * modify the exception list.
398  * It seems likely we'll want to add a CAP_CONTAINER capability to allow
399  * us to also grant CAP_SYS_ADMIN to containers without giving away the
400  * device exception list controls, but for now we'll stick with CAP_SYS_ADMIN
401  *
402  * Taking rules away is always allowed (given CAP_SYS_ADMIN).  Granting
403  * new access is only allowed if you're in the top-level cgroup, or your
404  * parent cgroup has the access you're asking for.
405  */
406 static int devcgroup_update_access(struct dev_cgroup *devcgroup,
407                                    int filetype, const char *buffer)
408 {
409         const char *b;
410         char temp[12];          /* 11 + 1 characters needed for a u32 */
411         int count, rc = 0;
412         struct dev_exception_item ex;
413         struct cgroup *p = devcgroup->css.cgroup;
414         struct dev_cgroup *parent = NULL;
415
416         if (!capable(CAP_SYS_ADMIN))
417                 return -EPERM;
418
419         if (p->parent)
420                 parent = cgroup_to_devcgroup(p->parent);
421
422         memset(&ex, 0, sizeof(ex));
423         b = buffer;
424
425         switch (*b) {
426         case 'a':
427                 switch (filetype) {
428                 case DEVCG_ALLOW:
429                         if (!may_allow_all(parent))
430                                 return -EPERM;
431                         dev_exception_clean(devcgroup);
432                         devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
433                         if (!parent)
434                                 break;
435
436                         rc = dev_exceptions_copy(&devcgroup->exceptions,
437                                                  &parent->exceptions);
438                         if (rc)
439                                 return rc;
440                         break;
441                 case DEVCG_DENY:
442                         dev_exception_clean(devcgroup);
443                         devcgroup->behavior = DEVCG_DEFAULT_DENY;
444                         break;
445                 default:
446                         return -EINVAL;
447                 }
448                 return 0;
449         case 'b':
450                 ex.type = DEV_BLOCK;
451                 break;
452         case 'c':
453                 ex.type = DEV_CHAR;
454                 break;
455         default:
456                 return -EINVAL;
457         }
458         b++;
459         if (!isspace(*b))
460                 return -EINVAL;
461         b++;
462         if (*b == '*') {
463                 ex.major = ~0;
464                 b++;
465         } else if (isdigit(*b)) {
466                 memset(temp, 0, sizeof(temp));
467                 for (count = 0; count < sizeof(temp) - 1; count++) {
468                         temp[count] = *b;
469                         b++;
470                         if (!isdigit(*b))
471                                 break;
472                 }
473                 rc = kstrtou32(temp, 10, &ex.major);
474                 if (rc)
475                         return -EINVAL;
476         } else {
477                 return -EINVAL;
478         }
479         if (*b != ':')
480                 return -EINVAL;
481         b++;
482
483         /* read minor */
484         if (*b == '*') {
485                 ex.minor = ~0;
486                 b++;
487         } else if (isdigit(*b)) {
488                 memset(temp, 0, sizeof(temp));
489                 for (count = 0; count < sizeof(temp) - 1; count++) {
490                         temp[count] = *b;
491                         b++;
492                         if (!isdigit(*b))
493                                 break;
494                 }
495                 rc = kstrtou32(temp, 10, &ex.minor);
496                 if (rc)
497                         return -EINVAL;
498         } else {
499                 return -EINVAL;
500         }
501         if (!isspace(*b))
502                 return -EINVAL;
503         for (b++, count = 0; count < 3; count++, b++) {
504                 switch (*b) {
505                 case 'r':
506                         ex.access |= ACC_READ;
507                         break;
508                 case 'w':
509                         ex.access |= ACC_WRITE;
510                         break;
511                 case 'm':
512                         ex.access |= ACC_MKNOD;
513                         break;
514                 case '\n':
515                 case '\0':
516                         count = 3;
517                         break;
518                 default:
519                         return -EINVAL;
520                 }
521         }
522
523         switch (filetype) {
524         case DEVCG_ALLOW:
525                 if (!parent_has_perm(devcgroup, &ex))
526                         return -EPERM;
527                 /*
528                  * If the default policy is to allow by default, try to remove
529                  * an matching exception instead. And be silent about it: we
530                  * don't want to break compatibility
531                  */
532                 if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) {
533                         dev_exception_rm(devcgroup, &ex);
534                         return 0;
535                 }
536                 return dev_exception_add(devcgroup, &ex);
537         case DEVCG_DENY:
538                 /*
539                  * If the default policy is to deny by default, try to remove
540                  * an matching exception instead. And be silent about it: we
541                  * don't want to break compatibility
542                  */
543                 if (devcgroup->behavior == DEVCG_DEFAULT_DENY) {
544                         dev_exception_rm(devcgroup, &ex);
545                         return 0;
546                 }
547                 return dev_exception_add(devcgroup, &ex);
548         default:
549                 return -EINVAL;
550         }
551         return 0;
552 }
553
554 static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
555                                   const char *buffer)
556 {
557         int retval;
558
559         mutex_lock(&devcgroup_mutex);
560         retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
561                                          cft->private, buffer);
562         mutex_unlock(&devcgroup_mutex);
563         return retval;
564 }
565
566 static struct cftype dev_cgroup_files[] = {
567         {
568                 .name = "allow",
569                 .write_string  = devcgroup_access_write,
570                 .private = DEVCG_ALLOW,
571         },
572         {
573                 .name = "deny",
574                 .write_string = devcgroup_access_write,
575                 .private = DEVCG_DENY,
576         },
577         {
578                 .name = "list",
579                 .read_seq_string = devcgroup_seq_read,
580                 .private = DEVCG_LIST,
581         },
582         { }     /* terminate */
583 };
584
585 struct cgroup_subsys devices_subsys = {
586         .name = "devices",
587         .can_attach = devcgroup_can_attach,
588         .css_alloc = devcgroup_css_alloc,
589         .css_free = devcgroup_css_free,
590         .subsys_id = devices_subsys_id,
591         .base_cftypes = dev_cgroup_files,
592
593         /*
594          * While devices cgroup has the rudimentary hierarchy support which
595          * checks the parent's restriction, it doesn't properly propagates
596          * config changes in ancestors to their descendents.  A child
597          * should only be allowed to add more restrictions to the parent's
598          * configuration.  Fix it and remove the following.
599          */
600         .broken_hierarchy = true,
601 };
602
603 /**
604  * __devcgroup_check_permission - checks if an inode operation is permitted
605  * @dev_cgroup: the dev cgroup to be tested against
606  * @type: device type
607  * @major: device major number
608  * @minor: device minor number
609  * @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD
610  *
611  * returns 0 on success, -EPERM case the operation is not permitted
612  */
613 static int __devcgroup_check_permission(short type, u32 major, u32 minor,
614                                         short access)
615 {
616         struct dev_cgroup *dev_cgroup;
617         struct dev_exception_item ex;
618         int rc;
619
620         memset(&ex, 0, sizeof(ex));
621         ex.type = type;
622         ex.major = major;
623         ex.minor = minor;
624         ex.access = access;
625
626         rcu_read_lock();
627         dev_cgroup = task_devcgroup(current);
628         rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior);
629         rcu_read_unlock();
630
631         if (!rc)
632                 return -EPERM;
633
634         return 0;
635 }
636
637 int __devcgroup_inode_permission(struct inode *inode, int mask)
638 {
639         short type, access = 0;
640
641         if (S_ISBLK(inode->i_mode))
642                 type = DEV_BLOCK;
643         if (S_ISCHR(inode->i_mode))
644                 type = DEV_CHAR;
645         if (mask & MAY_WRITE)
646                 access |= ACC_WRITE;
647         if (mask & MAY_READ)
648                 access |= ACC_READ;
649
650         return __devcgroup_check_permission(type, imajor(inode), iminor(inode),
651                         access);
652 }
653
654 int devcgroup_inode_mknod(int mode, dev_t dev)
655 {
656         short type;
657
658         if (!S_ISBLK(mode) && !S_ISCHR(mode))
659                 return 0;
660
661         if (S_ISBLK(mode))
662                 type = DEV_BLOCK;
663         else
664                 type = DEV_CHAR;
665
666         return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev),
667                         ACC_MKNOD);
668
669 }