[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220722084556.1342406-1-benjamin.tissoires@redhat.com>
Date: Fri, 22 Jul 2022 10:45:56 +0200
From: Benjamin Tissoires <benjamin.tissoires@...hat.com>
To: Greg KH <gregkh@...uxfoundation.org>,
Jiri Kosina <jikos@...nel.org>,
Alexei Starovoitov <ast@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>,
Andrii Nakryiko <andrii@...nel.org>,
Martin KaFai Lau <kafai@...com>,
Song Liu <songliubraving@...com>, Yonghong Song <yhs@...com>,
Kumar Kartikeya Dwivedi <memxor@...il.com>,
John Fastabend <john.fastabend@...il.com>,
KP Singh <kpsingh@...nel.org>, Shuah Khan <shuah@...nel.org>,
Dave Marchevsky <davemarchevsky@...com>,
Joe Stringer <joe@...ium.io>, Jonathan Corbet <corbet@....net>
Cc: Tero Kristo <tero.kristo@...ux.intel.com>,
linux-kernel@...r.kernel.org, linux-input@...r.kernel.org,
netdev@...r.kernel.org, bpf@...r.kernel.org,
linux-kselftest@...r.kernel.org, linux-doc@...r.kernel.org,
Benjamin Tissoires <benjamin.tissoires@...hat.com>
Subject: [PATCH bpf-next v8 02/24] bpf/verifier: allow kfunc to read user provided context
When a kfunc was trying to access data from context in a syscall eBPF
program, the verifier was rejecting the call.
This is because the syscall context is not known at compile time, and
so we need to check this when actually accessing it.
Check for the valid memory access and allow such situation to happen.
Acked-by: Kumar Kartikeya Dwivedi <memxor@...il.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@...hat.com>
---
changes in v8:
- fixup comment
- return -EACCESS instead of -EINVAL for consistency
changes in v7:
- renamed access_t into atype
- allow zero-byte read
- check_mem_access() to the correct offset/size
new in v6
---
kernel/bpf/verifier.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 7c1e056624f9..c807c5d7085a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -248,6 +248,7 @@ struct bpf_call_arg_meta {
struct bpf_map *map_ptr;
bool raw_mode;
bool pkt_access;
+ bool is_kfunc;
u8 release_regno;
int regno;
int access_size;
@@ -5170,6 +5171,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
struct bpf_call_arg_meta *meta)
{
struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno];
+ enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
u32 *max_access;
switch (base_type(reg->type)) {
@@ -5223,6 +5225,24 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
env,
regno, reg->off, access_size,
zero_size_allowed, ACCESS_HELPER, meta);
+ case PTR_TO_CTX:
+ /* in case of a kfunc called in a program of type SYSCALL, the context is
+ * user supplied, so not computed statically.
+ * Dynamically check it now
+ */
+ if (prog_type == BPF_PROG_TYPE_SYSCALL && meta && meta->is_kfunc) {
+ enum bpf_access_type atype = meta->raw_mode ? BPF_WRITE : BPF_READ;
+ int offset = access_size - 1;
+
+ /* Allow zero-byte read from PTR_TO_CTX */
+ if (access_size == 0)
+ return zero_size_allowed ? 0 : -EACCES;
+
+ return check_mem_access(env, env->insn_idx, regno, offset, BPF_B,
+ atype, -1, false);
+ }
+
+ fallthrough;
default: /* scalar_value or invalid ptr */
/* Allow zero-byte read from NULL, regardless of pointer type */
if (zero_size_allowed && access_size == 0 &&
@@ -5335,6 +5355,7 @@ int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state
WARN_ON_ONCE(regno < BPF_REG_2 || regno > BPF_REG_5);
memset(&meta, 0, sizeof(meta));
+ meta.is_kfunc = true;
if (may_be_null) {
saved_reg = *mem_reg;
--
2.36.1
Powered by blists - more mailing lists