Skip to content

Commit c5a7244

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
bpf: move subprog call logic back to verifier.c
Subprog call logic in btf_check_subprog_call() currently has both a lot of BTF parsing logic (which is, presumably, what justified putting it into btf.c), but also a bunch of register state checks, some of each utilize deep verifier logic helpers, necessarily exported from verifier.c: check_ptr_off_reg(), check_func_arg_reg_off(), and check_mem_reg(). Going forward, btf_check_subprog_call() will have a minimum of BTF-related logic, but will get more internal verifier logic related to register state manipulation. So move it into verifier.c to minimize amount of verifier-specific logic exposed to btf.c. We do this move before refactoring btf_check_func_arg_match() to preserve as much history post-refactoring as possible. No functional changes. Acked-by: Eduard Zingerman <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent e26080d commit c5a7244

File tree

4 files changed

+146
-156
lines changed

4 files changed

+146
-156
lines changed

include/linux/bpf.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,8 +2466,6 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
24662466
struct btf_func_model *m);
24672467

24682468
struct bpf_reg_state;
2469-
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
2470-
struct bpf_reg_state *regs);
24712469
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog);
24722470
int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,
24732471
struct btf *btf, const struct btf_type *t);

include/linux/bpf_verifier.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -785,14 +785,6 @@ bpf_prog_offload_replace_insn(struct bpf_verifier_env *env, u32 off,
785785
void
786786
bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt);
787787

788-
int check_ptr_off_reg(struct bpf_verifier_env *env,
789-
const struct bpf_reg_state *reg, int regno);
790-
int check_func_arg_reg_off(struct bpf_verifier_env *env,
791-
const struct bpf_reg_state *reg, int regno,
792-
enum bpf_arg_type arg_type);
793-
int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
794-
u32 regno, u32 mem_size);
795-
796788
/* this lives here instead of in bpf.h because it needs to dereference tgt_prog */
797789
static inline u64 bpf_trampoline_compute_key(const struct bpf_prog *tgt_prog,
798790
struct btf *btf, u32 btf_id)

kernel/bpf/btf.c

Lines changed: 0 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -6765,145 +6765,6 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr
67656765
return btf_check_func_type_match(log, btf1, t1, btf2, t2);
67666766
}
67676767

6768-
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
6769-
const struct btf *btf, u32 func_id,
6770-
struct bpf_reg_state *regs,
6771-
bool ptr_to_mem_ok)
6772-
{
6773-
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
6774-
struct bpf_verifier_log *log = &env->log;
6775-
const char *func_name, *ref_tname;
6776-
const struct btf_type *t, *ref_t;
6777-
const struct btf_param *args;
6778-
u32 i, nargs, ref_id;
6779-
int ret;
6780-
6781-
t = btf_type_by_id(btf, func_id);
6782-
if (!t || !btf_type_is_func(t)) {
6783-
/* These checks were already done by the verifier while loading
6784-
* struct bpf_func_info or in add_kfunc_call().
6785-
*/
6786-
bpf_log(log, "BTF of func_id %u doesn't point to KIND_FUNC\n",
6787-
func_id);
6788-
return -EFAULT;
6789-
}
6790-
func_name = btf_name_by_offset(btf, t->name_off);
6791-
6792-
t = btf_type_by_id(btf, t->type);
6793-
if (!t || !btf_type_is_func_proto(t)) {
6794-
bpf_log(log, "Invalid BTF of func %s\n", func_name);
6795-
return -EFAULT;
6796-
}
6797-
args = (const struct btf_param *)(t + 1);
6798-
nargs = btf_type_vlen(t);
6799-
if (nargs > MAX_BPF_FUNC_REG_ARGS) {
6800-
bpf_log(log, "Function %s has %d > %d args\n", func_name, nargs,
6801-
MAX_BPF_FUNC_REG_ARGS);
6802-
return -EINVAL;
6803-
}
6804-
6805-
/* check that BTF function arguments match actual types that the
6806-
* verifier sees.
6807-
*/
6808-
for (i = 0; i < nargs; i++) {
6809-
enum bpf_arg_type arg_type = ARG_DONTCARE;
6810-
u32 regno = i + 1;
6811-
struct bpf_reg_state *reg = &regs[regno];
6812-
6813-
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
6814-
if (btf_type_is_scalar(t)) {
6815-
if (reg->type == SCALAR_VALUE)
6816-
continue;
6817-
bpf_log(log, "R%d is not a scalar\n", regno);
6818-
return -EINVAL;
6819-
}
6820-
6821-
if (!btf_type_is_ptr(t)) {
6822-
bpf_log(log, "Unrecognized arg#%d type %s\n",
6823-
i, btf_type_str(t));
6824-
return -EINVAL;
6825-
}
6826-
6827-
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
6828-
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
6829-
6830-
ret = check_func_arg_reg_off(env, reg, regno, arg_type);
6831-
if (ret < 0)
6832-
return ret;
6833-
6834-
if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
6835-
/* If function expects ctx type in BTF check that caller
6836-
* is passing PTR_TO_CTX.
6837-
*/
6838-
if (reg->type != PTR_TO_CTX) {
6839-
bpf_log(log,
6840-
"arg#%d expected pointer to ctx, but got %s\n",
6841-
i, btf_type_str(t));
6842-
return -EINVAL;
6843-
}
6844-
} else if (ptr_to_mem_ok) {
6845-
const struct btf_type *resolve_ret;
6846-
u32 type_size;
6847-
6848-
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
6849-
if (IS_ERR(resolve_ret)) {
6850-
bpf_log(log,
6851-
"arg#%d reference type('%s %s') size cannot be determined: %ld\n",
6852-
i, btf_type_str(ref_t), ref_tname,
6853-
PTR_ERR(resolve_ret));
6854-
return -EINVAL;
6855-
}
6856-
6857-
if (check_mem_reg(env, reg, regno, type_size))
6858-
return -EINVAL;
6859-
} else {
6860-
bpf_log(log, "reg type unsupported for arg#%d function %s#%d\n", i,
6861-
func_name, func_id);
6862-
return -EINVAL;
6863-
}
6864-
}
6865-
6866-
return 0;
6867-
}
6868-
6869-
/* Compare BTF of a function call with given bpf_reg_state.
6870-
* Returns:
6871-
* EFAULT - there is a verifier bug. Abort verification.
6872-
* EINVAL - there is a type mismatch or BTF is not available.
6873-
* 0 - BTF matches with what bpf_reg_state expects.
6874-
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
6875-
*/
6876-
int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
6877-
struct bpf_reg_state *regs)
6878-
{
6879-
struct bpf_prog *prog = env->prog;
6880-
struct btf *btf = prog->aux->btf;
6881-
bool is_global;
6882-
u32 btf_id;
6883-
int err;
6884-
6885-
if (!prog->aux->func_info)
6886-
return -EINVAL;
6887-
6888-
btf_id = prog->aux->func_info[subprog].type_id;
6889-
if (!btf_id)
6890-
return -EFAULT;
6891-
6892-
if (prog->aux->func_info_aux[subprog].unreliable)
6893-
return -EINVAL;
6894-
6895-
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
6896-
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global);
6897-
6898-
/* Compiler optimizations can remove arguments from static functions
6899-
* or mismatched type can be passed into a global function.
6900-
* In such cases mark the function as unreliable from BTF point of view.
6901-
*/
6902-
if (err)
6903-
prog->aux->func_info_aux[subprog].unreliable = true;
6904-
return err;
6905-
}
6906-
69076768
/* Process BTF of a function to produce high-level expectation of function
69086769
* arguments (like ARG_PTR_TO_CTX, or ARG_PTR_TO_MEM, etc). This information
69096770
* is cached in subprog info for reuse.

kernel/bpf/verifier.c

Lines changed: 146 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5127,8 +5127,8 @@ static int __check_ptr_off_reg(struct bpf_verifier_env *env,
51275127
return 0;
51285128
}
51295129

5130-
int check_ptr_off_reg(struct bpf_verifier_env *env,
5131-
const struct bpf_reg_state *reg, int regno)
5130+
static int check_ptr_off_reg(struct bpf_verifier_env *env,
5131+
const struct bpf_reg_state *reg, int regno)
51325132
{
51335133
return __check_ptr_off_reg(env, reg, regno, false);
51345134
}
@@ -7300,8 +7300,8 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
73007300
return err;
73017301
}
73027302

7303-
int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
7304-
u32 regno, u32 mem_size)
7303+
static int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
7304+
u32 regno, u32 mem_size)
73057305
{
73067306
bool may_be_null = type_may_be_null(reg->type);
73077307
struct bpf_reg_state saved_reg;
@@ -8286,9 +8286,9 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields)
82868286
return field;
82878287
}
82888288

8289-
int check_func_arg_reg_off(struct bpf_verifier_env *env,
8290-
const struct bpf_reg_state *reg, int regno,
8291-
enum bpf_arg_type arg_type)
8289+
static int check_func_arg_reg_off(struct bpf_verifier_env *env,
8290+
const struct bpf_reg_state *reg, int regno,
8291+
enum bpf_arg_type arg_type)
82928292
{
82938293
u32 type = reg->type;
82948294

@@ -9249,6 +9249,145 @@ static int setup_func_entry(struct bpf_verifier_env *env, int subprog, int calls
92499249
return err;
92509250
}
92519251

9252+
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
9253+
const struct btf *btf, u32 func_id,
9254+
struct bpf_reg_state *regs,
9255+
bool ptr_to_mem_ok)
9256+
{
9257+
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
9258+
struct bpf_verifier_log *log = &env->log;
9259+
const char *func_name, *ref_tname;
9260+
const struct btf_type *t, *ref_t;
9261+
const struct btf_param *args;
9262+
u32 i, nargs, ref_id;
9263+
int ret;
9264+
9265+
t = btf_type_by_id(btf, func_id);
9266+
if (!t || !btf_type_is_func(t)) {
9267+
/* These checks were already done by the verifier while loading
9268+
* struct bpf_func_info or in add_kfunc_call().
9269+
*/
9270+
bpf_log(log, "BTF of func_id %u doesn't point to KIND_FUNC\n",
9271+
func_id);
9272+
return -EFAULT;
9273+
}
9274+
func_name = btf_name_by_offset(btf, t->name_off);
9275+
9276+
t = btf_type_by_id(btf, t->type);
9277+
if (!t || !btf_type_is_func_proto(t)) {
9278+
bpf_log(log, "Invalid BTF of func %s\n", func_name);
9279+
return -EFAULT;
9280+
}
9281+
args = (const struct btf_param *)(t + 1);
9282+
nargs = btf_type_vlen(t);
9283+
if (nargs > MAX_BPF_FUNC_REG_ARGS) {
9284+
bpf_log(log, "Function %s has %d > %d args\n", func_name, nargs,
9285+
MAX_BPF_FUNC_REG_ARGS);
9286+
return -EINVAL;
9287+
}
9288+
9289+
/* check that BTF function arguments match actual types that the
9290+
* verifier sees.
9291+
*/
9292+
for (i = 0; i < nargs; i++) {
9293+
enum bpf_arg_type arg_type = ARG_DONTCARE;
9294+
u32 regno = i + 1;
9295+
struct bpf_reg_state *reg = &regs[regno];
9296+
9297+
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
9298+
if (btf_type_is_scalar(t)) {
9299+
if (reg->type == SCALAR_VALUE)
9300+
continue;
9301+
bpf_log(log, "R%d is not a scalar\n", regno);
9302+
return -EINVAL;
9303+
}
9304+
9305+
if (!btf_type_is_ptr(t)) {
9306+
bpf_log(log, "Unrecognized arg#%d type %s\n",
9307+
i, btf_type_str(t));
9308+
return -EINVAL;
9309+
}
9310+
9311+
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
9312+
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
9313+
9314+
ret = check_func_arg_reg_off(env, reg, regno, arg_type);
9315+
if (ret < 0)
9316+
return ret;
9317+
9318+
if (btf_get_prog_ctx_type(log, btf, t, prog_type, i)) {
9319+
/* If function expects ctx type in BTF check that caller
9320+
* is passing PTR_TO_CTX.
9321+
*/
9322+
if (reg->type != PTR_TO_CTX) {
9323+
bpf_log(log,
9324+
"arg#%d expected pointer to ctx, but got %s\n",
9325+
i, btf_type_str(t));
9326+
return -EINVAL;
9327+
}
9328+
} else if (ptr_to_mem_ok) {
9329+
const struct btf_type *resolve_ret;
9330+
u32 type_size;
9331+
9332+
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
9333+
if (IS_ERR(resolve_ret)) {
9334+
bpf_log(log,
9335+
"arg#%d reference type('%s %s') size cannot be determined: %ld\n",
9336+
i, btf_type_str(ref_t), ref_tname,
9337+
PTR_ERR(resolve_ret));
9338+
return -EINVAL;
9339+
}
9340+
9341+
if (check_mem_reg(env, reg, regno, type_size))
9342+
return -EINVAL;
9343+
} else {
9344+
bpf_log(log, "reg type unsupported for arg#%d function %s#%d\n", i,
9345+
func_name, func_id);
9346+
return -EINVAL;
9347+
}
9348+
}
9349+
9350+
return 0;
9351+
}
9352+
9353+
/* Compare BTF of a function call with given bpf_reg_state.
9354+
* Returns:
9355+
* EFAULT - there is a verifier bug. Abort verification.
9356+
* EINVAL - there is a type mismatch or BTF is not available.
9357+
* 0 - BTF matches with what bpf_reg_state expects.
9358+
* Only PTR_TO_CTX and SCALAR_VALUE states are recognized.
9359+
*/
9360+
static int btf_check_subprog_call(struct bpf_verifier_env *env, int subprog,
9361+
struct bpf_reg_state *regs)
9362+
{
9363+
struct bpf_prog *prog = env->prog;
9364+
struct btf *btf = prog->aux->btf;
9365+
bool is_global;
9366+
u32 btf_id;
9367+
int err;
9368+
9369+
if (!prog->aux->func_info)
9370+
return -EINVAL;
9371+
9372+
btf_id = prog->aux->func_info[subprog].type_id;
9373+
if (!btf_id)
9374+
return -EFAULT;
9375+
9376+
if (prog->aux->func_info_aux[subprog].unreliable)
9377+
return -EINVAL;
9378+
9379+
is_global = prog->aux->func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL;
9380+
err = btf_check_func_arg_match(env, btf, btf_id, regs, is_global);
9381+
9382+
/* Compiler optimizations can remove arguments from static functions
9383+
* or mismatched type can be passed into a global function.
9384+
* In such cases mark the function as unreliable from BTF point of view.
9385+
*/
9386+
if (err)
9387+
prog->aux->func_info_aux[subprog].unreliable = true;
9388+
return err;
9389+
}
9390+
92529391
static int push_callback_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
92539392
int insn_idx, int subprog,
92549393
set_callee_state_fn set_callee_state_cb)

0 commit comments

Comments
 (0)