Skip to content

Commit

Permalink
cgroup: newly created dirs and files should be owned by the creator
Browse files Browse the repository at this point in the history
While converting cgroup to kernfs, 2bd59d4 ("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>
  • Loading branch information
Tejun Heo committed Apr 7, 2014
1 parent c6b3d5b commit 49957f8
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2346,19 +2346,40 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent,
return ret;
}

/* set uid and gid of cgroup dirs and files to that of the creator */
static int cgroup_kn_set_ugid(struct kernfs_node *kn)
{
struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
.ia_uid = current_fsuid(),
.ia_gid = current_fsgid(), };

if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
return 0;

return kernfs_setattr(kn, &iattr);
}

static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
{
char name[CGROUP_FILE_NAME_MAX];
struct kernfs_node *kn;
struct lock_class_key *key = NULL;
int ret;

#ifdef CONFIG_DEBUG_LOCK_ALLOC
key = &cft->lockdep_key;
#endif
kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
cgroup_file_mode(cft), 0, cft->kf_ops, cft,
NULL, false, key);
return PTR_ERR_OR_ZERO(kn);
if (IS_ERR(kn))
return PTR_ERR(kn);

ret = cgroup_kn_set_ugid(kn);
if (ret)
kernfs_remove(kn);
return ret;
}

/**
Expand Down Expand Up @@ -3753,6 +3774,10 @@ static long cgroup_create(struct cgroup *parent, const char *name,
*/
idr_replace(&root->cgroup_idr, cgrp, cgrp->id);

err = cgroup_kn_set_ugid(kn);
if (err)
goto err_destroy;

err = cgroup_addrm_files(cgrp, cgroup_base_files, true);
if (err)
goto err_destroy;
Expand Down

0 comments on commit 49957f8

Please sign in to comment.