aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-04-07 16:44:47 -0400
committerTejun Heo <tj@kernel.org>2014-04-07 16:44:47 -0400
commit49957f8e2a43035a97d05bddefa394492a969c0d (patch)
tree853fb807131438d7fb497d9fbc8e09d0c8efe4a8 /kernel
parentc6b3d5bcd67c75961a1e8b9564d1475c0f194a84 (diff)
cgroup: newly created dirs and files should be owned by the creator
While converting cgroup to kernfs, 2bd59d48ebfb ("cgroup: convert to kernfs") accidentally dropped the logic which makes newly created cgroup dirs and files owned by the current uid / gid. This broke cases where cgroup subtree management is delegated to !root as the sub manager wouldn't be able to create more than single level of hierarchy or put tasks into child cgroups it created. Among other things, this breaks user session management in systemd and one of the symptoms was 90s hang during shutdown. User session systemd running as the user creates a sub-service to initiate shutdown and tries to put kill(1) into it but fails because cgroup.procs is owned by root. This leads to 90s hang during shutdown. Implement cgroup_kn_set_ugid() which sets a kn's uid and gid to those of the caller and use it from file and dir creation paths. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 0dfc7324c789..9fcdaa705b6c 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2346,11 +2346,26 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent,
2346 return ret; 2346 return ret;
2347} 2347}
2348 2348
2349/* set uid and gid of cgroup dirs and files to that of the creator */
2350static int cgroup_kn_set_ugid(struct kernfs_node *kn)
2351{
2352 struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
2353 .ia_uid = current_fsuid(),
2354 .ia_gid = current_fsgid(), };
2355
2356 if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
2357 gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
2358 return 0;
2359
2360 return kernfs_setattr(kn, &iattr);
2361}
2362
2349static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft) 2363static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
2350{ 2364{
2351 char name[CGROUP_FILE_NAME_MAX]; 2365 char name[CGROUP_FILE_NAME_MAX];
2352 struct kernfs_node *kn; 2366 struct kernfs_node *kn;
2353 struct lock_class_key *key = NULL; 2367 struct lock_class_key *key = NULL;
2368 int ret;
2354 2369
2355#ifdef CONFIG_DEBUG_LOCK_ALLOC 2370#ifdef CONFIG_DEBUG_LOCK_ALLOC
2356 key = &cft->lockdep_key; 2371 key = &cft->lockdep_key;
@@ -2358,7 +2373,13 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
2358 kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name), 2373 kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
2359 cgroup_file_mode(cft), 0, cft->kf_ops, cft, 2374 cgroup_file_mode(cft), 0, cft->kf_ops, cft,
2360 NULL, false, key); 2375 NULL, false, key);
2361 return PTR_ERR_OR_ZERO(kn); 2376 if (IS_ERR(kn))
2377 return PTR_ERR(kn);
2378
2379 ret = cgroup_kn_set_ugid(kn);
2380 if (ret)
2381 kernfs_remove(kn);
2382 return ret;
2362} 2383}
2363 2384
2364/** 2385/**
@@ -3753,6 +3774,10 @@ static long cgroup_create(struct cgroup *parent, const char *name,
3753 */ 3774 */
3754 idr_replace(&root->cgroup_idr, cgrp, cgrp->id); 3775 idr_replace(&root->cgroup_idr, cgrp, cgrp->id);
3755 3776
3777 err = cgroup_kn_set_ugid(kn);
3778 if (err)
3779 goto err_destroy;
3780
3756 err = cgroup_addrm_files(cgrp, cgroup_base_files, true); 3781 err = cgroup_addrm_files(cgrp, cgroup_base_files, true);
3757 if (err) 3782 if (err)
3758 goto err_destroy; 3783 goto err_destroy;