Skip to content

Commit 2e1d30f

Browse files
ubiquekernel-patches-bot
authored andcommitted
bpf: relax return code check for subprograms
Currently verifier enforces return code checks for subprograms in the same manner as it does for program entry points. This prevents returning arbitrary scalar values from subprograms. Scalar type of returned values is checked by btf_prepare_func_args() and hence it should be safe to allow only scalars for now. Relax return code checks for subprograms and allow any correct scalar values. Signed-off-by: Dmitrii Banshchikov <[email protected]> Fixes: 51c39bb (bpf: Introduce function-by-function verification)
1 parent cdeea95 commit 2e1d30f

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

kernel/bpf/verifier.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7791,7 +7791,7 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
77917791
return 0;
77927792
}
77937793

7794-
static int check_return_code(struct bpf_verifier_env *env)
7794+
static int check_return_code(struct bpf_verifier_env *env, bool is_subprog)
77957795
{
77967796
struct tnum enforce_attach_type_range = tnum_unknown;
77977797
const struct bpf_prog *prog = env->prog;
@@ -7801,10 +7801,12 @@ static int check_return_code(struct bpf_verifier_env *env)
78017801
int err;
78027802

78037803
/* LSM and struct_ops func-ptr's return type could be "void" */
7804-
if ((prog_type == BPF_PROG_TYPE_STRUCT_OPS ||
7805-
prog_type == BPF_PROG_TYPE_LSM) &&
7806-
!prog->aux->attach_func_proto->type)
7807-
return 0;
7804+
if (!is_subprog) {
7805+
if ((prog_type == BPF_PROG_TYPE_STRUCT_OPS ||
7806+
prog_type == BPF_PROG_TYPE_LSM) &&
7807+
!prog->aux->attach_func_proto->type)
7808+
return 0;
7809+
}
78087810

78097811
/* eBPF calling convetion is such that R0 is used
78107812
* to return the value from eBPF program.
@@ -7821,6 +7823,16 @@ static int check_return_code(struct bpf_verifier_env *env)
78217823
return -EACCES;
78227824
}
78237825

7826+
reg = cur_regs(env) + BPF_REG_0;
7827+
if (is_subprog) {
7828+
if (reg->type != SCALAR_VALUE) {
7829+
verbose(env, "At subprogram exit the register R0 is not a scalar value (%s)\n",
7830+
reg_type_str[reg->type]);
7831+
return -EINVAL;
7832+
}
7833+
return 0;
7834+
}
7835+
78247836
switch (prog_type) {
78257837
case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
78267838
if (env->prog->expected_attach_type == BPF_CGROUP_UDP4_RECVMSG ||
@@ -7874,7 +7886,6 @@ static int check_return_code(struct bpf_verifier_env *env)
78747886
return 0;
78757887
}
78767888

7877-
reg = cur_regs(env) + BPF_REG_0;
78787889
if (reg->type != SCALAR_VALUE) {
78797890
verbose(env, "At program exit the register R0 is not a known value (%s)\n",
78807891
reg_type_str[reg->type]);
@@ -9266,6 +9277,7 @@ static int do_check(struct bpf_verifier_env *env)
92669277
int insn_cnt = env->prog->len;
92679278
bool do_print_state = false;
92689279
int prev_insn_idx = -1;
9280+
const bool is_subprog = env->cur_state->frame[0]->subprogno;
92699281

92709282
for (;;) {
92719283
struct bpf_insn *insn;
@@ -9530,7 +9542,7 @@ static int do_check(struct bpf_verifier_env *env)
95309542
if (err)
95319543
return err;
95329544

9533-
err = check_return_code(env);
9545+
err = check_return_code(env, is_subprog);
95349546
if (err)
95359547
return err;
95369548
process_bpf_exit:

tools/testing/selftests/bpf/prog_tests/test_global_funcs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ void test_test_global_funcs(void)
6060
{ "test_global_func5.o" , "expected pointer to ctx, but got PTR" },
6161
{ "test_global_func6.o" , "modified ctx ptr R2" },
6262
{ "test_global_func7.o" , "foo() doesn't return scalar" },
63+
{ "test_global_func8.o" },
6364
};
6465
libbpf_print_fn_t old_print_fn = NULL;
6566
int err, i, duration = 0;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright (c) 2020 Facebook */
3+
#include <stddef.h>
4+
#include <linux/bpf.h>
5+
#include <bpf/bpf_helpers.h>
6+
7+
__attribute__ ((noinline))
8+
int bar(struct __sk_buff *skb)
9+
{
10+
return bpf_get_prandom_u32();
11+
}
12+
13+
static __always_inline int foo(struct __sk_buff *skb)
14+
{
15+
if (!bar(skb))
16+
return 0;
17+
18+
return 1;
19+
}
20+
21+
SEC("cgroup_skb/ingress")
22+
int test_cls(struct __sk_buff *skb)
23+
{
24+
return foo(skb);
25+
}

0 commit comments

Comments
 (0)