Commit 7337224f authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Alexei Starovoitov

bpf: Improve the info.func_info and info.func_info_rec_size behavior

1) When bpf_dump_raw_ok() == false and the kernel can provide >=1
   func_info to the userspace, the current behavior is setting
   the info.func_info_cnt to 0 instead of setting info.func_info
   to 0.

   It is different from the behavior in jited_func_lens/nr_jited_func_lens,
   jited_ksyms/nr_jited_ksyms...etc.

   This patch fixes it. (i.e. set func_info to 0 instead of
   func_info_cnt to 0 when bpf_dump_raw_ok() == false).

2) When the userspace passed in info.func_info_cnt == 0, the kernel
   will set the expected func_info size back to the
   info.func_info_rec_size.  It is a way for the userspace to learn
   the kernel expected func_info_rec_size introduced in
   commit 838e9690 ("bpf: Introduce bpf_func_info").

   An exception is the kernel expected size is not set when
   func_info is not available for a bpf_prog.  This makes the
   returned info.func_info_rec_size has different values
   depending on the returned value of info.func_info_cnt.

   This patch sets the kernel expected size to info.func_info_rec_size
   independent of the info.func_info_cnt.

3) The current logic only rejects invalid func_info_rec_size if
   func_info_cnt is non zero.  This patch also rejects invalid
   nonzero info.func_info_rec_size and not equal to the kernel
   expected size.

4) Set info.btf_id as long as prog->aux->btf != NULL.  That will
   setup the later copy_to_user() codes look the same as others
   which then easier to understand and maintain.

   prog->aux->btf is not NULL only if prog->aux->func_info_cnt > 0.

   Breaking up info.btf_id from prog->aux->func_info_cnt is needed
   for the later line info patch anyway.

   A similar change is made to bpf_get_prog_name().

Fixes: 838e9690 ("bpf: Introduce bpf_func_info")
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 30da46b5
...@@ -410,7 +410,7 @@ static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) ...@@ -410,7 +410,7 @@ static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym)
sym = bin2hex(sym, prog->tag, sizeof(prog->tag)); sym = bin2hex(sym, prog->tag, sizeof(prog->tag));
/* prog->aux->name will be ignored if full btf name is available */ /* prog->aux->name will be ignored if full btf name is available */
if (prog->aux->btf) { if (prog->aux->func_info_cnt) {
type = btf_type_by_id(prog->aux->btf, type = btf_type_by_id(prog->aux->btf,
prog->aux->func_info[prog->aux->func_idx].type_id); prog->aux->func_info[prog->aux->func_idx].type_id);
func_name = btf_name_by_offset(prog->aux->btf, type->name_off); func_name = btf_name_by_offset(prog->aux->btf, type->name_off);
......
...@@ -2083,6 +2083,12 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, ...@@ -2083,6 +2083,12 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
return -EFAULT; return -EFAULT;
} }
if ((info.func_info_cnt || info.func_info_rec_size) &&
info.func_info_rec_size != sizeof(struct bpf_func_info))
return -EINVAL;
info.func_info_rec_size = sizeof(struct bpf_func_info);
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
info.jited_prog_len = 0; info.jited_prog_len = 0;
info.xlated_prog_len = 0; info.xlated_prog_len = 0;
...@@ -2226,35 +2232,23 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, ...@@ -2226,35 +2232,23 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
} }
} }
if (prog->aux->btf) { if (prog->aux->btf)
u32 krec_size = sizeof(struct bpf_func_info);
u32 ucnt, urec_size;
info.btf_id = btf_id(prog->aux->btf); info.btf_id = btf_id(prog->aux->btf);
ucnt = info.func_info_cnt; ulen = info.func_info_cnt;
info.func_info_cnt = prog->aux->func_info_cnt; info.func_info_cnt = prog->aux->func_info_cnt;
urec_size = info.func_info_rec_size; if (info.func_info_cnt && ulen) {
info.func_info_rec_size = krec_size;
if (ucnt) {
/* expect passed-in urec_size is what the kernel expects */
if (urec_size != info.func_info_rec_size)
return -EINVAL;
if (bpf_dump_raw_ok()) { if (bpf_dump_raw_ok()) {
char __user *user_finfo; char __user *user_finfo;
user_finfo = u64_to_user_ptr(info.func_info); user_finfo = u64_to_user_ptr(info.func_info);
ucnt = min_t(u32, info.func_info_cnt, ucnt); ulen = min_t(u32, info.func_info_cnt, ulen);
if (copy_to_user(user_finfo, prog->aux->func_info, if (copy_to_user(user_finfo, prog->aux->func_info,
krec_size * ucnt)) info.func_info_rec_size * ulen))
return -EFAULT; return -EFAULT;
} else { } else {
info.func_info_cnt = 0; info.func_info = 0;
}
} }
} else {
info.func_info_cnt = 0;
} }
done: done:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment