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 --- kernel/bpf/syscall.c | 55 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 2bdc0b43ec832..698c30ff99486 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -6092,11 +6092,57 @@ static int prog_stream_read(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, + bool *log_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) { + *log_common_attrs = true; + 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, bool log_common_attrs) { if (!attr->log_true_size) return 0; + if (log_common_attrs) + return __copy_common_attr_log_true_size(uattr_common, size_common, + &attr->log_true_size); + 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))) @@ -6109,6 +6155,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, bpfptr_t uattr_common, unsigned int size_common) { struct bpf_common_attr common_attrs; + bool log_common_attrs = false; union bpf_attr attr; int err, ret; @@ -6158,9 +6205,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, &log_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, log_common_attrs); err = ret ? ret : err; break; case BPF_OBJ_PIN: -- 2.51.0