ARM64: rockchip_defconfig: enable sdhci controller
[firefly-linux-kernel-4.4.55.git] / kernel / cgroup.c
index 470f6536b9e8cfb029eedb5ecdb3c3e8c3c341be..a57b7c86871ca969f16f31142d10d3746c8c284b 100644 (file)
@@ -2663,6 +2663,45 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp,
        return ret;
 }
 
+int subsys_cgroup_allow_attach(struct cgroup_taskset *tset)
+{
+       const struct cred *cred = current_cred(), *tcred;
+       struct task_struct *task;
+       struct cgroup_subsys_state *css;
+
+       if (capable(CAP_SYS_NICE))
+               return 0;
+
+       cgroup_taskset_for_each(task, css, tset) {
+               tcred = __task_cred(task);
+
+               if (current != task && !uid_eq(cred->euid, tcred->uid) &&
+                   !uid_eq(cred->euid, tcred->suid))
+                       return -EACCES;
+       }
+
+       return 0;
+}
+
+static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+{
+       struct cgroup_subsys_state *css;
+       int i;
+       int ret;
+
+       for_each_css(css, i, cgrp) {
+               if (css->ss->allow_attach) {
+                       ret = css->ss->allow_attach(tset);
+                       if (ret)
+                               return ret;
+               } else {
+                       return -EACCES;
+               }
+       }
+
+       return 0;
+}
+
 static int cgroup_procs_write_permission(struct task_struct *task,
                                         struct cgroup *dst_cgrp,
                                         struct kernfs_open_file *of)
@@ -2677,8 +2716,24 @@ static int cgroup_procs_write_permission(struct task_struct *task,
         */
        if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
            !uid_eq(cred->euid, tcred->uid) &&
-           !uid_eq(cred->euid, tcred->suid))
-               ret = -EACCES;
+           !uid_eq(cred->euid, tcred->suid)) {
+               /*
+                * if the default permission check fails, give each
+                * cgroup a chance to extend the permission check
+                */
+               struct cgroup_taskset tset = {
+                       .src_csets = LIST_HEAD_INIT(tset.src_csets),
+                       .dst_csets = LIST_HEAD_INIT(tset.dst_csets),
+                       .csets = &tset.src_csets,
+               };
+               struct css_set *cset;
+               cset = task_css_set(task);
+               list_add(&cset->mg_node, &tset.src_csets);
+               ret = cgroup_allow_attach(dst_cgrp, &tset);
+               list_del(&tset.src_csets);
+               if (ret)
+                       ret = -EACCES;
+       }
 
        if (!ret && cgroup_on_dfl(dst_cgrp)) {
                struct super_block *sb = of->file->f_path.dentry->d_sb;