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
6878 sch->ops = *cmd->ops;6878 sch->ops = *cmd->ops;
6879 }6879 }
6880 6880
6881 rcu_assign_pointer(ops->priv, sch);
6882
6883 sch->kobj.kset = scx_kset;
6884 INIT_LIST_HEAD(&sch->all);
6885
6886#ifdef CONFIG_EXT_SUB_SCHED6881#ifdef CONFIG_EXT_SUB_SCHED
6887 char *buf = kzalloc(PATH_MAX, GFP_KERNEL);6882 char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
6888 if (!buf) {6883 if (!buf) {
@@ -6900,7 +6895,19 @@ static struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 11 unmodified lines
6900 sch->cgrp = cgrp;6895 sch->cgrp = cgrp;
6901 INIT_LIST_HEAD(&sch->children);6896 INIT_LIST_HEAD(&sch->children);
6902 INIT_LIST_HEAD(&sch->sibling);6897 INIT_LIST_HEAD(&sch->sibling);
6898#endif /* CONFIG_EXT_SUB_SCHED */
6903 6899
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
6904 if (parent) {6911 if (parent) {
6905 /*6912 /*
6906 * Pin @parent for @sch's lifetime. The kobject hierarchy pins6913 * 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
6955 6962
6956#ifdef CONFIG_EXT_SUB_SCHED6963#ifdef CONFIG_EXT_SUB_SCHED
6957err_free_lb_resched:6964err_free_lb_resched:
6958 RCU_INIT_POINTER(ops->priv, NULL);
6959 free_cpumask_var(sch->bypass_lb_resched_cpumask);6965 free_cpumask_var(sch->bypass_lb_resched_cpumask);
6960#endif6966#endif
6961err_free_lb_cpumask:6967err_free_lb_cpumask: