bpf: support for void/primitive __arg_untrusted global func params
Allow specifying __arg_untrusted for void */char */int */long *
parameters. Treat such parameters as
PTR_TO_MEM|MEM_RDONLY|PTR_UNTRUSTED of size zero.
Intended usage is as follows:
int memcmp(char *a __arg_untrusted, char *b __arg_untrusted, size_t n) {
bpf_for(i, 0, n) {
if (a[i] - b[i]) // load at any offset is allowed
return a[i] - b[i];
}
return 0;
}
Allocate register id for ARG_PTR_TO_MEM parameters only when
PTR_MAYBE_NULL is set. Register id for PTR_TO_MEM is used only to
propagate non-null status after conditionals.
Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250704230354.1323244-8-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
pull/1309/head
parent
54ac2c9418
commit
c4aa454c64
|
|
@ -223,6 +223,7 @@ u32 btf_nr_types(const struct btf *btf);
|
||||||
struct btf *btf_base_btf(const struct btf *btf);
|
struct btf *btf_base_btf(const struct btf *btf);
|
||||||
bool btf_type_is_i32(const struct btf_type *t);
|
bool btf_type_is_i32(const struct btf_type *t);
|
||||||
bool btf_type_is_i64(const struct btf_type *t);
|
bool btf_type_is_i64(const struct btf_type *t);
|
||||||
|
bool btf_type_is_primitive(const struct btf_type *t);
|
||||||
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
|
||||||
const struct btf_member *m,
|
const struct btf_member *m,
|
||||||
u32 expected_offset, u32 expected_size);
|
u32 expected_offset, u32 expected_size);
|
||||||
|
|
|
||||||
|
|
@ -891,6 +891,12 @@ bool btf_type_is_i64(const struct btf_type *t)
|
||||||
return btf_type_is_int(t) && __btf_type_int_is_regular(t, 8);
|
return btf_type_is_int(t) && __btf_type_int_is_regular(t, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool btf_type_is_primitive(const struct btf_type *t)
|
||||||
|
{
|
||||||
|
return (btf_type_is_int(t) && btf_type_int_is_regular(t)) ||
|
||||||
|
btf_is_any_enum(t);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that given struct member is a regular int with expected
|
* Check that given struct member is a regular int with expected
|
||||||
* offset and size.
|
* offset and size.
|
||||||
|
|
@ -7830,6 +7836,13 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref_t = btf_type_skip_modifiers(btf, t->type, NULL);
|
||||||
|
if (btf_type_is_void(ref_t) || btf_type_is_primitive(ref_t)) {
|
||||||
|
sub->args[i].arg_type = ARG_PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED;
|
||||||
|
sub->args[i].mem_size = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
kern_type_id = btf_get_ptr_to_btf_id(log, i, btf, t);
|
kern_type_id = btf_get_ptr_to_btf_id(log, i, btf, t);
|
||||||
if (kern_type_id < 0)
|
if (kern_type_id < 0)
|
||||||
return kern_type_id;
|
return kern_type_id;
|
||||||
|
|
@ -7838,7 +7851,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
|
||||||
ref_t = btf_type_by_id(vmlinux_btf, kern_type_id);
|
ref_t = btf_type_by_id(vmlinux_btf, kern_type_id);
|
||||||
if (!btf_type_is_struct(ref_t)) {
|
if (!btf_type_is_struct(ref_t)) {
|
||||||
tname = __btf_name_by_offset(vmlinux_btf, t->name_off);
|
tname = __btf_name_by_offset(vmlinux_btf, t->name_off);
|
||||||
bpf_log(log, "arg#%d has type %s '%s', but only struct types are allowed\n",
|
bpf_log(log, "arg#%d has type %s '%s', but only struct or primitive types are allowed\n",
|
||||||
i, btf_type_str(ref_t), tname);
|
i, btf_type_str(ref_t), tname);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23152,11 +23152,12 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog)
|
||||||
__mark_dynptr_reg(reg, BPF_DYNPTR_TYPE_LOCAL, true, ++env->id_gen);
|
__mark_dynptr_reg(reg, BPF_DYNPTR_TYPE_LOCAL, true, ++env->id_gen);
|
||||||
} else if (base_type(arg->arg_type) == ARG_PTR_TO_MEM) {
|
} else if (base_type(arg->arg_type) == ARG_PTR_TO_MEM) {
|
||||||
reg->type = PTR_TO_MEM;
|
reg->type = PTR_TO_MEM;
|
||||||
if (arg->arg_type & PTR_MAYBE_NULL)
|
reg->type |= arg->arg_type &
|
||||||
reg->type |= PTR_MAYBE_NULL;
|
(PTR_MAYBE_NULL | PTR_UNTRUSTED | MEM_RDONLY);
|
||||||
mark_reg_known_zero(env, regs, i);
|
mark_reg_known_zero(env, regs, i);
|
||||||
reg->mem_size = arg->mem_size;
|
reg->mem_size = arg->mem_size;
|
||||||
reg->id = ++env->id_gen;
|
if (arg->arg_type & PTR_MAYBE_NULL)
|
||||||
|
reg->id = ++env->id_gen;
|
||||||
} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
|
} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
|
||||||
reg->type = PTR_TO_BTF_ID;
|
reg->type = PTR_TO_BTF_ID;
|
||||||
if (arg->arg_type & PTR_MAYBE_NULL)
|
if (arg->arg_type & PTR_MAYBE_NULL)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue