mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2026-01-13 11:41:07 +00:00
Kfuncs currently support specifying the KF_TRUSTED_ARGS flag to signal
to the verifier that it should enforce that a BPF program passes it a
"safe", trusted pointer. Currently, "safe" means that the pointer is
either PTR_TO_CTX, or is refcounted. There may be cases, however, where
the kernel passes a BPF program a safe / trusted pointer to an object
that the BPF program wishes to use as a kptr, but because the object
does not yet have a ref_obj_id from the perspective of the verifier, the
program would be unable to pass it to a KF_ACQUIRE | KF_TRUSTED_ARGS
kfunc.
The solution is to expand the set of pointers that are considered
trusted according to KF_TRUSTED_ARGS, so that programs can invoke kfuncs
with these pointers without getting rejected by the verifier.
There is already a PTR_UNTRUSTED flag that is set in some scenarios,
such as when a BPF program reads a kptr directly from a map
without performing a bpf_kptr_xchg() call. These pointers of course can
and should be rejected by the verifier. Unfortunately, however,
PTR_UNTRUSTED does not cover all the cases for safety that need to
be addressed to adequately protect kfuncs. Specifically, pointers
obtained by a BPF program "walking" a struct are _not_ considered
PTR_UNTRUSTED according to BPF. For example, say that we were to add a
kfunc called bpf_task_acquire(), with KF_ACQUIRE | KF_TRUSTED_ARGS, to
acquire a struct task_struct *. If we only used PTR_UNTRUSTED to signal
that a task was unsafe to pass to a kfunc, the verifier would mistakenly
allow the following unsafe BPF program to be loaded:
SEC("tp_btf/task_newtask")
int BPF_PROG(unsafe_acquire_task,
struct task_struct *task,
u64 clone_flags)
{
struct task_struct *acquired, *nested;
nested = task->last_wakee;
/* Would not be rejected by the verifier. */
acquired = bpf_task_acquire(nested);
if (!acquired)
return 0;
bpf_task_release(acquired);
return 0;
}
To address this, this patch defines a new type flag called PTR_TRUSTED
which tracks whether a PTR_TO_BTF_ID pointer is safe to pass to a
KF_TRUSTED_ARGS kfunc or a BPF helper function. PTR_TRUSTED pointers are
passed directly from the kernel as a tracepoint or struct_ops callback
argument. Any nested pointer that is obtained from walking a PTR_TRUSTED
pointer is no longer PTR_TRUSTED. From the example above, the struct
task_struct *task argument is PTR_TRUSTED, but the 'nested' pointer
obtained from 'task->last_wakee' is not PTR_TRUSTED.
A subsequent patch will add kfuncs for storing a task kfunc as a kptr,
and then another patch will add selftests to validate.
Signed-off-by: David Vernet <void@manifault.com>
Link: https://lore.kernel.org/r/20221120051004.3605026-3-void@manifault.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
||
|---|---|---|
| .. | ||
| .gitignore | ||
| and.c | ||
| array_access.c | ||
| atomic_and.c | ||
| atomic_bounds.c | ||
| atomic_cmpxchg.c | ||
| atomic_fetch_add.c | ||
| atomic_fetch.c | ||
| atomic_invalid.c | ||
| atomic_or.c | ||
| atomic_xchg.c | ||
| atomic_xor.c | ||
| basic_call.c | ||
| basic_instr.c | ||
| basic_stack.c | ||
| basic_stx_ldx.c | ||
| basic.c | ||
| bounds_deduction.c | ||
| bounds_mix_sign_unsign.c | ||
| bounds.c | ||
| bpf_get_stack.c | ||
| bpf_loop_inline.c | ||
| btf_ctx_access.c | ||
| calls.c | ||
| cfg.c | ||
| cgroup_inv_retcode.c | ||
| cgroup_skb.c | ||
| cgroup_storage.c | ||
| const_or.c | ||
| ctx_sk_lookup.c | ||
| ctx_sk_msg.c | ||
| ctx_skb.c | ||
| ctx.c | ||
| d_path.c | ||
| dead_code.c | ||
| direct_packet_access.c | ||
| direct_stack_access_wraparound.c | ||
| direct_value_access.c | ||
| div0.c | ||
| div_overflow.c | ||
| event_output.c | ||
| helper_access_var_len.c | ||
| helper_packet_access.c | ||
| helper_restricted.c | ||
| helper_value_access.c | ||
| int_ptr.c | ||
| jeq_infer_not_null.c | ||
| jit.c | ||
| jmp32.c | ||
| jset.c | ||
| jump.c | ||
| junk_insn.c | ||
| ld_abs.c | ||
| ld_dw.c | ||
| ld_imm64.c | ||
| ld_ind.c | ||
| leak_ptr.c | ||
| loops1.c | ||
| lwt.c | ||
| map_in_map.c | ||
| map_kptr.c | ||
| map_ptr_mixing.c | ||
| map_ptr.c | ||
| map_ret_val.c | ||
| masking.c | ||
| meta_access.c | ||
| perf_event_sample_period.c | ||
| precise.c | ||
| prevent_map_lookup.c | ||
| raw_stack.c | ||
| raw_tp_writable.c | ||
| ref_tracking.c | ||
| regalloc.c | ||
| ringbuf.c | ||
| runtime_jit.c | ||
| scale.c | ||
| search_pruning.c | ||
| sock.c | ||
| spill_fill.c | ||
| spin_lock.c | ||
| stack_ptr.c | ||
| subreg.c | ||
| uninit.c | ||
| unpriv.c | ||
| value_adj_spill.c | ||
| value_illegal_alu.c | ||
| value_or_null.c | ||
| value_ptr_arith.c | ||
| value.c | ||
| var_off.c | ||
| wide_access.c | ||
| xadd.c | ||
| xdp_direct_packet_access.c | ||
| xdp.c | ||