The log buffer of common attributes would be confusing with the one in 'union bpf_attr' for BPF_PROG_LOAD.
In order to clarify the usage of these two log buffers, they both can be used for logging if:
* They are same, including 'log_buf', 'log_level' and 'log_size'. * One of them is missing, then another one will be used for logging.
If they both have 'log_buf' but they are not same totally, return -EUSERS.
Signed-off-by: Leon Hwang leon.hwang@linux.dev --- kernel/bpf/syscall.c | 51 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 1739601fb7bd..ad565f569a4f 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -6160,14 +6160,55 @@ static int prog_assoc_struct_ops(union bpf_attr *attr) return ret; }
-static int copy_prog_load_log_true_size(union bpf_attr *attr, bpfptr_t uattr, unsigned int size) +static int check_log_attrs(u64 log_buf, u32 log_size, u32 log_level, + struct bpf_common_attr *common_attrs) +{ + if (log_buf && common_attrs->log_buf && (log_buf != common_attrs->log_buf || + log_size != common_attrs->log_size || + log_level != common_attrs->log_level)) + return -EUSERS; + + return 0; +} + +static int check_prog_load_log_attrs(union bpf_attr *attr, struct bpf_common_attr *common_attrs) +{ + int err; + + err = check_log_attrs(attr->log_buf, attr->log_size, attr->log_level, common_attrs); + if (err) + return err; + + if (!attr->log_buf && common_attrs->log_buf) { + attr->log_buf = common_attrs->log_buf; + attr->log_size = common_attrs->log_size; + attr->log_level = common_attrs->log_level; + } + + return 0; +} + +static int copy_common_attr_log_true_size(bpfptr_t uattr, unsigned int size, u32 *log_true_size) +{ + if (size >= offsetofend(struct bpf_common_attr, log_true_size) && + copy_to_bpfptr_offset(uattr, offsetof(struct bpf_common_attr, log_true_size), + log_true_size, sizeof(*log_true_size))) + return -EFAULT; + + return 0; +} + +static int copy_prog_load_log_true_size(union bpf_attr *attr, bpfptr_t uattr, unsigned int size, + struct bpf_common_attr *common_attrs, bpfptr_t uattr_common, + unsigned int size_common) { if (size >= offsetofend(union bpf_attr, log_true_size) && copy_to_bpfptr_offset(uattr, offsetof(union bpf_attr, log_true_size), &attr->log_true_size, sizeof(attr->log_true_size))) return -EFAULT;
- return 0; + return copy_common_attr_log_true_size(uattr_common, size_common, + &attr->log_true_size); }
static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, @@ -6225,9 +6266,13 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, err = map_freeze(&attr); break; case BPF_PROG_LOAD: + err = check_prog_load_log_attrs(&attr, &common_attrs); + if (err) + break; attr.log_true_size = 0; err = bpf_prog_load(&attr, uattr); - ret = copy_prog_load_log_true_size(&attr, uattr, size); + ret = copy_prog_load_log_true_size(&attr, uattr, size, &common_attrs, uattr_common, + size_common); err = ret ? ret : err; break; case BPF_OBJ_PIN: