The bpf_attr union is used to pass config into the bpf syscall. In many cases the union members can contain user pointers. In Morello PCuABI a user pointer is a 128-bit capability (plus 1 out-of-band tag bit) so the __aligned_u64 type is not big enough to hold it. Use the __kernel_aligned_uintptr_t type instead, which is big enough on the affected architectures while remaining __aligned_64 on others.
Use copy_from_user_with_ptr where blocks of memory containing pointers are being copied to preserve capabilities.
Signed-off-by: Zachary Leaf zachary.leaf@arm.com --- include/uapi/linux/bpf.h | 14 +++++++------- kernel/bpf/syscall.c | 6 +++--- kernel/bpf/verifier.c | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index d14b10b85e51..98a23f9a540e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1330,11 +1330,11 @@ union bpf_attr { struct { /* anonymous struct used by BPF_PROG_LOAD command */ __u32 prog_type; /* one of enum bpf_prog_type */ __u32 insn_cnt; - __aligned_u64 insns; - __aligned_u64 license; + __kernel_aligned_uintptr_t insns; + __kernel_aligned_uintptr_t license; __u32 log_level; /* verbosity level of verifier */ __u32 log_size; /* size of user buffer */ - __aligned_u64 log_buf; /* user supplied buffer */ + __kernel_aligned_uintptr_t log_buf; /* user supplied buffer */ __u32 kern_version; /* not used */ __u32 prog_flags; char prog_name[BPF_OBJ_NAME_LEN]; @@ -1346,10 +1346,10 @@ union bpf_attr { __u32 expected_attach_type; __u32 prog_btf_fd; /* fd pointing to BTF type data */ __u32 func_info_rec_size; /* userspace bpf_func_info size */ - __aligned_u64 func_info; /* func info */ + __kernel_aligned_uintptr_t func_info; /* func info */ __u32 func_info_cnt; /* number of bpf_func_info records */ __u32 line_info_rec_size; /* userspace bpf_line_info size */ - __aligned_u64 line_info; /* line info */ + __kernel_aligned_uintptr_t line_info; /* line info */ __u32 line_info_cnt; /* number of bpf_line_info records */ __u32 attach_btf_id; /* in-kernel BTF type id to attach to */ union { @@ -1359,8 +1359,8 @@ union bpf_attr { __u32 attach_btf_obj_fd; }; __u32 core_relo_cnt; /* number of bpf_core_relo */ - __aligned_u64 fd_array; /* array of FDs */ - __aligned_u64 core_relos; + __kernel_aligned_uintptr_t fd_array; /* array of FDs */ + __kernel_aligned_uintptr_t core_relos; __u32 core_relo_rec_size; /* sizeof(struct bpf_core_relo) */ };
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index cdaa1152436a..518ab0e9f2a4 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2233,7 +2233,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
/* copy eBPF program license from user space */ if (strncpy_from_bpfptr(license, - make_bpfptr(attr->license, uattr.is_kernel), + make_bpfptr_fixed(attr->license, uattr.is_kernel), sizeof(license) - 1) < 0) return -EFAULT; license[sizeof(license) - 1] = 0; @@ -2320,7 +2320,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr)
err = -EFAULT; if (copy_from_bpfptr(prog->insns, - make_bpfptr(attr->insns, uattr.is_kernel), + make_bpfptr_fixed(attr->insns, uattr.is_kernel), bpf_prog_insn_size(prog)) != 0) goto free_prog_sec;
@@ -4633,7 +4633,7 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
/* copy attributes from user space, may be less than sizeof(bpf_attr) */ memset(&attr, 0, sizeof(attr)); - if (copy_from_bpfptr(&attr, uattr, size) != 0) + if (copy_from_bpfptr_with_ptr(&attr, uattr, size) != 0) return -EFAULT;
err = security_bpf(cmd, &attr, size); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index d175b70067b3..41827b00492e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10296,7 +10296,7 @@ static int check_btf_func(struct bpf_verifier_env *env, prog = env->prog; btf = prog->aux->btf;
- urecord = make_bpfptr(attr->func_info, uattr.is_kernel); + urecord = make_bpfptr_fixed(attr->func_info, uattr.is_kernel); min_size = min_t(u32, krec_size, urec_size);
krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN); @@ -10440,7 +10440,7 @@ static int check_btf_line(struct bpf_verifier_env *env,
s = 0; sub = env->subprog_info; - ulinfo = make_bpfptr(attr->line_info, uattr.is_kernel); + ulinfo = make_bpfptr_fixed(attr->line_info, uattr.is_kernel); expected_size = sizeof(struct bpf_line_info); ncopy = min_t(u32, expected_size, rec_size); for (i = 0; i < nr_linfo; i++) { @@ -10558,7 +10558,7 @@ static int check_core_relo(struct bpf_verifier_env *env, rec_size % sizeof(u32)) return -EINVAL;
- u_core_relo = make_bpfptr(attr->core_relos, uattr.is_kernel); + u_core_relo = make_bpfptr_fixed(attr->core_relos, uattr.is_kernel); expected_size = sizeof(struct bpf_core_relo); ncopy = min_t(u32, expected_size, rec_size);
@@ -14387,7 +14387,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr) env->insn_aux_data[i].orig_idx = i; env->prog = *prog; env->ops = bpf_verifier_ops[env->prog->type]; - env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel); + env->fd_array = make_bpfptr_fixed(attr->fd_array, uattr.is_kernel); is_priv = bpf_capable();
bpf_get_btf_vmlinux(); @@ -14401,7 +14401,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr) * and supplied buffer to store the verification trace */ log->level = attr->log_level; - log->ubuf = (char __user *) (unsigned long) attr->log_buf; + log->ubuf = (char __user *) attr->log_buf; log->len_total = attr->log_size;
/* log attributes have to be sane */