Merge branch 'for-7.1-fixes' into for-7.2

Pull to receive:

 2d2b026c3e ("sched_ext: Deny SCX kfuncs to non-SCX struct_ops programs")

which modifies scx_kfunc_context_filter() to avoid conflicts with planned
changes in for-7.2.

Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Tejun Heo 2026-04-20 09:33:34 -10:00
commit 463a4436d6
6 changed files with 112 additions and 14 deletions

View File

@ -9625,6 +9625,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_any)
static const struct btf_kfunc_id_set scx_kfunc_set_any = {
.owner = THIS_MODULE,
.set = &scx_kfunc_ids_any,
.filter = scx_kfunc_context_filter,
};
/*
@ -9672,13 +9673,12 @@ static const u32 scx_kf_allow_flags[] = {
};
/*
* Verifier-time filter for context-sensitive SCX kfuncs. Registered via the
* .filter field on each per-group btf_kfunc_id_set. The BPF core invokes this
* for every kfunc call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or
* Verifier-time filter for SCX kfuncs. Registered via the .filter field on
* each per-group btf_kfunc_id_set. The BPF core invokes this for every kfunc
* call in the registered hook (BPF_PROG_TYPE_STRUCT_OPS or
* BPF_PROG_TYPE_SYSCALL), regardless of which set originally introduced the
* kfunc - so the filter must short-circuit on kfuncs it doesn't govern (e.g.
* scx_kfunc_ids_any) by falling through to "allow" when none of the
* context-sensitive sets contain the kfunc.
* kfunc - so the filter must short-circuit on kfuncs it doesn't govern by
* falling through to "allow" when none of the SCX sets contain the kfunc.
*/
int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
{
@ -9687,18 +9687,21 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
bool in_enqueue = btf_id_set8_contains(&scx_kfunc_ids_enqueue_dispatch, kfunc_id);
bool in_dispatch = btf_id_set8_contains(&scx_kfunc_ids_dispatch, kfunc_id);
bool in_cpu_release = btf_id_set8_contains(&scx_kfunc_ids_cpu_release, kfunc_id);
bool in_idle = btf_id_set8_contains(&scx_kfunc_ids_idle, kfunc_id);
bool in_any = btf_id_set8_contains(&scx_kfunc_ids_any, kfunc_id);
u32 moff, flags;
/* Not a context-sensitive kfunc (e.g. from scx_kfunc_ids_any) - allow. */
if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch || in_cpu_release))
/* Not an SCX kfunc - allow. */
if (!(in_unlocked || in_select_cpu || in_enqueue || in_dispatch ||
in_cpu_release || in_idle || in_any))
return 0;
/* SYSCALL progs (e.g. BPF test_run()) may call unlocked and select_cpu kfuncs. */
if (prog->type == BPF_PROG_TYPE_SYSCALL)
return (in_unlocked || in_select_cpu) ? 0 : -EACCES;
return (in_unlocked || in_select_cpu || in_idle || in_any) ? 0 : -EACCES;
if (prog->type != BPF_PROG_TYPE_STRUCT_OPS)
return -EACCES;
return (in_any || in_idle) ? 0 : -EACCES;
/*
* add_subprog_and_kfunc() collects all kfunc calls, including dead code
@ -9711,14 +9714,15 @@ int scx_kfunc_context_filter(const struct bpf_prog *prog, u32 kfunc_id)
return 0;
/*
* Non-SCX struct_ops: only unlocked kfuncs are safe. The other
* context-sensitive kfuncs assume the rq lock is held by the SCX
* dispatch path, which doesn't apply to other struct_ops users.
* Non-SCX struct_ops: SCX kfuncs are not permitted.
*/
if (prog->aux->st_ops != &bpf_sched_ext_ops)
return in_unlocked ? 0 : -EACCES;
return -EACCES;
/* SCX struct_ops: check the per-op allow list. */
if (in_any || in_idle)
return 0;
moff = prog->aux->attach_st_ops_member_off;
flags = scx_kf_allow_flags[SCX_MOFF_IDX(moff)];

View File

@ -1467,6 +1467,7 @@ BTF_KFUNCS_END(scx_kfunc_ids_idle)
static const struct btf_kfunc_id_set scx_kfunc_set_idle = {
.owner = THIS_MODULE,
.set = &scx_kfunc_ids_idle,
.filter = scx_kfunc_context_filter,
};
/*

View File

@ -12,6 +12,7 @@
struct sched_ext_ops;
extern struct btf_id_set8 scx_kfunc_ids_idle;
extern struct btf_id_set8 scx_kfunc_ids_select_cpu;
void scx_idle_update_selcpu_topology(struct sched_ext_ops *ops);

View File

@ -175,6 +175,7 @@ auto-test-targets := \
maximal \
maybe_null \
minimal \
non_scx_kfunc_deny \
numa \
allowed_cpus \
peek_dsq \

View File

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Verify that context-sensitive SCX kfuncs (even "unlocked" ones) are
* restricted to only SCX struct_ops programs. Non-SCX struct_ops programs,
* such as TCP congestion control programs, should be rejected by the BPF
* verifier when attempting to call these kfuncs.
*
* Copyright (C) 2026 Ching-Chun (Jim) Huang <jserv@ccns.ncku.edu.tw>
* Copyright (C) 2026 Cheng-Yang Chou <yphbchou0911@gmail.com>
*/
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
/* SCX kfunc from scx_kfunc_ids_any set */
void scx_bpf_kick_cpu(s32 cpu, u64 flags) __ksym;
SEC("struct_ops/ssthresh")
__u32 BPF_PROG(tcp_ca_ssthresh, struct sock *sk)
{
/*
* This call should be rejected by the verifier because this is a
* TCP congestion control program (non-SCX struct_ops).
*/
scx_bpf_kick_cpu(0, 0);
return 2;
}
SEC("struct_ops/cong_avoid")
void BPF_PROG(tcp_ca_cong_avoid, struct sock *sk, __u32 ack, __u32 acked) {}
SEC("struct_ops/undo_cwnd")
__u32 BPF_PROG(tcp_ca_undo_cwnd, struct sock *sk) { return 2; }
SEC(".struct_ops")
struct tcp_congestion_ops tcp_non_scx_ca = {
.ssthresh = (void *)tcp_ca_ssthresh,
.cong_avoid = (void *)tcp_ca_cong_avoid,
.undo_cwnd = (void *)tcp_ca_undo_cwnd,
.name = "tcp_kfunc_deny",
};
char _license[] SEC("license") = "GPL";

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Verify that context-sensitive SCX kfuncs (even "unlocked" ones) are
* restricted to only SCX struct_ops programs. Non-SCX struct_ops programs,
* such as TCP congestion control programs, should be rejected by the BPF
* verifier when attempting to call these kfuncs.
*
* Copyright (C) 2026 Ching-Chun (Jim) Huang <jserv@ccns.ncku.edu.tw>
* Copyright (C) 2026 Cheng-Yang Chou <yphbchou0911@gmail.com>
*/
#include <bpf/bpf.h>
#include <scx/common.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include "non_scx_kfunc_deny.bpf.skel.h"
#include "scx_test.h"
static enum scx_test_status run(void *ctx)
{
struct non_scx_kfunc_deny *skel;
int err;
skel = non_scx_kfunc_deny__open();
if (!skel) {
SCX_ERR("Failed to open skel");
return SCX_TEST_FAIL;
}
err = non_scx_kfunc_deny__load(skel);
non_scx_kfunc_deny__destroy(skel);
if (err == 0) {
SCX_ERR("non-SCX BPF program loaded when it should have been rejected");
return SCX_TEST_FAIL;
}
return SCX_TEST_PASS;
}
struct scx_test non_scx_kfunc_deny = {
.name = "non_scx_kfunc_deny",
.description = "Verify that non-SCX struct_ops programs cannot call SCX kfuncs",
.run = run,
};
REGISTER_SCX_TEST(&non_scx_kfunc_deny)