Similar to the syscall common attrs support for map_create [1], add the
syscall common attrs support for link_create.

Create and finalize the internal verifier log instance.

Then, report the error messages for invalid prog fd, invalid attach type,
and invalid prog type.

Links:
[1] https://lore.kernel.org/bpf/[email protected]/

Signed-off-by: Leon Hwang <[email protected]>
---
 include/linux/bpf_verifier.h |  1 +
 kernel/bpf/log.c             | 19 +++++++++++-------
 kernel/bpf/syscall.c         | 39 ++++++++++++++++++++++++++++++------
 3 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 951a90458d18..de9845526ce0 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -896,6 +896,7 @@ struct bpf_verifier_log *bpf_log_attr_create_vlog(struct 
bpf_log_attr *attr_log,
                                                  struct bpf_common_attr 
*common, bpfptr_t uattr,
                                                  u32 size);
 int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log 
*log);
+int bpf_log_attr_report_size(struct bpf_log_attr *attr, u32 size);
 
 #define BPF_MAX_SUBPROGS 256
 
diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c
index 5432c0fc442b..2bcd62d9ad88 100644
--- a/kernel/bpf/log.c
+++ b/kernel/bpf/log.c
@@ -884,17 +884,22 @@ struct bpf_verifier_log *bpf_log_attr_create_vlog(struct 
bpf_log_attr *attr_log,
        return log;
 }
 
+int bpf_log_attr_report_size(struct bpf_log_attr *attr, u32 size)
+{
+       if (attr->offsetof_true_size &&
+           copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &size, 
sizeof(size)))
+               return -EFAULT;
+
+       return 0;
+}
+
 int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log 
*log)
 {
        u32 log_true_size;
-       int err;
+       int err, ret;
 
        err = bpf_vlog_finalize(log, &log_true_size);
 
-       if (attr->offsetof_true_size &&
-           copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, 
&log_true_size,
-                                 sizeof(log_true_size)))
-               return -EFAULT;
-
-       return err;
+       ret = bpf_log_attr_report_size(attr, log_true_size);
+       return ret ? ret : err;
 }
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 849bc9136299..201658b75ab7 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -5856,8 +5856,11 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
 }
 
 #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.path_fd
-static int link_create(union bpf_attr *attr, bpfptr_t uattr)
+static int link_create(union bpf_attr *attr, bpfptr_t uattr, struct 
bpf_common_attr *attr_common,
+                      bpfptr_t uattr_common, u32 size_common)
 {
+       struct bpf_verifier_log *log;
+       struct bpf_log_attr attr_log;
        struct bpf_prog *prog;
        int ret;
 
@@ -5867,14 +5870,28 @@ static int link_create(union bpf_attr *attr, bpfptr_t 
uattr)
        if (attr->link_create.attach_type == BPF_STRUCT_OPS)
                return bpf_struct_ops_link_create(attr);
 
+       log = bpf_log_attr_create_vlog(&attr_log, attr_common, uattr_common, 
size_common);
+       if (IS_ERR(log))
+               return PTR_ERR(log);
+
        prog = bpf_prog_get(attr->link_create.prog_fd);
-       if (IS_ERR(prog))
-               return PTR_ERR(prog);
+       if (IS_ERR(prog)) {
+               bpf_log(log, "Invalid prog_fd.\n");
+               ret = PTR_ERR(prog);
+               prog = NULL;
+               goto out;
+       }
 
        ret = bpf_prog_attach_check_attach_type(prog,
                                                attr->link_create.attach_type);
-       if (ret)
+       if (ret) {
+               bpf_log(log, "Invalid attach_type.\n");
                goto out;
+       }
+
+       ret = bpf_log_attr_report_size(&attr_log, 0);
+       if (ret)
+               goto put_prog;
 
        switch (prog->type) {
        case BPF_PROG_TYPE_CGROUP_SKB:
@@ -5953,12 +5970,22 @@ static int link_create(union bpf_attr *attr, bpfptr_t 
uattr)
                        ret = bpf_uprobe_multi_link_attach(attr, prog);
                break;
        default:
+               bpf_log(log, "Invalid prog type.\n");
                ret = -EINVAL;
        }
 
 out:
-       if (ret < 0)
+       if (ret < 0) {
+               int err = bpf_log_attr_finalize(&attr_log, log);
+
+               ret = err ? err : ret;
+       }
+
+put_prog:
+       if (ret < 0 && prog)
                bpf_prog_put(prog);
+
+       kfree(log);
        return ret;
 }
 
@@ -6530,7 +6557,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, 
unsigned int size,
                err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH);
                break;
        case BPF_LINK_CREATE:
-               err = link_create(&attr, uattr);
+               err = link_create(&attr, uattr, &attr_common, uattr_common, 
size_common);
                break;
        case BPF_LINK_UPDATE:
                err = link_update(&attr);
-- 
2.55.0


Reply via email to