aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-06-18 16:54:28 -0400
committerTejun Heo <tj@kernel.org>2015-06-18 16:54:28 -0400
commitdedf22e9e66ef3fbefd1b8c750d2db11b690ade3 (patch)
treedf98e0293fb57ab616f700cf56681023a57d5435 /kernel/cgroup.c
parentfb02915f47181e824339d91f8e385fd4bd746d6a (diff)
cgroup: separate out cgroup_procs_write_permission() from __cgroup_procs_write()
Separate out task / process migration permission check from __cgroup_procs_write() into cgroup_procs_write_permission(). * Permission check is moved right above the actual migration and no longer performed while holding rcu_read_lock(). cgroup_procs_write_permission() uses get_task_cred() / put_cred() instead of __task_cred(). Also, !root trying to migrate kthreadd or PF_NO_SETAFFINITY tasks will now fail with -EINVAL rather than -EACCES which should be fine. * The same permission check is now performed even when moving self by specifying 0 as pid. This always succeeds so there's no functional difference. We'll add more permission checks later and the benefits of keeping both cases consistent outweigh the minute overhead of doing perm checks on pid 0 case. Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 12b580f4338e..4504d64f91e1 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2392,6 +2392,25 @@ static int cgroup_attach_task(struct cgroup *dst_cgrp,
2392 return ret; 2392 return ret;
2393} 2393}
2394 2394
2395static int cgroup_procs_write_permission(struct task_struct *task)
2396{
2397 const struct cred *cred = current_cred();
2398 const struct cred *tcred = get_task_cred(task);
2399 int ret = 0;
2400
2401 /*
2402 * even if we're attaching all tasks in the thread group, we only
2403 * need to check permissions on one of them.
2404 */
2405 if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
2406 !uid_eq(cred->euid, tcred->uid) &&
2407 !uid_eq(cred->euid, tcred->suid))
2408 ret = -EACCES;
2409
2410 put_cred(tcred);
2411 return ret;
2412}
2413
2395/* 2414/*
2396 * Find the task_struct of the task to attach by vpid and pass it along to the 2415 * Find the task_struct of the task to attach by vpid and pass it along to the
2397 * function to attach either it or all tasks in its threadgroup. Will lock 2416 * function to attach either it or all tasks in its threadgroup. Will lock
@@ -2401,7 +2420,6 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2401 size_t nbytes, loff_t off, bool threadgroup) 2420 size_t nbytes, loff_t off, bool threadgroup)
2402{ 2421{
2403 struct task_struct *tsk; 2422 struct task_struct *tsk;
2404 const struct cred *cred = current_cred(), *tcred;
2405 struct cgroup *cgrp; 2423 struct cgroup *cgrp;
2406 pid_t pid; 2424 pid_t pid;
2407 int ret; 2425 int ret;
@@ -2421,19 +2439,9 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2421 ret = -ESRCH; 2439 ret = -ESRCH;
2422 goto out_unlock_rcu; 2440 goto out_unlock_rcu;
2423 } 2441 }
2424 /* 2442 } else {
2425 * even if we're attaching all tasks in the thread group, we
2426 * only need to check permissions on one of them.
2427 */
2428 tcred = __task_cred(tsk);
2429 if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
2430 !uid_eq(cred->euid, tcred->uid) &&
2431 !uid_eq(cred->euid, tcred->suid)) {
2432 ret = -EACCES;
2433 goto out_unlock_rcu;
2434 }
2435 } else
2436 tsk = current; 2443 tsk = current;
2444 }
2437 2445
2438 if (threadgroup) 2446 if (threadgroup)
2439 tsk = tsk->group_leader; 2447 tsk = tsk->group_leader;
@@ -2451,7 +2459,9 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
2451 get_task_struct(tsk); 2459 get_task_struct(tsk);
2452 rcu_read_unlock(); 2460 rcu_read_unlock();
2453 2461
2454 ret = cgroup_attach_task(cgrp, tsk, threadgroup); 2462 ret = cgroup_procs_write_permission(tsk);
2463 if (!ret)
2464 ret = cgroup_attach_task(cgrp, tsk, threadgroup);
2455 2465
2456 put_task_struct(tsk); 2466 put_task_struct(tsk);
2457 goto out_unlock_threadgroup; 2467 goto out_unlock_threadgroup;