BPF List
 help / color / mirror / Atom feed
From: Daniel Rosenberg <drosen@google.com>
To: Miklos Szeredi <miklos@szeredi.hu>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	John Fastabend <john.fastabend@gmail.com>
Cc: Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>, Yonghong Song <yhs@fb.com>,
	KP Singh <kpsingh@kernel.org>,
	Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
	Jiri Olsa <jolsa@kernel.org>,
	Daniel Rosenberg <drosen@google.com>,
	Paul Lawrence <paullawrence@google.com>,
	Alessio Balsini <balsini@google.com>,
	David Anderson <dvander@google.com>,
	Sandeep Patil <sspatil@google.com>,
	linux-fsdevel@vger.kernel.org, bpf@vger.kernel.org,
	kernel-team@android.com
Subject: [PATCH 02/26] bpf: verifier: Allow single packet invalidation
Date: Mon, 26 Sep 2022 16:17:58 -0700	[thread overview]
Message-ID: <20220926231822.994383-3-drosen@google.com> (raw)
In-Reply-To: <20220926231822.994383-1-drosen@google.com>

Previously there could only be one packet. Helper functions that may
modify the packet could simply invalidate all packets. Now that we
support multiple packets, we should allow helpers to invalidate specific
packets.

This is leaving the default global invalidation in place in case that's
still useful. All existing packets use the default id of '0', and could
be transitioned to the specific packet code with no change in behavior.

This also adds ARG_PTR_TO_PACKET, to allow packets to be passed to
helper functions at all. This is required to inform the verifier which
packets should be invalidated. Currenly only one packet is allowed per
helper.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Paul Lawrence <paullawrence@google.com>
---
 include/linux/bpf.h      |  1 +
 include/linux/bpf_fuse.h | 11 ++++++
 kernel/bpf/core.c        |  5 +++
 kernel/bpf/verifier.c    | 83 +++++++++++++++++++++++++++++++++++++++-
 4 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/bpf_fuse.h

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 07086e375487..4e6bfcfd8fea 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -456,6 +456,7 @@ enum bpf_arg_type {
 	ARG_PTR_TO_TIMER,	/* pointer to bpf_timer */
 	ARG_PTR_TO_KPTR,	/* pointer to referenced kptr */
 	ARG_PTR_TO_DYNPTR,      /* pointer to bpf_dynptr. See bpf_type_flag for dynptr type */
+	ARG_PTR_TO_PACKET,	/* pointer to packet */
 	__BPF_ARG_TYPE_MAX,
 
 	/* Extended arg_types. */
diff --git a/include/linux/bpf_fuse.h b/include/linux/bpf_fuse.h
new file mode 100644
index 000000000000..18e2ec5bf453
--- /dev/null
+++ b/include/linux/bpf_fuse.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2022 Google LLC.
+ */
+
+#ifndef _BPF_FUSE_H
+#define _BPF_FUSE_H
+
+bool bpf_helper_changes_one_pkt_data(void *func);
+
+#endif /* _BPF_FUSE_H */
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 3d9eb3ae334c..2ac3597ec932 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2685,6 +2685,11 @@ bool __weak bpf_helper_changes_pkt_data(void *func)
 	return false;
 }
 
+bool __weak bpf_helper_changes_one_pkt_data(void *func)
+{
+	return false;
+}
+
 /* Return TRUE if the JIT backend wants verifier to enable sub-register usage
  * analysis code and wants explicit zero extension inserted by verifier.
  * Otherwise, return FALSE.
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d28cb22d5ee5..2884650904fe 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -23,6 +23,7 @@
 #include <linux/error-injection.h>
 #include <linux/bpf_lsm.h>
 #include <linux/btf_ids.h>
+#include <linux/bpf_fuse.h>
 
 #include "disasm.h"
 
@@ -263,6 +264,7 @@ struct bpf_call_arg_meta {
 	u32 subprogno;
 	struct bpf_map_value_off_desc *kptr_off_desc;
 	u8 uninit_dynptr_regno;
+	u32 data_id;
 };
 
 struct btf *btf_vmlinux;
@@ -1396,6 +1398,12 @@ static bool reg_is_pkt_pointer_any(const struct bpf_reg_state *reg)
 	       reg->type == PTR_TO_PACKET_END;
 }
 
+static bool reg_is_specific_pkt_pointer_any(const struct bpf_reg_state *reg, u32 id)
+{
+	return (reg_is_pkt_pointer(reg) ||
+	       reg->type == PTR_TO_PACKET_END) && reg->data_id == id;
+}
+
 /* Unmodified PTR_TO_PACKET[_META,_END] register from ctx access. */
 static bool reg_is_init_pkt_pointer(const struct bpf_reg_state *reg,
 				    enum bpf_reg_type which)
@@ -5664,6 +5672,7 @@ static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK }
 static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } };
 static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };
 static const struct bpf_reg_types kptr_types = { .types = { PTR_TO_MAP_VALUE } };
+static const struct bpf_reg_types packet_ptr_types = { .types = { PTR_TO_PACKET } };
 
 static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
 	[ARG_PTR_TO_MAP_KEY]		= &map_key_value_types,
@@ -5691,6 +5700,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
 	[ARG_PTR_TO_TIMER]		= &timer_types,
 	[ARG_PTR_TO_KPTR]		= &kptr_types,
 	[ARG_PTR_TO_DYNPTR]		= &stack_ptr_types,
+	[ARG_PTR_TO_PACKET]		= &packet_ptr_types,
 };
 
 static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
@@ -5800,7 +5810,8 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env,
 		/* Some of the argument types nevertheless require a
 		 * zero register offset.
 		 */
-		if (base_type(arg_type) != ARG_PTR_TO_ALLOC_MEM)
+		if (base_type(arg_type) != ARG_PTR_TO_ALLOC_MEM &&
+			base_type(arg_type) != ARG_PTR_TO_PACKET)
 			return 0;
 		break;
 	/* All the rest must be rejected, except PTR_TO_BTF_ID which allows
@@ -6135,6 +6146,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
 		if (process_kptr_func(env, regno, meta))
 			return -EACCES;
 		break;
+	case ARG_PTR_TO_PACKET:
+		meta->data_id = reg->data_id;
+		break;
 	}
 
 	return err;
@@ -6509,13 +6523,36 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
 	return true;
 }
 
+static bool check_packet_ok(const struct bpf_func_proto *fn)
+{
+	int count = 0;
+
+	if (fn->arg1_type == ARG_PTR_TO_PACKET)
+		count++;
+	if (fn->arg2_type == ARG_PTR_TO_PACKET)
+		count++;
+	if (fn->arg3_type == ARG_PTR_TO_PACKET)
+		count++;
+	if (fn->arg4_type == ARG_PTR_TO_PACKET)
+		count++;
+	if (fn->arg5_type == ARG_PTR_TO_PACKET)
+		count++;
+
+	/* We only support one arg being a packet at the moment,
+	 * which is sufficient for the helper functions we have right now.
+	 */
+	return count <= 1;
+}
+
+
 static int check_func_proto(const struct bpf_func_proto *fn, int func_id,
 			    struct bpf_call_arg_meta *meta)
 {
 	return check_raw_mode_ok(fn) &&
 	       check_arg_pair_ok(fn) &&
 	       check_btf_id_ok(fn) &&
-	       check_refcount_ok(fn, func_id) ? 0 : -EINVAL;
+	       check_refcount_ok(fn, func_id) &&
+	       check_packet_ok(fn) ? 0 : -EINVAL;
 }
 
 /* Packet data might have moved, any old PTR_TO_PACKET[_META,_END]
@@ -6539,6 +6576,25 @@ static void __clear_all_pkt_pointers(struct bpf_verifier_env *env,
 	}
 }
 
+static void __clear_specific_pkt_pointers(struct bpf_verifier_env *env,
+				     struct bpf_func_state *state,
+				     u32 data_id)
+{
+	struct bpf_reg_state *regs = state->regs, *reg;
+	int i;
+
+	for (i = 0; i < MAX_BPF_REG; i++)
+		if (reg_is_specific_pkt_pointer_any(&regs[i], data_id))
+			mark_reg_unknown(env, regs, i);
+
+	bpf_for_each_spilled_reg(i, state, reg) {
+		if (!reg)
+			continue;
+		if (reg_is_specific_pkt_pointer_any(reg, data_id))
+			__mark_reg_unknown(env, reg);
+	}
+}
+
 static void clear_all_pkt_pointers(struct bpf_verifier_env *env)
 {
 	struct bpf_verifier_state *vstate = env->cur_state;
@@ -6548,6 +6604,15 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env)
 		__clear_all_pkt_pointers(env, vstate->frame[i]);
 }
 
+static void clear_specific_pkt_pointers(struct bpf_verifier_env *env, u32 data_id)
+{
+	struct bpf_verifier_state *vstate = env->cur_state;
+	int i;
+
+	for (i = 0; i <= vstate->curframe; i++)
+		__clear_specific_pkt_pointers(env, vstate->frame[i], data_id);
+}
+
 enum {
 	AT_PKT_END = -1,
 	BEYOND_PKT_END = -2,
@@ -7187,6 +7252,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 	struct bpf_call_arg_meta meta;
 	int insn_idx = *insn_idx_p;
 	bool changes_data;
+	bool changes_specific_data;
 	int i, err, func_id;
 
 	/* find function prototype */
@@ -7224,6 +7290,17 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 		return -EINVAL;
 	}
 
+	changes_specific_data = bpf_helper_changes_one_pkt_data(fn->func);
+	if (changes_data && fn->arg1_type != ARG_PTR_TO_PACKET &&
+			    fn->arg2_type != ARG_PTR_TO_PACKET &&
+			    fn->arg3_type != ARG_PTR_TO_PACKET &&
+			    fn->arg4_type != ARG_PTR_TO_PACKET &&
+			    fn->arg5_type != ARG_PTR_TO_PACKET) {
+		verbose(env, "kernel subsystem misconfigured func %s#%d: no packet arg\n",
+			func_id_name(func_id), func_id);
+		return -EINVAL;
+	}
+
 	memset(&meta, 0, sizeof(meta));
 	meta.pkt_access = fn->pkt_access;
 
@@ -7534,6 +7611,8 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
 
 	if (changes_data)
 		clear_all_pkt_pointers(env);
+	if (changes_specific_data)
+		clear_specific_pkt_pointers(env, meta.data_id);
 	return 0;
 }
 
-- 
2.37.3.998.g577e59143f-goog


  parent reply	other threads:[~2022-09-26 23:19 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-26 23:17 [PATCH 00/26] FUSE BPF: A Stacked Filesystem Extension for FUSE Daniel Rosenberg
2022-09-26 23:17 ` [PATCH 01/26] bpf: verifier: Allow for multiple packets Daniel Rosenberg
2022-09-26 23:17 ` Daniel Rosenberg [this message]
2022-09-26 23:17 ` [PATCH 03/26] fuse-bpf: Update uapi for fuse-bpf Daniel Rosenberg
2022-09-27 18:19   ` Miklos Szeredi
2022-09-30 22:02     ` Paul Lawrence
2022-10-01  7:47       ` Amir Goldstein
2022-09-26 23:18 ` [PATCH 04/26] fuse-bpf: Add BPF supporting functions Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 05/26] fs: Generic function to convert iocb to rw flags Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 06/26] bpf: Export bpf_prog_fops Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 07/26] fuse-bpf: Prepare for fuse-bpf patch Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 08/26] fuse: Add fuse-bpf, a stacked fs extension for FUSE Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 09/26] fuse-bpf: Don't support export_operations Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 10/26] fuse-bpf: Partially add mapping support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 11/26] fuse-bpf: Add lseek support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 12/26] fuse-bpf: Add support for fallocate Daniel Rosenberg
2022-09-27 22:07   ` Dave Chinner
2022-09-27 23:36     ` Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 13/26] fuse-bpf: Support file/dir open/close Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 14/26] fuse-bpf: Support mknod/unlink/mkdir/rmdir Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 15/26] fuse-bpf: Add support for read/write iter Daniel Rosenberg
2022-10-01  6:53   ` Amir Goldstein
2022-09-26 23:18 ` [PATCH 16/26] fuse-bpf: support FUSE_READDIR Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 17/26] fuse-bpf: Add support for sync operations Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 18/26] fuse-bpf: Add Rename support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 19/26] fuse-bpf: Add attr support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 20/26] fuse-bpf: Add support for FUSE_COPY_FILE_RANGE Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 21/26] fuse-bpf: Add xattr support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 22/26] fuse-bpf: Add symlink/link support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 23/26] fuse-bpf: allow mounting with no userspace daemon Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 24/26] fuse-bpf: Call bpf for pre/post filters Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 25/26] fuse-bpf: Add userspace " Daniel Rosenberg
2022-09-28  6:41 ` [PATCH 00/26] FUSE BPF: A Stacked Filesystem Extension for FUSE Martin KaFai Lau
2022-09-28 12:31   ` Brian Foster
2022-10-01  0:47     ` Daniel Rosenberg
2022-10-01  0:05   ` Daniel Rosenberg
2022-10-01  0:24     ` Alexei Starovoitov
2022-10-06  1:58     ` Martin KaFai Lau

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=20220926231822.994383-3-drosen@google.com \
    --to=drosen@google.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=balsini@google.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=dvander@google.com \
    --cc=haoluo@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kernel-team@android.com \
    --cc=kpsingh@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=miklos@szeredi.hu \
    --cc=paullawrence@google.com \
    --cc=sdf@google.com \
    --cc=song@kernel.org \
    --cc=sspatil@google.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