Skip to content

Commit 425000d

Browse files
mrprePaolo Abeni
authored andcommitted
team: fix header_ops type confusion with non-Ethernet ports
Similar to commit 950803f ("bonding: fix type confusion in bond_setup_by_slave()") team has the same class of header_ops type confusion. For non-Ethernet ports, team_setup_by_port() copies port_dev->header_ops directly. When the team device later calls dev_hard_header() or dev_parse_header(), these callbacks can run with the team net_device instead of the real lower device, so netdev_priv(dev) is interpreted as the wrong private type and can crash. The syzbot report shows a crash in bond_header_create(), but the root cause is in team: the topology is gre -> bond -> team, and team calls the inherited header_ops with its own net_device instead of the lower device, so bond_header_create() receives a team device and interprets netdev_priv() as bonding private data, causing a type confusion crash. Fix this by introducing team header_ops wrappers for create/parse, selecting a team port under RCU, and calling the lower device callbacks with port->dev, so each callback always sees the correct net_device context. Also pass the selected lower device to the lower parse callback, so recursion is bounded in stacked non-Ethernet topologies and parse callbacks always run with the correct device context. Fixes: 1d76efe ("team: add support for non-ethernet devices") Reported-by: [email protected] Closes: https://lore.kernel.org/all/[email protected]/T/ Cc: Jiayuan Chen <[email protected]> Signed-off-by: Jiayuan Chen <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 673bb63 commit 425000d

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

drivers/net/team/team_core.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,68 @@ static const struct ethtool_ops team_ethtool_ops = {
20582058
* rt netlink interface
20592059
***********************/
20602060

2061+
/* For tx path we need a linkup && enabled port and for parse any port
2062+
* suffices.
2063+
*/
2064+
static struct team_port *team_header_port_get_rcu(struct team *team,
2065+
bool txable)
2066+
{
2067+
struct team_port *port;
2068+
2069+
list_for_each_entry_rcu(port, &team->port_list, list) {
2070+
if (!txable || team_port_txable(port))
2071+
return port;
2072+
}
2073+
2074+
return NULL;
2075+
}
2076+
2077+
static int team_header_create(struct sk_buff *skb, struct net_device *team_dev,
2078+
unsigned short type, const void *daddr,
2079+
const void *saddr, unsigned int len)
2080+
{
2081+
struct team *team = netdev_priv(team_dev);
2082+
const struct header_ops *port_ops;
2083+
struct team_port *port;
2084+
int ret = 0;
2085+
2086+
rcu_read_lock();
2087+
port = team_header_port_get_rcu(team, true);
2088+
if (port) {
2089+
port_ops = READ_ONCE(port->dev->header_ops);
2090+
if (port_ops && port_ops->create)
2091+
ret = port_ops->create(skb, port->dev,
2092+
type, daddr, saddr, len);
2093+
}
2094+
rcu_read_unlock();
2095+
return ret;
2096+
}
2097+
2098+
static int team_header_parse(const struct sk_buff *skb,
2099+
const struct net_device *team_dev,
2100+
unsigned char *haddr)
2101+
{
2102+
struct team *team = netdev_priv(team_dev);
2103+
const struct header_ops *port_ops;
2104+
struct team_port *port;
2105+
int ret = 0;
2106+
2107+
rcu_read_lock();
2108+
port = team_header_port_get_rcu(team, false);
2109+
if (port) {
2110+
port_ops = READ_ONCE(port->dev->header_ops);
2111+
if (port_ops && port_ops->parse)
2112+
ret = port_ops->parse(skb, port->dev, haddr);
2113+
}
2114+
rcu_read_unlock();
2115+
return ret;
2116+
}
2117+
2118+
static const struct header_ops team_header_ops = {
2119+
.create = team_header_create,
2120+
.parse = team_header_parse,
2121+
};
2122+
20612123
static void team_setup_by_port(struct net_device *dev,
20622124
struct net_device *port_dev)
20632125
{
@@ -2066,7 +2128,8 @@ static void team_setup_by_port(struct net_device *dev,
20662128
if (port_dev->type == ARPHRD_ETHER)
20672129
dev->header_ops = team->header_ops_cache;
20682130
else
2069-
dev->header_ops = port_dev->header_ops;
2131+
dev->header_ops = port_dev->header_ops ?
2132+
&team_header_ops : NULL;
20702133
dev->type = port_dev->type;
20712134
dev->hard_header_len = port_dev->hard_header_len;
20722135
dev->needed_headroom = port_dev->needed_headroom;

0 commit comments

Comments
 (0)