Merge branch 'enable-static-subprog-calls-in-spin-lock-critical-sections'
Kumar Kartikeya Dwivedi says: ==================== Enable static subprog calls in spin lock critical sections This set allows a BPF program to make a call to a static subprog within a bpf_spin_lock critical section. This problem has been hit in sched-ext and ghOSt [0] as well, and is mostly an annoyance which is worked around by inling the static subprog into the critical section. In case of sched-ext, there are a lot of other helper/kfunc calls that need to be allow listed for the support to be complete, but a separate follow up will deal with that. Unlike static subprogs, global subprogs cannot be allowed yet as the verifier will not explore their body when encountering a call instruction for them. Therefore, we would need an alternative approach (some sort of function summarization to ensure a lock is never taken from a global subprog and all its callees). [0]: https://lore.kernel.org/bpf/bd173bf2-dea6-3e0e-4176-4a9256a9a056@google.com Changelog: ---------- v1 -> v2 v1: https://lore.kernel.org/bpf/20240204120206.796412-1-memxor@gmail.com * Indicate global function call in verifier error string (Yonghong, David) * Add Acks from Yonghong, David ==================== Link: https://lore.kernel.org/r/20240204222349.938118-1-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
8244ab509f
@ -9493,6 +9493,13 @@ static int check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||
if (subprog_is_global(env, subprog)) {
|
||||
const char *sub_name = subprog_name(env, subprog);
|
||||
|
||||
/* Only global subprogs cannot be called with a lock held. */
|
||||
if (env->cur_state->active_lock.ptr) {
|
||||
verbose(env, "global function calls are not allowed while holding a lock,\n"
|
||||
"use static function instead\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
verbose(env, "Caller passes invalid args into func#%d ('%s')\n",
|
||||
subprog, sub_name);
|
||||
@ -17644,7 +17651,6 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
|
||||
if (env->cur_state->active_lock.ptr) {
|
||||
if ((insn->src_reg == BPF_REG_0 && insn->imm != BPF_FUNC_spin_unlock) ||
|
||||
(insn->src_reg == BPF_PSEUDO_CALL) ||
|
||||
(insn->src_reg == BPF_PSEUDO_KFUNC_CALL &&
|
||||
(insn->off != 0 || !is_bpf_graph_api_kfunc(insn->imm)))) {
|
||||
verbose(env, "function calls are not allowed while holding a lock\n");
|
||||
@ -17692,8 +17698,7 @@ static int do_check(struct bpf_verifier_env *env)
|
||||
return -EINVAL;
|
||||
}
|
||||
process_bpf_exit_full:
|
||||
if (env->cur_state->active_lock.ptr &&
|
||||
!in_rbtree_lock_required_cb(env)) {
|
||||
if (env->cur_state->active_lock.ptr && !env->cur_state->curframe) {
|
||||
verbose(env, "bpf_spin_unlock is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ static struct {
|
||||
{ "lock_id_mismatch_innermapval_kptr", "bpf_spin_unlock of different lock" },
|
||||
{ "lock_id_mismatch_innermapval_global", "bpf_spin_unlock of different lock" },
|
||||
{ "lock_id_mismatch_innermapval_mapval", "bpf_spin_unlock of different lock" },
|
||||
{ "lock_global_subprog_call1", "global function calls are not allowed while holding a lock" },
|
||||
{ "lock_global_subprog_call2", "global function calls are not allowed while holding a lock" },
|
||||
};
|
||||
|
||||
static int match_regex(const char *pattern, const char *string)
|
||||
|
@ -101,4 +101,69 @@ int bpf_spin_lock_test(struct __sk_buff *skb)
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
|
||||
struct bpf_spin_lock lockA __hidden SEC(".data.A");
|
||||
|
||||
__noinline
|
||||
static int static_subprog(struct __sk_buff *ctx)
|
||||
{
|
||||
volatile int ret = 0;
|
||||
|
||||
if (ctx->protocol)
|
||||
return ret;
|
||||
return ret + ctx->len;
|
||||
}
|
||||
|
||||
__noinline
|
||||
static int static_subprog_lock(struct __sk_buff *ctx)
|
||||
{
|
||||
volatile int ret = 0;
|
||||
|
||||
ret = static_subprog(ctx);
|
||||
bpf_spin_lock(&lockA);
|
||||
return ret + ctx->len;
|
||||
}
|
||||
|
||||
__noinline
|
||||
static int static_subprog_unlock(struct __sk_buff *ctx)
|
||||
{
|
||||
volatile int ret = 0;
|
||||
|
||||
ret = static_subprog(ctx);
|
||||
bpf_spin_unlock(&lockA);
|
||||
return ret + ctx->len;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
int lock_static_subprog_call(struct __sk_buff *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_spin_lock(&lockA);
|
||||
if (ctx->mark == 42)
|
||||
ret = static_subprog(ctx);
|
||||
bpf_spin_unlock(&lockA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
int lock_static_subprog_lock(struct __sk_buff *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = static_subprog_lock(ctx);
|
||||
bpf_spin_unlock(&lockA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
int lock_static_subprog_unlock(struct __sk_buff *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_spin_lock(&lockA);
|
||||
ret = static_subprog_unlock(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
@ -201,4 +201,48 @@ CHECK(innermapval_mapval, &iv->lock, &v->lock);
|
||||
|
||||
#undef CHECK
|
||||
|
||||
__noinline
|
||||
int global_subprog(struct __sk_buff *ctx)
|
||||
{
|
||||
volatile int ret = 0;
|
||||
|
||||
if (ctx->protocol)
|
||||
ret += ctx->protocol;
|
||||
return ret + ctx->mark;
|
||||
}
|
||||
|
||||
__noinline
|
||||
static int static_subprog_call_global(struct __sk_buff *ctx)
|
||||
{
|
||||
volatile int ret = 0;
|
||||
|
||||
if (ctx->protocol)
|
||||
return ret;
|
||||
return ret + ctx->len + global_subprog(ctx);
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
int lock_global_subprog_call1(struct __sk_buff *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_spin_lock(&lockA);
|
||||
if (ctx->mark == 42)
|
||||
ret = global_subprog(ctx);
|
||||
bpf_spin_unlock(&lockA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("?tc")
|
||||
int lock_global_subprog_call2(struct __sk_buff *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_spin_lock(&lockA);
|
||||
if (ctx->mark == 42)
|
||||
ret = static_subprog_call_global(ctx);
|
||||
bpf_spin_unlock(&lockA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
@ -330,7 +330,7 @@ l1_%=: r7 = r0; \
|
||||
|
||||
SEC("cgroup/skb")
|
||||
__description("spin_lock: test10 lock in subprog without unlock")
|
||||
__failure __msg("unlock is missing")
|
||||
__success
|
||||
__failure_unpriv __msg_unpriv("")
|
||||
__naked void lock_in_subprog_without_unlock(void)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user