Skip to content

Commit 305e6c4

Browse files
committed
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
2 parents c36c04c + 2bdfd28 commit 305e6c4

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

kernel/cgroup/cgroup-v1.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,14 @@ static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of,
549549

550550
BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
551551

552+
/*
553+
* Release agent gets called with all capabilities,
554+
* require capabilities to set release agent.
555+
*/
556+
if ((of->file->f_cred->user_ns != &init_user_ns) ||
557+
!capable(CAP_SYS_ADMIN))
558+
return -EPERM;
559+
552560
cgrp = cgroup_kn_lock_live(of->kn, false);
553561
if (!cgrp)
554562
return -ENODEV;
@@ -954,6 +962,12 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
954962
/* Specifying two release agents is forbidden */
955963
if (ctx->release_agent)
956964
return invalfc(fc, "release_agent respecified");
965+
/*
966+
* Release agent gets called with all capabilities,
967+
* require capabilities to set release agent.
968+
*/
969+
if ((fc->user_ns != &init_user_ns) || !capable(CAP_SYS_ADMIN))
970+
return invalfc(fc, "Setting release_agent not allowed");
957971
ctx->release_agent = param->string;
958972
param->string = NULL;
959973
break;

kernel/cgroup/cpuset.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,35 @@ static inline void free_cpuset(struct cpuset *cs)
590590
kfree(cs);
591591
}
592592

593+
/*
594+
* validate_change_legacy() - Validate conditions specific to legacy (v1)
595+
* behavior.
596+
*/
597+
static int validate_change_legacy(struct cpuset *cur, struct cpuset *trial)
598+
{
599+
struct cgroup_subsys_state *css;
600+
struct cpuset *c, *par;
601+
int ret;
602+
603+
WARN_ON_ONCE(!rcu_read_lock_held());
604+
605+
/* Each of our child cpusets must be a subset of us */
606+
ret = -EBUSY;
607+
cpuset_for_each_child(c, css, cur)
608+
if (!is_cpuset_subset(c, trial))
609+
goto out;
610+
611+
/* On legacy hierarchy, we must be a subset of our parent cpuset. */
612+
ret = -EACCES;
613+
par = parent_cs(cur);
614+
if (par && !is_cpuset_subset(trial, par))
615+
goto out;
616+
617+
ret = 0;
618+
out:
619+
return ret;
620+
}
621+
593622
/*
594623
* validate_change() - Used to validate that any proposed cpuset change
595624
* follows the structural rules for cpusets.
@@ -614,20 +643,21 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
614643
{
615644
struct cgroup_subsys_state *css;
616645
struct cpuset *c, *par;
617-
int ret;
618-
619-
/* The checks don't apply to root cpuset */
620-
if (cur == &top_cpuset)
621-
return 0;
646+
int ret = 0;
622647

623648
rcu_read_lock();
624-
par = parent_cs(cur);
625649

626-
/* On legacy hierarchy, we must be a subset of our parent cpuset. */
627-
ret = -EACCES;
628-
if (!is_in_v2_mode() && !is_cpuset_subset(trial, par))
650+
if (!is_in_v2_mode())
651+
ret = validate_change_legacy(cur, trial);
652+
if (ret)
653+
goto out;
654+
655+
/* Remaining checks don't apply to root cpuset */
656+
if (cur == &top_cpuset)
629657
goto out;
630658

659+
par = parent_cs(cur);
660+
631661
/*
632662
* If either I or some sibling (!= me) is exclusive, we can't
633663
* overlap
@@ -1175,9 +1205,7 @@ enum subparts_cmd {
11751205
*
11761206
* Because of the implicit cpu exclusive nature of a partition root,
11771207
* cpumask changes that violates the cpu exclusivity rule will not be
1178-
* permitted when checked by validate_change(). The validate_change()
1179-
* function will also prevent any changes to the cpu list if it is not
1180-
* a superset of children's cpu lists.
1208+
* permitted when checked by validate_change().
11811209
*/
11821210
static int update_parent_subparts_cpumask(struct cpuset *cpuset, int cmd,
11831211
struct cpumask *newmask,
@@ -1522,19 +1550,29 @@ static void update_sibling_cpumasks(struct cpuset *parent, struct cpuset *cs,
15221550
struct cpuset *sibling;
15231551
struct cgroup_subsys_state *pos_css;
15241552

1553+
percpu_rwsem_assert_held(&cpuset_rwsem);
1554+
15251555
/*
15261556
* Check all its siblings and call update_cpumasks_hier()
15271557
* if their use_parent_ecpus flag is set in order for them
15281558
* to use the right effective_cpus value.
1559+
*
1560+
* The update_cpumasks_hier() function may sleep. So we have to
1561+
* release the RCU read lock before calling it.
15291562
*/
15301563
rcu_read_lock();
15311564
cpuset_for_each_child(sibling, pos_css, parent) {
15321565
if (sibling == cs)
15331566
continue;
15341567
if (!sibling->use_parent_ecpus)
15351568
continue;
1569+
if (!css_tryget_online(&sibling->css))
1570+
continue;
15361571

1572+
rcu_read_unlock();
15371573
update_cpumasks_hier(sibling, tmp);
1574+
rcu_read_lock();
1575+
css_put(&sibling->css);
15381576
}
15391577
rcu_read_unlock();
15401578
}
@@ -1607,8 +1645,7 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
16071645
* Make sure that subparts_cpus is a subset of cpus_allowed.
16081646
*/
16091647
if (cs->nr_subparts_cpus) {
1610-
cpumask_andnot(cs->subparts_cpus, cs->subparts_cpus,
1611-
cs->cpus_allowed);
1648+
cpumask_and(cs->subparts_cpus, cs->subparts_cpus, cs->cpus_allowed);
16121649
cs->nr_subparts_cpus = cpumask_weight(cs->subparts_cpus);
16131650
}
16141651
spin_unlock_irq(&callback_lock);

0 commit comments

Comments
 (0)