The log buffer of common attributes would be confusing with the one in 'union bpf_attr' for BPF_PROG_LOAD and BPF_BTF_LOAD. In order to clarify the usage of these two 'log_buf's, 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, a log message will be written to the log buffer of 'union bpf_attr'. Signed-off-by: Leon Hwang --- include/linux/bpf.h | 3 ++- include/linux/bpf_verifier.h | 2 +- include/linux/btf.h | 3 ++- kernel/bpf/btf.c | 12 +++++++----- kernel/bpf/log.c | 23 ++++++++++++++++++++++- kernel/bpf/syscall.c | 14 ++++++++------ kernel/bpf/verifier.c | 8 ++++---- 7 files changed, 46 insertions(+), 19 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8f6e87f0f3a89..adc0e68cb4e50 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2717,7 +2717,8 @@ int bpf_check_uarg_tail_zero(bpfptr_t uaddr, size_t expected_size, size_t actual_size); /* verify correctness of eBPF program */ -int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size); +int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size, + struct bpf_common_attr *common_attrs); #ifndef CONFIG_BPF_JIT_ALWAYS_ON void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth); diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 020de62bd09cd..2d61afec91c92 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -864,7 +864,7 @@ __printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env, __printf(2, 3) void bpf_log(struct bpf_verifier_log *log, const char *fmt, ...); int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, - char __user *log_buf, u32 log_size); + char __user *log_buf, u32 log_size, const struct bpf_common_attr *common_attrs); void bpf_vlog_reset(struct bpf_verifier_log *log, u64 new_pos); int bpf_vlog_finalize(struct bpf_verifier_log *log, u32 *log_size_actual); diff --git a/include/linux/btf.h b/include/linux/btf.h index 9eda6b113f9b4..c0acb46930bde 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -145,7 +145,8 @@ const char *btf_get_name(const struct btf *btf); void btf_get(struct btf *btf); void btf_put(struct btf *btf); const struct btf_header *btf_header(const struct btf *btf); -int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_sz); +int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_sz, + const struct bpf_common_attr *common_attrs); struct btf *btf_get_by_fd(int fd); int btf_get_info_by_fd(const struct btf *btf, const union bpf_attr *attr, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 64739308902f7..4a17ae4842210 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5771,7 +5771,8 @@ static int finalize_log(struct bpf_verifier_log *log, bpfptr_t uattr, u32 uattr_ return err; } -static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) +static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size, + const struct bpf_common_attr *common_attrs) { bpfptr_t btf_data = make_bpfptr(attr->btf, uattr.is_kernel); char __user *log_ubuf = u64_to_user_ptr(attr->btf_log_buf); @@ -5791,8 +5792,8 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat /* user could have requested verbose verifier output * and supplied buffer to store the verification trace */ - err = bpf_vlog_init(&env->log, attr->btf_log_level, - log_ubuf, attr->btf_log_size); + err = bpf_vlog_init(&env->log, attr->btf_log_level, log_ubuf, attr->btf_log_size, + common_attrs); if (err) goto errout_free; @@ -8028,12 +8029,13 @@ static int __btf_new_fd(struct btf *btf) return anon_inode_getfd("btf", &btf_fops, btf, O_RDONLY | O_CLOEXEC); } -int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) +int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size, + const struct bpf_common_attr *common_attrs) { struct btf *btf; int ret; - btf = btf_parse(attr, uattr, uattr_size); + btf = btf_parse(attr, uattr, uattr_size, common_attrs); if (IS_ERR(btf)) return PTR_ERR(btf); diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index e4983c1303e76..a9a0834884eb9 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -29,12 +29,33 @@ static bool bpf_verifier_log_attr_valid(const struct bpf_verifier_log *log) } int bpf_vlog_init(struct bpf_verifier_log *log, u32 log_level, - char __user *log_buf, u32 log_size) + char __user *log_buf, u32 log_size, const struct bpf_common_attr *common_attrs) { + u32 log_true_size; + int err; + log->level = log_level; log->ubuf = log_buf; log->len_total = log_size; + if (log_buf && common_attrs && common_attrs->log_buf && + ((u64) log_buf != common_attrs->log_buf || log_level != common_attrs->log_level || + log_size != common_attrs->log_size)) { + if (!bpf_verifier_log_attr_valid(log)) + return -EINVAL; + bpf_log(log, "Conflict log configs between bpf_attr and common_attr.\n"); + err = bpf_vlog_finalize(log, &log_true_size); + if (err) + return err; + return -EINVAL; + } + + if (!log_buf && common_attrs && common_attrs->log_buf) { + log->level = common_attrs->log_level; + log->ubuf = u64_to_user_ptr(common_attrs->log_buf); + log->len_total = common_attrs->log_size; + } + /* log attributes have to be sane */ if (!bpf_verifier_log_attr_valid(log)) return -EINVAL; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d49f822ceea12..5e5cf0262a14e 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2764,7 +2764,8 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) /* last field in 'union bpf_attr' used by this command */ #define BPF_PROG_LOAD_LAST_FIELD fd_array_cnt -static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) +static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size, + struct bpf_common_attr *common_attrs) { enum bpf_prog_type type = attr->prog_type; struct bpf_prog *prog, *dst_prog = NULL; @@ -2976,7 +2977,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) goto free_prog_sec; /* run eBPF verifier */ - err = bpf_check(&prog, attr, uattr, uattr_size); + err = bpf_check(&prog, attr, uattr, uattr_size, common_attrs); if (err < 0) goto free_used_maps; @@ -5292,7 +5293,8 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr, #define BPF_BTF_LOAD_LAST_FIELD btf_token_fd -static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size) +static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size, + struct bpf_common_attr *common_attrs) { struct bpf_token *token = NULL; @@ -5319,7 +5321,7 @@ static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_ bpf_token_put(token); - return btf_new_fd(attr, uattr, uattr_size); + return btf_new_fd(attr, uattr, uattr_size, common_attrs); } #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD fd_by_id_token_fd @@ -6036,7 +6038,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, err = map_freeze(&attr); break; case BPF_PROG_LOAD: - err = bpf_prog_load(&attr, uattr, size); + err = bpf_prog_load(&attr, uattr, size, &common_attrs); break; case BPF_OBJ_PIN: err = bpf_obj_pin(&attr); @@ -6081,7 +6083,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size, err = bpf_raw_tracepoint_open(&attr); break; case BPF_BTF_LOAD: - err = bpf_btf_load(&attr, uattr, size); + err = bpf_btf_load(&attr, uattr, size, &common_attrs); break; case BPF_BTF_GET_FD_BY_ID: err = bpf_btf_get_fd_by_id(&attr); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b9394f8fac0ed..77b57289ec097 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -24584,7 +24584,8 @@ static int compute_scc(struct bpf_verifier_env *env) return err; } -int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size) +int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size, + struct bpf_common_attr *common_attrs) { u64 start_time = ktime_get_ns(); struct bpf_verifier_env *env; @@ -24633,9 +24634,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 /* user could have requested verbose verifier output * and supplied buffer to store the verification trace */ - ret = bpf_vlog_init(&env->log, attr->log_level, - (char __user *) (unsigned long) attr->log_buf, - attr->log_size); + ret = bpf_vlog_init(&env->log, attr->log_level, u64_to_user_ptr(attr->log_buf), + attr->log_size, common_attrs); if (ret) goto err_unlock; -- 2.50.1