Extend union bpf_attr for BPF_PROG_LOAD to support proof-based verifier refinement. The new fields let the verifier export the refinement condition to userspace, preserve its state behind an anon-fd, and later accept a proof and resume analysis. - bcf_buf, bcf_buf_size, bcf_buf_true_size: shared buffer used first to export expressions+condition to userspace and later to receive a proof. true_size refers to the condition size and proof size accordingly. - bcf_fd: anon-fd that owns the preserved verifier_env. Set by the kernel on request; userspace passes it back when submitting a proof. Tools uapi is also updated. Signed-off-by: Hao Sun --- include/uapi/linux/bpf.h | 21 +++++++++++++++++++++ kernel/bpf/syscall.c | 23 ++++++++++++++++++++++- tools/include/uapi/linux/bpf.h | 21 +++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 1d73f165394d..fbe99fbc39ab 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1484,6 +1484,15 @@ enum { BPF_STREAM_STDERR = 2, }; +/* bcf_flags used in BPF_PROG_LOAD command to indicate if the verifier + * requests or the user provides proofs. + */ +enum { + BCF_F_PROOF_REQUESTED = (1U << 0), + BCF_F_PROOF_PROVIDED = (1U << 1), + BCF_F_PROOF_PATH_UNREACHABLE = (1U << 2), +}; + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ @@ -1624,6 +1633,18 @@ union bpf_attr { * verification. */ __s32 keyring_id; + /* BCF buffer for both the condition to be proved required by + * the verifier and the proof provided from user space. + */ + __aligned_u64 bcf_buf; + __u32 bcf_buf_size; + __u32 bcf_buf_true_size; + /* output: BCF fd for loading proof, set by the verifier when + * proof is requested. + */ + __u32 bcf_fd; + /* input/output: proof requested or provided. */ + __u32 bcf_flags; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8a129746bd6c..5968b74ed7b2 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2854,7 +2854,7 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr } /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD keyring_id +#define BPF_PROG_LOAD_LAST_FIELD bcf_flags static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) { @@ -2869,6 +2869,24 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) if (CHECK_ATTR(BPF_PROG_LOAD)) return -EINVAL; + if (!!attr->bcf_buf != !!attr->bcf_buf_size || + (attr->bcf_flags & ~(BCF_F_PROOF_PROVIDED | + BCF_F_PROOF_PATH_UNREACHABLE))) + return -EINVAL; + + /* Check proof and resume the last analysis. */ + if (attr->bcf_flags & BCF_F_PROOF_PROVIDED) { + if (attr->bcf_buf_true_size > attr->bcf_buf_size || + !attr->bcf_buf_size) + return -EINVAL; + /* The resumed analysis must only uses the old, first attr. */ + memset(attr, 0, offsetof(union bpf_attr, bcf_buf)); + return -ENOTSUPP; + } + + if (attr->bcf_fd || attr->bcf_buf_true_size || attr->bcf_flags) + return -EINVAL; + if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT | BPF_F_TEST_STATE_FREQ | @@ -2901,6 +2919,9 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) bpf_cap = bpf_token_capable(token, CAP_BPF); err = -EPERM; + if (attr->bcf_buf && !bpf_cap) + goto put_token; + if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && !bpf_cap) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 1d73f165394d..fbe99fbc39ab 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1484,6 +1484,15 @@ enum { BPF_STREAM_STDERR = 2, }; +/* bcf_flags used in BPF_PROG_LOAD command to indicate if the verifier + * requests or the user provides proofs. + */ +enum { + BCF_F_PROOF_REQUESTED = (1U << 0), + BCF_F_PROOF_PROVIDED = (1U << 1), + BCF_F_PROOF_PATH_UNREACHABLE = (1U << 2), +}; + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ @@ -1624,6 +1633,18 @@ union bpf_attr { * verification. */ __s32 keyring_id; + /* BCF buffer for both the condition to be proved required by + * the verifier and the proof provided from user space. + */ + __aligned_u64 bcf_buf; + __u32 bcf_buf_size; + __u32 bcf_buf_true_size; + /* output: BCF fd for loading proof, set by the verifier when + * proof is requested. + */ + __u32 bcf_fd; + /* input/output: proof requested or provided. */ + __u32 bcf_flags; }; struct { /* anonymous struct used by BPF_OBJ_* commands */ -- 2.34.1