mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge branch 'bpf-enforce-trusted-btf-id-argument-provenance'
Yiyang Chen says: ==================== bpf: Enforce trusted BTF ID argument provenance A global subprogram parameter tagged __arg_trusted is verified with PTR_TRUSTED, but its call-site type check also accepts bare PTR_TO_BTF_ID and MEM_RCU registers. This lets a callee use a pointer with weaker provenance under the trusted-pointer contract, including passing it to a non-KF_RCU kfunc. Encode the trusted-pointer requirement in generated kfunc prototypes and drive the shared provenance check from the argument contract. A KF_RCU kfunc additionally permits MEM_RCU, while a global __arg_trusted argument requires a referenced or trusted pointer. Normalize nullability when the argument contract permits it. Add rejection coverage for bare and RCU-protected global-subprogram arguments and acceptance coverage for a nullable kfunc receiving a trusted nullable pointer. A separate scx_cake caller fix has been prepared but is not yet submitted. The current veristat-scx pin still uses the old caller, which this series rejects. Changes in v4: - Rebase onto bpf-next and use the shared argument checker. - Reject MEM_RCU for global __arg_trusted arguments. - Encode trusted and KF_RCU provenance in generated kfunc prototypes. - Add nullable-kfunc coverage and use a 12-character Fixes SHA. - Link to v3: https://lore.kernel.org/r/20261006-a3-arg-trusted-v4-v3-0-4619daf30e1c@mails.tsinghua.edu.cn Changes in v3: - Preserve RCU-protected arguments accepted by existing sched-ext programs. - Make the MEM_RCU case a positive regression test. - Use the preferred multi-line comment style. - Link to v2: https://lore.kernel.org/r/20261005-a3-arg-trusted-v4-v2-0-319ce2936949@mails.tsinghua.edu.cn Changes in v2: - Retarget the fix to btf_check_func_arg_match(), where the subprogram argument check lives in this tree, instead of check_func_arg(). - Run the check after check_reg_type() and check_func_arg_reg_off() so type and offset diagnostics keep their wording. v1: https://lore.kernel.org/bpf/20261005-a3-arg-trusted-v4-v1-0-50ee0268fd39@mails.tsinghua.edu.cn/ --- ==================== Link: https://patch.msgid.link/20261007-a3-arg-trusted-v4-v4-0-253ef3a1a69a@mails.tsinghua.edu.cn Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
commit
44b6b1dfb2
|
|
@ -5501,15 +5501,17 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
|
|||
[CONST_PTR_TO_MAP] = btf_bpf_map_id,
|
||||
};
|
||||
|
||||
static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_state *reg)
|
||||
static bool is_trusted_reg_type(struct bpf_verifier_env *env,
|
||||
const struct bpf_reg_state *reg,
|
||||
enum bpf_reg_type type)
|
||||
{
|
||||
/* A referenced register is always trusted. */
|
||||
if (reg_is_referenced(env, reg))
|
||||
return true;
|
||||
|
||||
/* Types listed in the reg2btf_ids are always trusted */
|
||||
if (reg2btf_ids[base_type(reg->type)] &&
|
||||
!bpf_type_has_unsafe_modifiers(reg->type))
|
||||
if (reg2btf_ids[base_type(type)] &&
|
||||
!bpf_type_has_unsafe_modifiers(type))
|
||||
return true;
|
||||
|
||||
/* If a register is not referenced, it is trusted if it has the
|
||||
|
|
@ -5521,8 +5523,14 @@ static bool is_trusted_reg(struct bpf_verifier_env *env, const struct bpf_reg_st
|
|||
* Eventually, we should make PTR_TRUSTED the single source of truth
|
||||
* for whether a register is trusted.
|
||||
*/
|
||||
return type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS &&
|
||||
!bpf_type_has_unsafe_modifiers(reg->type);
|
||||
return type_flag(type) & BPF_REG_TRUSTED_MODIFIERS &&
|
||||
!bpf_type_has_unsafe_modifiers(type);
|
||||
}
|
||||
|
||||
static bool is_trusted_reg(struct bpf_verifier_env *env,
|
||||
const struct bpf_reg_state *reg)
|
||||
{
|
||||
return is_trusted_reg_type(env, reg, reg->type);
|
||||
}
|
||||
|
||||
static bool is_rcu_reg(const struct bpf_reg_state *reg)
|
||||
|
|
@ -9798,6 +9806,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
|
|||
{
|
||||
const u32 *arg_btf_id = fn->arg_btf_id[arg];
|
||||
const struct btf *arg_btf = is_kfunc(meta) ? meta->btf : btf_vmlinux;
|
||||
enum bpf_reg_type reg_type;
|
||||
|
||||
if (!meta->btf) {
|
||||
const struct bpf_reg_types *compatible;
|
||||
|
|
@ -9825,8 +9834,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
|
|||
}
|
||||
}
|
||||
|
||||
if (is_kfunc(meta) && (!is_trusted_reg(env, reg) ||
|
||||
bpf_type_has_unsafe_modifiers(reg->type))) {
|
||||
reg_type = reg->type & ~(arg_type & PTR_MAYBE_NULL);
|
||||
if ((arg_type & PTR_TRUSTED) &&
|
||||
(!is_trusted_reg_type(env, reg, reg_type) ||
|
||||
bpf_type_has_unsafe_modifiers(reg_type))) {
|
||||
if (!(arg_type & MEM_RCU)) {
|
||||
const char *actual_type, *arg_name, *expected_type;
|
||||
|
||||
|
|
@ -14023,6 +14034,8 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
|
|||
else
|
||||
proto->arg_btf_id[arg] = ref_id_ptr;
|
||||
|
||||
arg_type |= PTR_TRUSTED;
|
||||
|
||||
/*
|
||||
* A KF_RCU kfunc accepts an RCU-protected pointer where it would
|
||||
* otherwise demand a referenced or trusted one. Other argument kinds
|
||||
|
|
|
|||
|
|
@ -46,6 +46,17 @@ int iter_next_trusted_or_null(const void *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("syscall")
|
||||
__success
|
||||
int trusted_nullable_kfunc(const void *ctx)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = bpf_kfunc_trusted_null_test();
|
||||
bpf_kfunc_trusted_nullable_test(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("raw_tp/sys_enter")
|
||||
__success
|
||||
int iter_next_rcu(const void *ctx)
|
||||
|
|
|
|||
|
|
@ -289,6 +289,41 @@ __weak int subprog_void_untrusted(void *p __arg_untrusted)
|
|||
return *(int *)p;
|
||||
}
|
||||
|
||||
__weak int subprog_trusted_bare(struct task_struct *task __arg_trusted)
|
||||
{
|
||||
return task->pid;
|
||||
}
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
__failure
|
||||
__msg("R1 must be referenced or trusted")
|
||||
__msg("Caller passes invalid args into func#{{.*}} ('subprog_trusted_bare')")
|
||||
int bare_to_trusted(void *ctx)
|
||||
{
|
||||
struct task_struct *cur = bpf_get_current_task_btf();
|
||||
struct task_struct *wakee;
|
||||
|
||||
if (!cur)
|
||||
return 0;
|
||||
wakee = cur->last_wakee;
|
||||
if (!wakee)
|
||||
return 0;
|
||||
return subprog_trusted_bare(wakee);
|
||||
}
|
||||
|
||||
SEC("tp_btf/task_newtask")
|
||||
__failure
|
||||
__msg("R1 must be referenced or trusted")
|
||||
__msg("Caller passes invalid args into func#{{.*}}")
|
||||
int memrcu_to_trusted(void *ctx)
|
||||
{
|
||||
struct task_struct *cur = bpf_get_current_task_btf();
|
||||
|
||||
if (!cur)
|
||||
return 0;
|
||||
return subprog_trusted_task_nullable(cur->real_parent);
|
||||
}
|
||||
|
||||
__weak int subprog_char_untrusted(char *p __arg_untrusted)
|
||||
{
|
||||
return *(int *)p;
|
||||
|
|
|
|||
|
|
@ -350,6 +350,15 @@ __bpf_kfunc void bpf_kfunc_trusted_task_test(struct task_struct *ptr)
|
|||
{
|
||||
}
|
||||
|
||||
__bpf_kfunc struct task_struct *bpf_kfunc_trusted_null_test(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_trusted_nullable_test(struct task_struct *ptr__nullable)
|
||||
{
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_trusted_num_test(int *ptr)
|
||||
{
|
||||
}
|
||||
|
|
@ -957,6 +966,8 @@ BTF_ID_FLAGS(func, bpf_kfunc_nested_acquire_zero_offset_test, KF_ACQUIRE)
|
|||
BTF_ID_FLAGS(func, bpf_kfunc_nested_release_test, KF_RELEASE)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_trusted_vma_test)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_trusted_task_test)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_trusted_null_test, KF_RET_NULL)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_trusted_nullable_test)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_trusted_num_test)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_rcu_task_test, KF_RCU)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_ret_rcu_test, KF_RET_NULL | KF_RCU_PROTECTED)
|
||||
|
|
|
|||
|
|
@ -353,6 +353,8 @@ int bpf_kfunc_st_ops_inc10(struct st_ops_args *args) __ksym;
|
|||
|
||||
void bpf_kfunc_trusted_vma_test(struct vm_area_struct *ptr) __ksym;
|
||||
void bpf_kfunc_trusted_task_test(struct task_struct *ptr) __ksym;
|
||||
struct task_struct *bpf_kfunc_trusted_null_test(void) __ksym;
|
||||
void bpf_kfunc_trusted_nullable_test(struct task_struct *ptr__nullable) __ksym;
|
||||
void bpf_kfunc_trusted_num_test(int *ptr) __ksym;
|
||||
void bpf_kfunc_rcu_task_test(struct task_struct *ptr) __ksym;
|
||||
struct task_struct *bpf_kfunc_ret_rcu_test(void) __ksym;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user