History

sched_ext: Fix premature ops->priv publication in scx_alloc_and_add_sched()

scx_alloc_and_add_sched() publishes @sch through ops->priv before allocating the cgroup path. If that allocation fails, the unwind path clears ops->priv and frees @sch immediately. scx_prog_sched() callers can dereference ops->priv from RCU context the moment it is set, so freeing without a grace period can use-after-free a concurrent kfunc caller. Move the publication below the cgroup path allocation so that every failure path after publication frees @sch through kobject_put(), whose release path defers the freeing by a grace period.

Tejun Heo committed 4 months ago

Commit 49b33781 parent db4e9de1 file · +12 −6Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/sched/ext/ext.c+12−6
@@ -6878,11 +6878,6 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 6877 unmodified lines
68786878 sch->ops = *cmd->ops;
68796879 }
68806880
6881− rcu_assign_pointer(ops->priv, sch);
6882−
6883− sch->kobj.kset = scx_kset;
6884− INIT_LIST_HEAD(&sch->all);
6885−
68866881 #ifdef CONFIG_EXT_SUB_SCHED
68876882 char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
68886883 if (!buf) {
@@ -6900,7 +6895,19 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 11 unmodified lines
69006895 sch->cgrp = cgrp;
69016896 INIT_LIST_HEAD(&sch->children);
69026897 INIT_LIST_HEAD(&sch->sibling);
6898+#endif /* CONFIG_EXT_SUB_SCHED */
69036899
6900+ /*
6901+ * Publishing makes @sch visible to scx_prog_sched() readers. Failure
6902+ * paths after this point must free @sch through kobject_put() whose
6903+ * release path defers the actual freeing by an RCU grace period.
6904+ */
6905+ rcu_assign_pointer(ops->priv, sch);
6906+
6907+ sch->kobj.kset = scx_kset;
6908+ INIT_LIST_HEAD(&sch->all);
6909+
6910+#ifdef CONFIG_EXT_SUB_SCHED
69046911 if (parent) {
69056912 /*
69066913 * Pin @parent for @sch's lifetime. The kobject hierarchy pins
@@ -6955,7 +6962,6 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 48 unmodified lines
69556962
69566963 #ifdef CONFIG_EXT_SUB_SCHED
69576964 err_free_lb_resched:
6958− RCU_INIT_POINTER(ops->priv, NULL);
69596965 free_cpumask_var(sch->bypass_lb_resched_cpumask);
69606966 #endif
69616967 err_free_lb_cpumask: