From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Greg KH <gregkh@linuxfoundation.org>,
Jiri Kosina <jikos@kernel.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
Yonghong Song <yhs@fb.com>,
John Fastabend <john.fastabend@gmail.com>,
KP Singh <kpsingh@kernel.org>, Shuah Khan <shuah@kernel.org>,
Dave Marchevsky <davemarchevsky@fb.com>,
Joe Stringer <joe@cilium.io>, Jonathan Corbet <corbet@lwn.net>
Cc: Tero Kristo <tero.kristo@linux.intel.com>,
linux-kernel@vger.kernel.org, linux-input@vger.kernel.org,
netdev@vger.kernel.org, bpf@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
Benjamin Tissoires <benjamin.tissoires@redhat.com>
Subject: [PATCH bpf-next v5 02/17] bpf/verifier: allow kfunc to return an allocated mem
Date: Wed, 18 May 2022 22:59:09 +0200 [thread overview]
Message-ID: <20220518205924.399291-3-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20220518205924.399291-1-benjamin.tissoires@redhat.com>
When a kfunc is not returning a pointer to a struct but to a plain type,
we can consider it is a valid allocated memory assuming that:
- one of the arguments is called rdonly_buf_size
- or one of the arguments is called rdwr_buf_size
- and this argument is a const from the caller point of view
We can then use this parameter as the size of the allocated memory.
The memory is either read-only or read-write based on the name
of the size parameter.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
changes in v5:
- updated PTR_TO_MEM comment in btf.c to match upstream
- make it read-only or read-write based on the name of size
new in v4
---
include/linux/btf.h | 7 +++++
kernel/bpf/btf.c | 41 +++++++++++++++++++++++-
kernel/bpf/verifier.c | 72 +++++++++++++++++++++++++++++++++----------
3 files changed, 102 insertions(+), 18 deletions(-)
diff --git a/include/linux/btf.h b/include/linux/btf.h
index 2611cea2c2b6..2a4feafc083e 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -343,6 +343,13 @@ static inline struct btf_param *btf_params(const struct btf_type *t)
return (struct btf_param *)(t + 1);
}
+struct bpf_reg_state;
+
+bool btf_is_kfunc_arg_mem_size(const struct btf *btf,
+ const struct btf_param *arg,
+ const struct bpf_reg_state *reg,
+ const char *name);
+
#ifdef CONFIG_BPF_SYSCALL
struct bpf_prog;
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 7bccaa4646e5..2d11d178807c 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -6049,6 +6049,31 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf,
return true;
}
+bool btf_is_kfunc_arg_mem_size(const struct btf *btf,
+ const struct btf_param *arg,
+ const struct bpf_reg_state *reg,
+ const char *name)
+{
+ int len, target_len = strlen(name);
+ const struct btf_type *t;
+ const char *param_name;
+
+ t = btf_type_skip_modifiers(btf, arg->type, NULL);
+ if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
+ return false;
+
+ param_name = btf_name_by_offset(btf, arg->name_off);
+ if (str_is_empty(param_name))
+ return false;
+ len = strlen(param_name);
+ if (len != target_len)
+ return false;
+ if (strncmp(param_name, name, target_len))
+ return false;
+
+ return true;
+}
+
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
const struct btf *btf, u32 func_id,
struct bpf_reg_state *regs,
@@ -6198,7 +6223,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
if (reg->type == PTR_TO_BTF_ID) {
reg_btf = reg->btf;
reg_ref_id = reg->btf_id;
- /* Ensure only one argument is referenced PTR_TO_BTF_ID */
+ /* Ensure only one argument is reference PTR_TO_BTF_ID or PTR_TO_MEM */
if (reg->ref_obj_id) {
if (ref_obj_id) {
bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
@@ -6258,6 +6283,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
i++;
continue;
}
+
+ if (rel && reg->ref_obj_id) {
+ /* Ensure only one argument is referenced PTR_TO_BTF_ID or PTR_TO_MEM */
+ if (ref_obj_id) {
+ bpf_log(log,
+ "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
+ regno,
+ reg->ref_obj_id,
+ ref_obj_id);
+ return -EFAULT;
+ }
+ ref_regno = regno;
+ ref_obj_id = reg->ref_obj_id;
+ }
}
resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9b59581026f8..084319073064 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -7219,13 +7219,14 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
int *insn_idx_p)
{
const struct btf_type *t, *func, *func_proto, *ptr_type;
- struct bpf_reg_state *regs = cur_regs(env);
+ struct bpf_reg_state *reg, *regs = cur_regs(env);
const char *func_name, *ptr_type_name;
- u32 i, nargs, func_id, ptr_type_id;
+ u32 i, nargs, func_id, ptr_type_id, regno;
int err, insn_idx = *insn_idx_p;
const struct btf_param *args;
struct btf *desc_btf;
bool acq;
+ size_t reg_rw_size = 0, reg_ro_size = 0;
/* skip for now, but return error when we find this in fixup_kfunc_call */
if (!insn->imm)
@@ -7266,8 +7267,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
}
- for (i = 0; i < CALLER_SAVED_REGS; i++)
- mark_reg_not_init(env, regs, caller_saved[i]);
+ /* reset REG_0 */
+ mark_reg_not_init(env, regs, BPF_REG_0);
/* Check return type */
t = btf_type_skip_modifiers(desc_btf, func_proto->type, NULL);
@@ -7277,6 +7278,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
return -EINVAL;
}
+ nargs = btf_type_vlen(func_proto);
+ args = btf_params(func_proto);
+
if (btf_type_is_scalar(t)) {
mark_reg_unknown(env, regs, BPF_REG_0);
mark_btf_func_reg_size(env, BPF_REG_0, t->size);
@@ -7284,24 +7288,57 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
ptr_type = btf_type_skip_modifiers(desc_btf, t->type,
&ptr_type_id);
if (!btf_type_is_struct(ptr_type)) {
- ptr_type_name = btf_name_by_offset(desc_btf,
- ptr_type->name_off);
- verbose(env, "kernel function %s returns pointer type %s %s is not supported\n",
- func_name, btf_type_str(ptr_type),
- ptr_type_name);
- return -EINVAL;
+ /* if we have an array, look for the arguments */
+ for (i = 0; i < nargs; i++) {
+ regno = i + BPF_REG_1;
+ reg = ®s[regno];
+
+ /* look for any const scalar parameter of name "rdonly_buf_size"
+ * or "rdwr_buf_size"
+ */
+ if (!check_reg_arg(env, regno, SRC_OP) &&
+ tnum_is_const(regs[regno].var_off)) {
+ if (btf_is_kfunc_arg_mem_size(desc_btf, &args[i], reg,
+ "rdonly_buf_size"))
+ reg_ro_size = regs[regno].var_off.value;
+ else if (btf_is_kfunc_arg_mem_size(desc_btf, &args[i], reg,
+ "rdwr_buf_size"))
+ reg_rw_size = regs[regno].var_off.value;
+ }
+ }
+
+ if (!reg_rw_size && !reg_ro_size) {
+ ptr_type_name = btf_name_by_offset(desc_btf,
+ ptr_type->name_off);
+ verbose(env,
+ "kernel function %s returns pointer type %s %s is not supported\n",
+ func_name,
+ btf_type_str(ptr_type),
+ ptr_type_name);
+ return -EINVAL;
+ }
+
+ mark_reg_known_zero(env, regs, BPF_REG_0);
+ regs[BPF_REG_0].type = PTR_TO_MEM;
+ regs[BPF_REG_0].mem_size = reg_ro_size + reg_rw_size;
+
+ if (reg_ro_size)
+ regs[BPF_REG_0].type |= MEM_RDONLY;
+ } else {
+ mark_reg_known_zero(env, regs, BPF_REG_0);
+ regs[BPF_REG_0].type = PTR_TO_BTF_ID;
+ regs[BPF_REG_0].btf = desc_btf;
+ regs[BPF_REG_0].btf_id = ptr_type_id;
+ mark_btf_func_reg_size(env, BPF_REG_0, sizeof(void *));
}
- mark_reg_known_zero(env, regs, BPF_REG_0);
- regs[BPF_REG_0].btf = desc_btf;
- regs[BPF_REG_0].type = PTR_TO_BTF_ID;
- regs[BPF_REG_0].btf_id = ptr_type_id;
+
if (btf_kfunc_id_set_contains(desc_btf, resolve_prog_type(env->prog),
BTF_KFUNC_TYPE_RET_NULL, func_id)) {
regs[BPF_REG_0].type |= PTR_MAYBE_NULL;
/* For mark_ptr_or_null_reg, see 93c230e3f5bd6 */
regs[BPF_REG_0].id = ++env->id_gen;
}
- mark_btf_func_reg_size(env, BPF_REG_0, sizeof(void *));
+
if (acq) {
int id = acquire_reference_state(env, insn_idx);
@@ -7312,8 +7349,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
}
} /* else { add_kfunc_call() ensures it is btf_type_is_void(t) } */
- nargs = btf_type_vlen(func_proto);
- args = (const struct btf_param *)(func_proto + 1);
+ for (i = 1 ; i < CALLER_SAVED_REGS; i++)
+ mark_reg_not_init(env, regs, caller_saved[i]);
+
for (i = 0; i < nargs; i++) {
u32 regno = i + 1;
--
2.36.1
next prev parent reply other threads:[~2022-05-18 20:59 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-18 20:59 [PATCH bpf-next v5 00/17] Introduce eBPF support for HID devices Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 01/17] bpf/btf: also allow kfunc in tracing and syscall programs Benjamin Tissoires
2022-05-21 2:34 ` Alexei Starovoitov
2022-05-18 20:59 ` Benjamin Tissoires [this message]
2022-05-18 21:59 ` [PATCH bpf-next v5 02/17] bpf/verifier: allow kfunc to return an allocated mem Kumar Kartikeya Dwivedi
2022-05-19 12:05 ` Benjamin Tissoires
2022-05-19 12:40 ` Kumar Kartikeya Dwivedi
2022-05-18 20:59 ` [PATCH bpf-next v5 03/17] bpf: prepare for more bpf syscall to be used from kernel and user space Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 04/17] libbpf: add map_get_fd_by_id and map_delete_elem in light skeleton Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 05/17] HID: core: store the unique system identifier in hid_device Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 06/17] HID: export hid_report_type to uapi Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 07/17] HID: initial BPF implementation Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 08/17] selftests/bpf: add tests for the HID-bpf initial implementation Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 09/17] HID: bpf: allocate data memory for device_event BPF programs Benjamin Tissoires
2022-05-18 23:13 ` kernel test robot
2022-05-18 20:59 ` [PATCH bpf-next v5 10/17] selftests/bpf/hid: add test to change the report size Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 11/17] HID: bpf: introduce hid_hw_request() Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 12/17] selftests/bpf: add tests for bpf_hid_hw_request Benjamin Tissoires
2022-05-18 22:20 ` Kumar Kartikeya Dwivedi
2022-05-19 12:12 ` Benjamin Tissoires
2022-05-19 12:51 ` Kumar Kartikeya Dwivedi
2022-05-19 13:13 ` Benjamin Tissoires
2022-05-19 13:44 ` Kumar Kartikeya Dwivedi
2022-05-19 15:47 ` Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 13/17] HID: bpf: allow to change the report descriptor Benjamin Tissoires
2022-05-21 2:46 ` Alexei Starovoitov
2022-05-18 20:59 ` [PATCH bpf-next v5 14/17] selftests/bpf: add report descriptor fixup tests Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 15/17] samples/bpf: add new hid_mouse example Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 16/17] selftests/bpf: Add a test for BPF_F_INSERT_HEAD Benjamin Tissoires
2022-05-18 20:59 ` [PATCH bpf-next v5 17/17] Documentation: add HID-BPF docs Benjamin Tissoires
2022-05-19 8:10 ` [PATCH bpf-next v5 00/17] Introduce eBPF support for HID devices Christoph Hellwig
2022-05-19 8:20 ` Greg KH
2022-05-19 8:38 ` Christoph Hellwig
2022-05-19 10:20 ` Benjamin Tissoires
2022-05-19 10:43 ` Toke Høiland-Jørgensen
2022-05-19 11:56 ` Benjamin Tissoires
2022-05-21 0:18 ` Alexei Starovoitov
2022-05-19 10:32 ` Greg KH
2022-05-19 11:46 ` Benjamin Tissoires
2022-05-21 2:40 ` patchwork-bot+netdevbpf
2022-05-27 7:26 ` Tero Kristo
2022-05-30 15:49 ` Benjamin Tissoires
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220518205924.399291-3-benjamin.tissoires@redhat.com \
--to=benjamin.tissoires@redhat.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=davemarchevsky@fb.com \
--cc=gregkh@linuxfoundation.org \
--cc=jikos@kernel.org \
--cc=joe@cilium.io \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kpsingh@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=shuah@kernel.org \
--cc=songliubraving@fb.com \
--cc=tero.kristo@linux.intel.com \
--cc=yhs@fb.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).