[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)