[PATCH net 2/2] team: reject frames with insufficient headroom in team_header_create

Qihang <[email protected]>
Newsgroups org.kernel.vger.netdev,org.kernel.vger.stable
Message-ID <[email protected]>
From: Qihang Tang <[email protected]>

AF_PACKET SOCK_DGRAM sends reserve skb headroom from a snapshot of
team_dev->hard_header_len.  A concurrent team type change can switch the
selected port to one with a larger hard_header_len between that snapshot
and team_header_create(), so the port's create() pushes or writes past
skb->head.

This is the same race as in bond_header_create(); the snapshot series
that fixed the SOCK_RAW send paths deferred it.  dev->header_ops is the
stable team_header_ops, so snapshotting header_ops in the caller does
not help.

Reject the frame if skb headroom is smaller than the selected port's
hard_header_len, before delegating under the existing rcu_read_lock.

Fixes: 425000dbf173 ("team: fix header_ops type confusion with non-Ethernet ports")
Cc: [email protected]
Cc: Willem de Bruijn <[email protected]>
Cc: Jiri Pirko <[email protected]>
Signed-off-by: Qihang Tang <[email protected]>
---
 drivers/net/team/team_core.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c
index feaa75fbf8fc..2742a4bfc9d0 100644
--- a/drivers/net/team/team_core.c
+++ b/drivers/net/team/team_core.c
@@ -2269,10 +2269,24 @@ static int team_header_create(struct sk_buff *skb, struct net_device *team_dev,
 	port = team_header_port_get_rcu(team, true);
 	if (port) {
 		port_ops = READ_ONCE(port->dev->header_ops);
-		if (port_ops && port_ops->create)
+		if (port_ops && port_ops->create) {
+			unsigned int hlen = READ_ONCE(port->dev->hard_header_len);
+
+			/* Headroom was reserved from a snapshot of
+			 * team_dev->hard_header_len that may predate this
+			 * port (concurrent team type change); reject if
+			 * insufficient for the port's create(), which
+			 * pushes its own hlen.
+			 */
+			if (skb_headroom(skb) < hlen) {
+				ret = -EINVAL;
+				goto unlock;
+			}
 			ret = port_ops->create(skb, port->dev,
 					       type, daddr, saddr, len);
+		}
 	}
+unlock:
 	rcu_read_unlock();
 	return ret;
 }
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.