Skip to content
4 changes: 3 additions & 1 deletion include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -2913,7 +2913,9 @@ 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);
struct bpf_log_attr;
int bpf_check(struct bpf_prog **fp, union bpf_attr *attr, bpfptr_t uattr,
struct bpf_log_attr *attr_log);

#ifndef CONFIG_BPF_JIT_ALWAYS_ON
void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth);
Expand Down
17 changes: 17 additions & 0 deletions include/linux/bpf_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,23 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log)
return log && log->level;
}

struct bpf_log_attr {
u32 offsetof_true_size;
u32 uattr_size;
bpfptr_t uattr;
};

int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
bpfptr_t uattr, u32 size, struct bpf_common_attr *attr_common,
bpfptr_t uattr_common, u32 size_common);
int bpf_btf_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
bpfptr_t uattr, u32 size, struct bpf_common_attr *attr_common,
bpfptr_t uattr_common, u32 size_common);
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);

#define BPF_MAX_SUBPROGS 256

struct bpf_subprog_arg_info {
Expand Down
3 changes: 2 additions & 1 deletion include/linux/btf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
struct bpf_log_attr;
int btf_new_fd(const union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_attr *attr_log);
struct btf *btf_get_by_fd(int fd);
int btf_get_info_by_fd(const struct btf *btf,
const union bpf_attr *attr,
Expand Down
3 changes: 2 additions & 1 deletion include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,8 @@ asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
asmlinkage long sys_getrandom(char __user *buf, size_t count,
unsigned int flags);
asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags);
asmlinkage long sys_bpf(int cmd, union bpf_attr __user *attr, unsigned int size);
asmlinkage long sys_bpf(int cmd, union bpf_attr __user *attr, unsigned int size,
struct bpf_common_attr __user *attr_common, unsigned int size_common);
asmlinkage long sys_execveat(int dfd, const char __user *filename,
const char __user *const __user *argv,
const char __user *const __user *envp, int flags);
Expand Down
8 changes: 8 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,7 @@ enum bpf_cmd {
BPF_PROG_STREAM_READ_BY_FD,
BPF_PROG_ASSOC_STRUCT_OPS,
__MAX_BPF_CMD,
BPF_COMMON_ATTRS = 1 << 16, /* Indicate carrying syscall common attrs. */
};

enum bpf_map_type {
Expand Down Expand Up @@ -1500,6 +1501,13 @@ struct bpf_stack_build_id {
};
};

struct bpf_common_attr {
__u64 log_buf;
__u32 log_size;
__u32 log_level;
__u32 log_true_size;
};

#define BPF_OBJ_NAME_LEN 16U

enum {
Expand Down
26 changes: 6 additions & 20 deletions kernel/bpf/btf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5857,22 +5857,8 @@ static int btf_check_type_tags(struct btf_verifier_env *env,
return 0;
}

static int finalize_log(struct bpf_verifier_log *log, bpfptr_t uattr, u32 uattr_size)
{
u32 log_true_size;
int err;

err = bpf_vlog_finalize(log, &log_true_size);

if (uattr_size >= offsetofend(union bpf_attr, btf_log_true_size) &&
copy_to_bpfptr_offset(uattr, offsetof(union bpf_attr, btf_log_true_size),
&log_true_size, sizeof(log_true_size)))
err = -EFAULT;

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,
struct bpf_log_attr *attr_log)
{
bpfptr_t btf_data = make_bpfptr(attr->btf, uattr.is_kernel);
char __user *log_ubuf = u64_to_user_ptr(attr->btf_log_buf);
Expand Down Expand Up @@ -5954,7 +5940,7 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
}
}

err = finalize_log(&env->log, uattr, uattr_size);
err = bpf_log_attr_finalize(attr_log, &env->log);
if (err)
goto errout_free;

Expand All @@ -5966,7 +5952,7 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
btf_free_struct_meta_tab(btf);
errout:
/* overwrite err with -ENOSPC or -EFAULT */
ret = finalize_log(&env->log, uattr, uattr_size);
ret = bpf_log_attr_finalize(attr_log, &env->log);
if (ret)
err = ret;
errout_free:
Expand Down Expand Up @@ -8137,12 +8123,12 @@ 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, struct bpf_log_attr *attr_log)
{
struct btf *btf;
int ret;

btf = btf_parse(attr, uattr, uattr_size);
btf = btf_parse(attr, uattr, attr_log);
if (IS_ERR(btf))
return PTR_ERR(btf);

Expand Down
101 changes: 101 additions & 0 deletions kernel/bpf/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,3 +863,104 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
}
print_verifier_state(env, vstate, frameno, false);
}

static void bpf_log_attr_init(struct bpf_log_attr *attr_log, int offsetof_true_size, bpfptr_t uattr,
u32 uattr_size)
{
memset(attr_log, 0, sizeof(*attr_log));
attr_log->offsetof_true_size = offsetof_true_size;
attr_log->uattr_size = uattr_size;
attr_log->uattr = uattr;
}

static bool bpf_log_attrs_diff(struct bpf_common_attr *common, u64 log_buf, u32 log_size,
u32 log_level)
{
return log_buf && common->log_buf && (log_buf != common->log_buf ||
log_size != common->log_size ||
log_level != common->log_level);
}

int bpf_prog_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
bpfptr_t uattr, u32 size, struct bpf_common_attr *attr_common,
bpfptr_t uattr_common, u32 size_common)
{
if (bpf_log_attrs_diff(attr_common, attr->log_buf, attr->log_size, attr->log_level))
return -EINVAL;

if (!attr->log_buf && attr_common->log_buf) {
attr->log_buf = attr_common->log_buf;
attr->log_size = attr_common->log_size;
attr->log_level = attr_common->log_level;
bpf_log_attr_init(attr_log, offsetof(struct bpf_common_attr, log_true_size),
uattr_common, size_common);
} else {
bpf_log_attr_init(attr_log, offsetof(union bpf_attr, log_true_size), uattr, size);
}
return 0;
}

int bpf_btf_load_log_attr_init(struct bpf_log_attr *attr_log, union bpf_attr *attr,
bpfptr_t uattr, u32 size, struct bpf_common_attr *attr_common,
bpfptr_t uattr_common, u32 size_common)
{
if (bpf_log_attrs_diff(attr_common, attr->btf_log_buf, attr->btf_log_size,
attr->btf_log_level))
return -EINVAL;

if (!attr->btf_log_buf && attr_common->log_buf) {
attr->btf_log_buf = attr_common->log_buf;
attr->btf_log_size = attr_common->log_size;
attr->btf_log_level = attr_common->log_level;
bpf_log_attr_init(attr_log, offsetof(struct bpf_common_attr, log_true_size),
uattr_common, size_common);
} else {
bpf_log_attr_init(attr_log, offsetof(union bpf_attr, btf_log_true_size), uattr,
size);
}
return 0;
}

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)
{
struct bpf_verifier_log *log;
int err;

if (!common->log_buf)
return NULL;

log = kzalloc(sizeof(*log), GFP_KERNEL);
if (!log)
return ERR_PTR(-ENOMEM);

err = bpf_vlog_init(log, common->log_level, u64_to_user_ptr(common->log_buf),
common->log_size);
if (err) {
kfree(log);
return ERR_PTR(err);
}

bpf_log_attr_init(attr_log, offsetof(struct bpf_common_attr, log_true_size), uattr, size);
return log;
}

int bpf_log_attr_finalize(struct bpf_log_attr *attr, struct bpf_verifier_log *log)
{
u32 log_true_size;
size_t size;
int err;

if (!log)
return 0;

err = bpf_vlog_finalize(log, &log_true_size);

size = sizeof(log_true_size);
if (attr->uattr_size >= attr->offsetof_true_size + size &&
copy_to_bpfptr_offset(attr->uattr, attr->offsetof_true_size, &log_true_size, size))
err = -EFAULT;

return err;
}
Loading
Loading