From: Björn Töpel <bjorn.to...@intel.com> Break up bpf_prog_load into one function that allocates, initializes and verifies a bpf program, and one that allocates a file descriptor.
The former function will be used in a later commit to load a builtin BPF program. Signed-off-by: Björn Töpel <bjorn.to...@intel.com> --- kernel/bpf/syscall.c | 59 ++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index aa05aa38f4a8..ee1328625330 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1441,7 +1441,8 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, /* last field in 'union bpf_attr' used by this command */ #define BPF_PROG_LOAD_LAST_FIELD func_info_cnt -static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) +static struct bpf_prog *__bpf_prog_load(union bpf_attr *attr, + union bpf_attr __user *uattr) { enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog; @@ -1450,45 +1451,45 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) bool is_gpl; if (CHECK_ATTR(BPF_PROG_LOAD)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | BPF_F_ANY_ALIGNMENT)) - return -EINVAL; + return ERR_PTR(-EINVAL); if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && !capable(CAP_SYS_ADMIN)) - return -EPERM; + return ERR_PTR(-EPERM); /* copy eBPF program license from user space */ if (strncpy_from_user(license, u64_to_user_ptr(attr->license), sizeof(license) - 1) < 0) - return -EFAULT; + return ERR_PTR(-EFAULT); license[sizeof(license) - 1] = 0; /* eBPF programs must be GPL compatible to use GPL-ed functions */ is_gpl = license_is_gpl_compatible(license); if (attr->insn_cnt == 0 || attr->insn_cnt > BPF_MAXINSNS) - return -E2BIG; + return ERR_PTR(-E2BIG); if (type == BPF_PROG_TYPE_KPROBE && attr->kern_version != LINUX_VERSION_CODE) - return -EINVAL; + return ERR_PTR(-EINVAL); if (type != BPF_PROG_TYPE_SOCKET_FILTER && type != BPF_PROG_TYPE_CGROUP_SKB && !capable(CAP_SYS_ADMIN)) - return -EPERM; + return ERR_PTR(-EPERM); bpf_prog_load_fixup_attach_type(attr); if (bpf_prog_load_check_attach_type(type, attr->expected_attach_type)) - return -EINVAL; + return ERR_PTR(-EINVAL); /* plain bpf_prog allocation */ prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); if (!prog) - return -ENOMEM; + return ERR_PTR(-ENOMEM); prog->expected_attach_type = attr->expected_attach_type; @@ -1544,20 +1545,8 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) if (err) goto free_used_maps; - err = bpf_prog_new_fd(prog); - if (err < 0) { - /* failed to allocate fd. - * bpf_prog_put() is needed because the above - * bpf_prog_alloc_id() has published the prog - * to the userspace and the userspace may - * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. - */ - bpf_prog_put(prog); - return err; - } - bpf_prog_kallsyms_add(prog); - return err; + return prog; free_used_maps: kvfree(prog->aux->func_info); @@ -1570,7 +1559,29 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) security_bpf_prog_free(prog->aux); free_prog_nouncharge: bpf_prog_free(prog); - return err; + return ERR_PTR(err); +} + +static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) +{ + struct bpf_prog *prog = __bpf_prog_load(attr, uattr); + int fd; + + if (IS_ERR(prog)) + return PTR_ERR(prog); + + fd = bpf_prog_new_fd(prog); + if (fd < 0) { + /* failed to allocate fd. + * bpf_prog_put() is needed because the above + * bpf_prog_alloc_id() has published the prog + * to the userspace and the userspace may + * have refcnt-ed it through BPF_PROG_GET_FD_BY_ID. + */ + bpf_prog_put(prog); + } + + return fd; } #define BPF_OBJ_LAST_FIELD file_flags -- 2.19.1