]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sched_ext: Fix premature ops->priv publication in scx_alloc_and_add_sched()
authorTejun Heo <tj@kernel.org>
Thu, 9 Jul 2026 21:08:22 +0000 (11:08 -1000)
committerTejun Heo <tj@kernel.org>
Thu, 9 Jul 2026 21:08:22 +0000 (11:08 -1000)
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.

Fixes: 105dcd005be2 ("sched_ext: Introduce scx_prog_sched()")
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
kernel/sched/ext/ext.c

index 40cef77394ac42f090de1aa48ff9e658b10238e5..aeee44e016abbed6e25d9e5e608b19eed43258e1 100644 (file)
@@ -6878,11 +6878,6 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
                sch->ops = *cmd->ops;
        }
 
-       rcu_assign_pointer(ops->priv, sch);
-
-       sch->kobj.kset = scx_kset;
-       INIT_LIST_HEAD(&sch->all);
-
 #ifdef CONFIG_EXT_SUB_SCHED
        char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
        if (!buf) {
@@ -6900,7 +6895,19 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd,
        sch->cgrp = cgrp;
        INIT_LIST_HEAD(&sch->children);
        INIT_LIST_HEAD(&sch->sibling);
+#endif /* CONFIG_EXT_SUB_SCHED */
 
+       /*
+        * Publishing makes @sch visible to scx_prog_sched() readers. Failure
+        * paths after this point must free @sch through kobject_put() whose
+        * release path defers the actual freeing by an RCU grace period.
+        */
+       rcu_assign_pointer(ops->priv, sch);
+
+       sch->kobj.kset = scx_kset;
+       INIT_LIST_HEAD(&sch->all);
+
+#ifdef CONFIG_EXT_SUB_SCHED
        if (parent) {
                /*
                 * 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,
 
 #ifdef CONFIG_EXT_SUB_SCHED
 err_free_lb_resched:
-       RCU_INIT_POINTER(ops->priv, NULL);
        free_cpumask_var(sch->bypass_lb_resched_cpumask);
 #endif
 err_free_lb_cpumask: