All of lore.kernel.org
 help / color / mirror / Atom feed
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 1/2] bpf: reject incompatible socket assignments
Date: Thu,  1 Oct 2026 00:40:19 +0800	[thread overview]
Message-ID: <20260930164020.41006-1-shlomojune6@gmail.com> (raw)

bpf_sk_assign() permits TC ingress programs to associate an IPv6 packet
with an AF_INET socket. The receive path can then interpret IPv6 skb
control data as IPv4 metadata. When IP_RETOPTS is enabled, this can cause
__ip_options_echo() to copy beyond its stack buffer.

Reject incompatible packet and socket families before attaching the socket,
while preserving IPv4 assignments to dual-stack AF_INET6 sockets. Validate
request, mapped, and time-wait sockets using their effective family.

Use the packet's effective protocol for VLAN checks and share the same
predicate across bpf_sk_assign() and bpf_sk_assign_tcp_reqsk().

Fixes: cf7fbe660f2d ("bpf: Add socket assign support")
Assisted-by: LLM
Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
---
Changes since v2:
- Use the effective packet protocol for VLAN-aware family validation.
- Handle IPv4-mapped AF_INET6 sockets, TCP children, and TIME_WAIT sockets.
- Share the protocol-based check with bpf_sk_assign_tcp_reqsk().

v2:
https://lore.kernel.org/netdev/20260911172313.64009-1-shlomojune6@gmail.com/

Changes since v1:
- Move family validation out of the IPv6 receive fast path and into
  bpf_sk_assign() and bpf_sk_assign_tcp_reqsk().
- Preserve IPv4 assignments to dual-stack AF_INET6 sockets.
- Check request sockets using rsk_ops->family.
- Split the fix into two patches and target the BPF fixes tree.

v1:
https://lore.kernel.org/netdev/20260823101809.26802-1-shlomojune6@gmail.com/
---
 include/uapi/linux/bpf.h       |  4 +++
 net/core/filter.c              | 63 ++++++++++++++++++++++++++++++++++
 tools/include/uapi/linux/bpf.h |  4 +++
 3 files changed, 71 insertions(+)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 732b35cc08d1c..5d8f5e2c8db38 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -4568,6 +4568,10 @@ union bpf_attr {
  *		**-EOPNOTSUPP** if the operation is not supported, for example
  *		a call from outside of TC ingress.
  *
+ *		**-EAFNOSUPPORT** if the socket family is not compatible with
+ *		the network layer of the packet, for example an **AF_INET**
+ *		socket and an IPv6 packet.
+ *
  * long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags)
  *	Description
  *		Helper is overloaded depending on BPF program type. This
diff --git a/net/core/filter.c b/net/core/filter.c
index 61940e7535523..5f64065523584 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3491,6 +3491,64 @@ static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto)
 	return -ENOTSUPP;
 }
 
+static bool bpf_sk_assign_family_ok_proto(const struct sock *sk, __be16 proto)
+{
+	const struct inet_connection_sock_af_ops *af_ops;
+	unsigned short family;
+
+	switch (proto) {
+	case htons(ETH_P_IP):
+		family = AF_INET;
+		break;
+	case htons(ETH_P_IPV6):
+		family = AF_INET6;
+		break;
+	default:
+		return true;
+	}
+
+	/* Requests inherit the listener family, but have family-specific ops. */
+	if (sk->sk_state == TCP_NEW_SYN_RECV)
+		return inet_reqsk(sk)->rsk_ops->family == family;
+
+	/* A dual-stack listener accepts both packet families. */
+	if (sk->sk_state == TCP_LISTEN && sk->sk_family == AF_INET6)
+		return family == AF_INET6 || !ipv6_only_sock(sk);
+
+#if IS_ENABLED(CONFIG_IPV6)
+	/* IPv4-mapped and pure IPv6 time-wait sockets retain AF_INET6. */
+	if (sk->sk_state == TCP_TIME_WAIT && sk->sk_family == AF_INET6) {
+		const struct inet_timewait_sock *tw = inet_twsk(sk);
+		bool mapped;
+
+		mapped = ipv6_addr_v4mapped(&tw->tw_v6_daddr) &&
+			 ipv6_addr_v4mapped(&tw->tw_v6_rcv_saddr);
+		return family == (mapped ? AF_INET : AF_INET6);
+	}
+#endif
+
+	/* IPv4-mapped and pure IPv6 TCP children keep AF_INET6 in sk_family. */
+	if (sk_fullsock(sk) && sk->sk_family == AF_INET6 && sk_is_tcp(sk)) {
+		af_ops = READ_ONCE(inet_csk(sk)->icsk_af_ops);
+		if ((family == AF_INET6 &&
+		     af_ops->net_header_len == sizeof(struct iphdr)) ||
+		    (family == AF_INET &&
+		     af_ops->net_header_len == sizeof(struct ipv6hdr)))
+			return false;
+	}
+
+	return sk->sk_family == family ||
+	       (family == AF_INET &&
+		sk->sk_family == AF_INET6 &&
+		!ipv6_only_sock(sk));
+}
+
+static bool bpf_sk_assign_family_ok(const struct sk_buff *skb,
+				    const struct sock *sk)
+{
+	return bpf_sk_assign_family_ok_proto(sk, skb_protocol(skb, true));
+}
+
 BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto,
 	   u64, flags)
 {
@@ -7989,6 +8047,8 @@ BPF_CALL_3(bpf_sk_assign, struct sk_buff *, skb, struct sock *, sk, u64, flags)
 		return -ENETUNREACH;
 	if (sk_unhashed(sk))
 		return -EOPNOTSUPP;
+	if (!bpf_sk_assign_family_ok(skb, sk))
+		return -EAFNOSUPPORT;
 	if (sk_is_refcounted(sk) &&
 	    unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
 		return -ENOENT;
@@ -12526,6 +12586,9 @@ __bpf_kfunc int bpf_sk_assign_tcp_reqsk(struct __sk_buff *s, struct sock *sk,
 	if (net != sock_net(sk))
 		return -ENETUNREACH;
 
+	if (!bpf_sk_assign_family_ok(skb, sk))
+		return -EAFNOSUPPORT;
+
 	switch (skb->protocol) {
 	case htons(ETH_P_IP):
 		ops = &tcp_request_sock_ops;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 732b35cc08d1c..5d8f5e2c8db38 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -4568,6 +4568,10 @@ union bpf_attr {
  *		**-EOPNOTSUPP** if the operation is not supported, for example
  *		a call from outside of TC ingress.
  *
+ *		**-EAFNOSUPPORT** if the socket family is not compatible with
+ *		the network layer of the packet, for example an **AF_INET**
+ *		socket and an IPv6 packet.
+ *
  * long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags)
  *	Description
  *		Helper is overloaded depending on BPF program type. This
-- 
2.43.0

             reply	other threads:[~2026-09-30 16:40 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30 16:40 Shihuang Liu [this message]
2026-09-30 16:40 ` [PATCH bpf v3 2/2] bpf: reject incompatible protocol changes Shihuang Liu
2026-09-30 17:26   ` bot+bpf-ci
2026-09-30 16:54 ` [PATCH bpf v3 1/2] bpf: reject incompatible socket assignments sashiko-bot

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-1-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 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.