All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
To: bpf@vger.kernel.org
Cc: Eduard Zingerman <eddyz87@gmail.com>,
	Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Emil Tsalapatis <emil@etsalapatis.com>, Tejun Heo <tj@kernel.org>,
	Amery Hung <ameryhung@gmail.com>,
	kkd@meta.com, kernel-team@meta.com
Subject: [PATCH bpf-next v4 3/8] bpf: Check read access for initialized writable memory arguments
Date: Fri, 18 Sep 2026 07:28:57 +0200	[thread overview]
Message-ID: <20260918052906.12226-4-memxor@gmail.com> (raw)
In-Reply-To: <20260918052906.12226-1-memxor@gmail.com>

From: Eduard Zingerman <eddyz87@gmail.com>

MEM_WRITE without MEM_UNINIT denotes memory that may be read as well as
written. Helper argument checking currently requests only BPF_WRITE, which
checks stack initialization but omits read permission checks on map values.
For example, bpf_check_mtu() reads its mtu_len argument before overwriting it,
but the verifier permits that argument to point into a BPF_F_WRONLY_PROG map.

Derive generic memory access from argument flags: read-only for inputs,
write-only for MEM_WRITE | MEM_UNINIT, and read/write for MEM_WRITE alone.
Encode MEM_WRITE when classifying kfunc memory arguments and resolving
scalar-only struct pointers, replacing the kfunc-specific access override.

This rejects write-only map values passed to helper arguments that require
initialized writable memory. Generic kfunc __uninit output bookkeeping is
completed in a following patch.

Fixes: 8ea607330a39 ("bpf: Fix overloading of MEM_UNINIT's meaning")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/verifier.c | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 1d5e4ee64fc0..21eb806b1351 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8886,6 +8886,15 @@ static int process_map_ptr_arg(struct bpf_verifier_env *env, struct bpf_reg_stat
 	return 0;
 }
 
+static enum bpf_access_type func_arg_access_type(enum bpf_arg_type arg_type)
+{
+	if (!(arg_type & MEM_WRITE))
+		return BPF_READ;
+	if (arg_type & MEM_UNINIT)
+		return BPF_WRITE;
+	return BPF_READ | BPF_WRITE;
+}
+
 static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 prev_slot,
 			  struct bpf_call_arg_meta *meta,
 			  int insn_idx)
@@ -9180,9 +9189,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 		if (!(arg_type & MEM_FIXED_SIZE))
 			break;
 
-		access_type = arg_type & MEM_WRITE ? BPF_WRITE : BPF_READ;
-		if (meta->btf)
-			access_type = BPF_READ | BPF_WRITE;
+		access_type = func_arg_access_type(arg_type);
 
 		err = check_mem_reg(env, reg, argno, arg_size, access_type, meta, &known_memory);
 		if (err < 0) {
@@ -9228,9 +9235,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 		if (meta->btf && bpf_register_is_null(buff_reg))
 			break;
 
-		access_type = fn->arg_type[arg - 1] & MEM_WRITE ? BPF_WRITE : BPF_READ;
-		if (meta->btf)
-			access_type = BPF_READ | BPF_WRITE;
+		access_type = func_arg_access_type(fn->arg_type[arg - 1]);
 
 		zero_size_allowed = meta->btf || base_type(arg_type) == ARG_MEM_SIZE_OR_ZERO;
 
@@ -12436,7 +12441,8 @@ static int resolve_func_arg_type(struct bpf_verifier_env *env,
 			PTR_ERR(resolve_ret));
 		return -EINVAL;
 	}
-	*arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | (*arg_type & PTR_MAYBE_NULL);
+	*arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | MEM_WRITE |
+		    (*arg_type & PTR_MAYBE_NULL);
 
 	return 0;
 }
@@ -12933,7 +12939,7 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
 				reg_arg_name(env, argno), btf_type_str(ref_t), ref_tname);
 			return -EINVAL;
 		}
-		arg_type = ARG_PTR_TO_MEM;
+		arg_type = ARG_PTR_TO_MEM | MEM_WRITE;
 	} else if (btf_type_is_struct(ref_t))
 		/* A pointer to a struct without a size argument is classified as ARG_PTR_TO_BTF_ID */
 		arg_type = ARG_PTR_TO_BTF_ID;
@@ -12958,7 +12964,7 @@ get_kfunc_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *meta,
 			return -EINVAL;
 		}
 		proto->arg_size[arg] = type_size;
-		arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+		arg_type = ARG_PTR_TO_MEM | MEM_FIXED_SIZE | MEM_WRITE;
 	}
 
 	if (is_kfunc_arg_uninit(meta->btf, &args[arg]))
-- 
2.53.0


  parent reply	other threads:[~2026-09-18  5:29 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18  5:28 [PATCH bpf-next v4 0/8] Fix generic __uninit kfunc output buffers Kumar Kartikeya Dwivedi
2026-09-18  5:28 ` [PATCH bpf-next v4 1/8] selftests/bpf: Allow privileged preparation for capability tests Kumar Kartikeya Dwivedi
2026-09-18  5:28 ` [PATCH bpf-next v4 2/8] bpf: Record raw memory arguments during argument checking Kumar Kartikeya Dwivedi
2026-09-18  6:35   ` bot+bpf-ci
2026-09-18 16:24     ` Eduard Zingerman
2026-09-18  5:28 ` Kumar Kartikeya Dwivedi [this message]
2026-09-18  5:50   ` [PATCH bpf-next v4 3/8] bpf: Check read access for initialized writable memory arguments sashiko-bot
2026-09-18 17:46     ` Eduard Zingerman
2026-09-18 18:01     ` Amery Hung
2026-09-18  5:28 ` [PATCH bpf-next v4 4/8] selftests/bpf: Cover helper memory access permissions Kumar Kartikeya Dwivedi
2026-09-18  6:17   ` bot+bpf-ci
2026-09-18  5:28 ` [PATCH bpf-next v4 5/8] bpf: Fix generic __uninit kfunc output buffers Kumar Kartikeya Dwivedi
2026-09-18  6:35   ` bot+bpf-ci
2026-09-18 17:50   ` Eduard Zingerman
2026-09-18  5:29 ` [PATCH bpf-next v4 6/8] selftests/bpf: Cover generic __uninit output initialization Kumar Kartikeya Dwivedi
2026-09-18  5:29 ` [PATCH bpf-next v4 7/8] bpf: Support multiple __uninit kfunc output arguments Kumar Kartikeya Dwivedi
2026-09-18  5:29 ` [PATCH bpf-next v4 8/8] selftests/bpf: Cover __uninit kfunc output argument slots Kumar Kartikeya Dwivedi
2026-09-18  6:35   ` bot+bpf-ci

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=20260918052906.12226-4-memxor@gmail.com \
    --to=memxor@gmail.com \
    --cc=ameryhung@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=emil@etsalapatis.com \
    --cc=kernel-team@meta.com \
    --cc=kkd@meta.com \
    --cc=tj@kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.