Merge branch 'for-5.17-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup fixes from Tejun Heo: - Eric's fix for a long standing cgroup1 permission issue where it only checks for uid 0 instead of CAP which inadvertently allows unprivileged userns roots to modify release_agent userhelper - Fixes for the fallout from Waiman's recent cpuset work * 'for-5.17-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: cgroup/cpuset: Fix "suspicious RCU usage" lockdep warning cgroup-v1: Require capabilities to set release_agent cpuset: Fix the bug that subpart_cpus updated wrongly in update_cpumask() cgroup/cpuset: Make child cpusets restrict parents on v1 hierarchy
This commit is contained in:
commit
305e6c42e8
@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
|
||||
|
||||
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
|
||||
|
||||
/*
|
||||
* Release agent gets called with all capabilities,
|
||||
* require capabilities to set release agent.
|
||||
*/
|
||||
if ((of->file->f_cred->user_ns != &init_user_ns) ||
|
||||
!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
cgrp = cgroup_kn_lock_live(of->kn, false);
|
||||
if (!cgrp)
|
||||
return -ENODEV;
|
||||
@ -954,6 +962,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
/* Specifying two release agents is forbidden */
|
||||
if (ctx->release_agent)
|
||||
return invalfc(fc, "release_agent respecified");
|
||||
/*
|
||||
* Release agent gets called with all capabilities,
|
||||
* require capabilities to set release agent.
|
||||
*/
|
||||
if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
|
||||
return invalfc(fc, "Setting release_agent not allowed");
|
||||
ctx->release_agent = param->string;
|
||||
param->string = NULL;
|
||||
break;
|
||||
|
@ -590,6 +590,35 @@ static inline void free_cpuset(struct cpuset *cs)
|
||||
kfree(cs);
|
||||
}
|
||||
|
||||
/*
|
||||
* validate_change_legacy() - Validate conditions specific to legacy (v1)
|
||||
* behavior.
|
||||
*/
|
||||
static int validate_change_legacy(struct cpuset *cur, struct cpuset *trial)
|
||||
{
|
||||
struct cgroup_subsys_state *css;
|
||||
struct cpuset *c, *par;
|
||||
int ret;
|
||||
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
|
||||
/* Each of our child cpusets must be a subset of us */
|
||||
ret = -EBUSY;
|
||||
cpuset_for_each_child(c, css, cur)
|
||||
if (!is_cpuset_subset(c, trial))
|
||||
goto out;
|
||||
|
||||
/* On legacy hierarchy, we must be a subset of our parent cpuset. */
|
||||
ret = -EACCES;
|
||||
par = parent_cs(cur);
|
||||
if (par && !is_cpuset_subset(trial, par))
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* validate_change() - Used to validate that any proposed cpuset change
|
||||
* follows the structural rules for cpusets.
|
||||
@ -614,20 +643,21 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
|
||||
{
|
||||
struct cgroup_subsys_state *css;
|
||||
struct cpuset *c, *par;
|
||||
int ret;
|
||||
|
||||
/* The checks don't apply to root cpuset */
|
||||
if (cur == &top_cpuset)
|
||||
return 0;
|
||||
int ret = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
par = parent_cs(cur);
|
||||
|
||||
/* On legacy hierarchy, we must be a subset of our parent cpuset. */
|
||||
ret = -EACCES;
|
||||
if (!is_in_v2_mode() && !is_cpuset_subset(trial, par))
|
||||
if (!is_in_v2_mode())
|
||||
ret = validate_change_legacy(cur, trial);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Remaining checks don't apply to root cpuset */
|
||||
if (cur == &top_cpuset)
|
||||
goto out;
|
||||
|
||||
par = parent_cs(cur);
|
||||
|
||||
/*
|
||||
* If either I or some sibling (!= me) is exclusive, we can't
|
||||
* overlap
|
||||
@ -1175,9 +1205,7 @@ enum subparts_cmd {
|
||||
*
|
||||
* Because of the implicit cpu exclusive nature of a partition root,
|
||||
* cpumask changes that violates the cpu exclusivity rule will not be
|
||||
* permitted when checked by validate_change(). The validate_change()
|
||||
* function will also prevent any changes to the cpu list if it is not
|
||||
* a superset of children's cpu lists.
|
||||
* permitted when checked by validate_change().
|
||||
*/
|
||||
static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
|
||||
struct cpumask *newmask,
|
||||
@ -1522,10 +1550,15 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
|
||||
struct cpuset *sibling;
|
||||
struct cgroup_subsys_state *pos_css;
|
||||
|
||||
percpu_rwsem_assert_held(&cpuset_rwsem);
|
||||
|
||||
/*
|
||||
* Check all its siblings and call update_cpumasks_hier()
|
||||
* if their use_parent_ecpus flag is set in order for them
|
||||
* to use the right effective_cpus value.
|
||||
*
|
||||
* The update_cpumasks_hier() function may sleep. So we have to
|
||||
* release the RCU read lock before calling it.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
cpuset_for_each_child(sibling, pos_css, parent) {
|
||||
@ -1533,8 +1566,13 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
|
||||
continue;
|
||||
if (!sibling->use_parent_ecpus)
|
||||
continue;
|
||||
if (!css_tryget_online(&sibling->css))
|
||||
continue;
|
||||
|
||||
rcu_read_unlock();
|
||||
update_cpumasks_hier(sibling, tmp);
|
||||
rcu_read_lock();
|
||||
css_put(&sibling->css);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
@ -1607,8 +1645,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
* Make sure that subparts_cpus is a subset of cpus_allowed.
|
||||
*/
|
||||
if (cs->nr_subparts_cpus) {
|
||||
cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
|
||||
cs->cpus_allowed);
|
||||
cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
|
||||
cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
|
||||
}
|
||||
spin_unlock_irq(&callback_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user