device_cgroup: add "deny_all" in dev_cgroup structure
[platform/adaptation/renesas_rcar/renesas_kernel.git] / security / device_cgroup.c
index 442204c..e3ce02a 100644 (file)
@@ -42,6 +42,7 @@ struct dev_whitelist_item {
 struct dev_cgroup {
        struct cgroup_subsys_state css;
        struct list_head whitelist;
+       bool deny_all;
 };
 
 static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -178,12 +179,14 @@ static struct cgroup_subsys_state *devcgroup_create(struct cgroup *cgroup)
                wh->minor = wh->major = ~0;
                wh->type = DEV_ALL;
                wh->access = ACC_MASK;
+               dev_cgroup->deny_all = false;
                list_add(&wh->list, &dev_cgroup->whitelist);
        } else {
                parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
                mutex_lock(&devcgroup_mutex);
                ret = dev_whitelist_copy(&dev_cgroup->whitelist,
                                &parent_dev_cgroup->whitelist);
+               dev_cgroup->deny_all = parent_dev_cgroup->deny_all;
                mutex_unlock(&devcgroup_mutex);
                if (ret) {
                        kfree(dev_cgroup);
@@ -409,9 +412,11 @@ handle:
        case DEVCG_ALLOW:
                if (!parent_has_perm(devcgroup, &wh))
                        return -EPERM;
+               devcgroup->deny_all = false;
                return dev_whitelist_add(devcgroup, &wh);
        case DEVCG_DENY:
                dev_whitelist_rm(devcgroup, &wh);
+               devcgroup->deny_all = true;
                break;
        default:
                return -EINVAL;
@@ -457,6 +462,15 @@ struct cgroup_subsys devices_subsys = {
        .destroy = devcgroup_destroy,
        .subsys_id = devices_subsys_id,
        .base_cftypes = dev_cgroup_files,
+
+       /*
+        * While devices cgroup has the rudimentary hierarchy support which
+        * checks the parent's restriction, it doesn't properly propagates
+        * config changes in ancestors to their descendents.  A child
+        * should only be allowed to add more restrictions to the parent's
+        * configuration.  Fix it and remove the following.
+        */
+       .broken_hierarchy = true,
 };
 
 int __devcgroup_inode_permission(struct inode *inode, int mask)