From: Shihuang Liu <shlomojune6@gmail.com>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org,
eddyz87@gmail.com, memxor@gmail.com, martin.lau@linux.dev,
song@kernel.org, yonghong.song@linux.dev, jolsa@kernel.org,
emil@etsalapatis.com, ihor.solodrai@linux.dev,
john.fastabend@gmail.com, sdf@fomichev.me, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, Shihuang Liu <shlomojune6@gmail.com>
Subject: [PATCH bpf v3 2/2] bpf: reject incompatible protocol changes
Date: Thu, 1 Oct 2026 00:40:20 +0800 [thread overview]
Message-ID: <20260930164020.41006-2-shlomojune6@gmail.com> (raw)
In-Reply-To: <20260930164020.41006-1-shlomojune6@gmail.com>
An skb assigned to a socket by bpf_sk_assign() can later have its L3
protocol changed by bpf_skb_change_proto() or bpf_skb_adjust_room().
Without revalidation, this bypasses the assignment-time family check.
Reject incompatible protocol changes before modifying the skb, including L3
encapsulation and decapsulation. Reuse the assignment family predicate and
preserve the socket assignment when the change is rejected.
Fixes: cf7fbe660f2d ("bpf: Add socket assign support")
Assisted-by: LLM
Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
---
Changes since v2:
- Check compatibility before changing the skb, preserving the socket
assignment instead of calling skb_orphan().
- Cover L3 encapsulation and decapsulation in bpf_skb_adjust_room(), as well
as bpf_skb_change_proto().
Changes since v1:
- Revalidate prefetched sockets after bpf_skb_change_proto() changes the
packet protocol, closing a bypass of assignment-time validation.
- Preserve compatible dual-stack assignments and release incompatible
assignments through their existing skb destructor.
- Split the fix into two patches and target the BPF fixes tree.
v2:
https://lore.kernel.org/netdev/20260911172313.64009-2-shlomojune6@gmail.com/
v1:
https://lore.kernel.org/netdev/20260823101809.26802-1-shlomojune6@gmail.com/
---
include/uapi/linux/bpf.h | 10 ++++++++++
net/core/filter.c | 23 +++++++++++++++++++++++
tools/include/uapi/linux/bpf.h | 10 ++++++++++
3 files changed, 43 insertions(+)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 5d8f5e2c8db38..d1897ee13a66c 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2659,6 +2659,11 @@ union bpf_attr {
* checked and segments are recalculated by the GSO/GRO engine.
* The size for GSO target is adapted as well.
*
+ * If the skb was assigned to a socket by **bpf_sk_assign** and
+ * the requested protocol is incompatible with that socket, the
+ * helper returns **-EAFNOSUPPORT** before translating the packet.
+ * The skb assignment is preserved.
+ *
* All values for *flags* are reserved for future usage, and must
* be left at zero.
*
@@ -3067,6 +3072,11 @@ union bpf_attr {
* removed from the packet. This handles cases where all tunnel
* layers have been decapsulated.
*
+ * If an L3 encapsulation or decapsulation would produce a
+ * protocol incompatible with a socket assigned by
+ * **bpf_sk_assign**, the helper returns **-EAFNOSUPPORT** before
+ * changing the packet. The skb assignment is preserved.
+ *
* A call to this helper is susceptible to change the underlying
* packet buffer. Therefore, at load time, all checks on pointers
* previously done by the verifier are invalidated and must be
diff --git a/net/core/filter.c b/net/core/filter.c
index 5f64065523584..09816da113554 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3549,6 +3549,12 @@ static bool bpf_sk_assign_family_ok(const struct sk_buff *skb,
return bpf_sk_assign_family_ok_proto(sk, skb_protocol(skb, true));
}
+static bool bpf_skb_proto_change_sk_ok(struct sk_buff *skb, __be16 proto)
+{
+ return !skb_sk_is_prefetched(skb) ||
+ bpf_sk_assign_family_ok_proto(skb->sk, proto);
+}
+
BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
u64, flags)
{
@@ -3556,6 +3562,12 @@ BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
if (unlikely(flags))
return -EINVAL;
+ if (((skb->protocol == htons(ETH_P_IP) &&
+ proto == htons(ETH_P_IPV6)) ||
+ (skb->protocol == htons(ETH_P_IPV6) &&
+ proto == htons(ETH_P_IP))) &&
+ !bpf_skb_proto_change_sk_ok(skb, proto))
+ return -EAFNOSUPPORT;
/* General idea is that this helper does the basic groundwork
* needed for changing the protocol, and eBPF program fills the
@@ -3699,6 +3711,11 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
if (inner_mac_len > len_diff)
return -EINVAL;
inner_trans = skb->transport_header;
+
+ if (!bpf_skb_proto_change_sk_ok(skb,
+ flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 ?
+ htons(ETH_P_IPV6) : htons(ETH_P_IP)))
+ return -EAFNOSUPPORT;
}
ret = bpf_skb_net_hdr_push(skb, off, len_diff);
@@ -3786,6 +3803,12 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff,
return -ENOTSUPP;
}
+ if (decap &&
+ !bpf_skb_proto_change_sk_ok(skb,
+ flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6 ?
+ htons(ETH_P_IPV6) : htons(ETH_P_IP)))
+ return -EAFNOSUPPORT;
+
ret = skb_unclone(skb, GFP_ATOMIC);
if (unlikely(ret < 0))
return ret;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 5d8f5e2c8db38..d1897ee13a66c 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -2659,6 +2659,11 @@ union bpf_attr {
* checked and segments are recalculated by the GSO/GRO engine.
* The size for GSO target is adapted as well.
*
+ * If the skb was assigned to a socket by **bpf_sk_assign** and
+ * the requested protocol is incompatible with that socket, the
+ * helper returns **-EAFNOSUPPORT** before translating the packet.
+ * The skb assignment is preserved.
+ *
* All values for *flags* are reserved for future usage, and must
* be left at zero.
*
@@ -3067,6 +3072,11 @@ union bpf_attr {
* removed from the packet. This handles cases where all tunnel
* layers have been decapsulated.
*
+ * If an L3 encapsulation or decapsulation would produce a
+ * protocol incompatible with a socket assigned by
+ * **bpf_sk_assign**, the helper returns **-EAFNOSUPPORT** before
+ * changing the packet. The skb assignment is preserved.
+ *
* A call to this helper is susceptible to change the underlying
* packet buffer. Therefore, at load time, all checks on pointers
* previously done by the verifier are invalidated and must be
--
2.43.0
next prev parent reply other threads:[~2026-09-30 16:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 16:40 [PATCH bpf v3 1/2] bpf: reject incompatible socket assignments Shihuang Liu
2026-09-30 16:40 ` Shihuang Liu [this message]
2026-09-30 17:26 ` [PATCH bpf v3 2/2] bpf: reject incompatible protocol changes 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=20260930164020.41006-2-shlomojune6@gmail.com \
--to=shlomojune6@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eddyz87@gmail.com \
--cc=edumazet@google.com \
--cc=emil@etsalapatis.com \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/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
all inboxes | Powered by JetHome®