mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
bonding: prevent potential infinite loop in bond_header_parse()
bond_header_parse() can loop if a stack of two bonding devices is setup,
because skb->dev always points to the hierarchy top.
Add new "const struct net_device *dev" parameter to
(struct header_ops)->parse() method to make sure the recursion
is bounded, and that the final leaf parse method is called.
Fixes: 950803f725 ("bonding: fix type confusion in bond_setup_by_slave()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@shopee.com>
Tested-by: Jiayuan Chen <jiayuan.chen@shopee.com>
Cc: Jay Vosburgh <jv@jvosburgh.net>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>
Link: https://patch.msgid.link/20260315104152.1436867-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
43d222fbcd
commit
b7405dcf73
@@ -257,9 +257,10 @@ static void fwnet_header_cache_update(struct hh_cache *hh,
|
||||
memcpy((u8 *)hh->hh_data + HH_DATA_OFF(FWNET_HLEN), haddr, net->addr_len);
|
||||
}
|
||||
|
||||
static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int fwnet_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
|
||||
memcpy(haddr, dev->dev_addr, FWNET_ALEN);
|
||||
|
||||
return FWNET_ALEN;
|
||||
}
|
||||
|
||||
@@ -1530,9 +1530,11 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int bond_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
struct bonding *bond = netdev_priv(skb->dev);
|
||||
struct bonding *bond = netdev_priv(dev);
|
||||
const struct header_ops *slave_ops;
|
||||
struct slave *slave;
|
||||
int ret = 0;
|
||||
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
if (slave) {
|
||||
slave_ops = READ_ONCE(slave->dev->header_ops);
|
||||
if (slave_ops && slave_ops->parse)
|
||||
ret = slave_ops->parse(skb, haddr);
|
||||
ret = slave_ops->parse(skb, slave->dev, haddr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
|
||||
@@ -42,7 +42,8 @@ extern const struct header_ops eth_header_ops;
|
||||
|
||||
int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
|
||||
const void *daddr, const void *saddr, unsigned len);
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
|
||||
__be16 type);
|
||||
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
|
||||
|
||||
@@ -40,7 +40,8 @@ static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb)
|
||||
return (struct ethhdr *)skb_inner_mac_header(skb);
|
||||
}
|
||||
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
|
||||
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
|
||||
|
||||
|
||||
@@ -311,7 +311,9 @@ struct header_ops {
|
||||
int (*create) (struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type, const void *daddr,
|
||||
const void *saddr, unsigned int len);
|
||||
int (*parse)(const struct sk_buff *skb, unsigned char *haddr);
|
||||
int (*parse)(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr);
|
||||
int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type);
|
||||
void (*cache_update)(struct hh_cache *hh,
|
||||
const struct net_device *dev,
|
||||
@@ -3445,7 +3447,7 @@ static inline int dev_parse_header(const struct sk_buff *skb,
|
||||
|
||||
if (!dev->header_ops || !dev->header_ops->parse)
|
||||
return 0;
|
||||
return dev->header_ops->parse(skb, haddr);
|
||||
return dev->header_ops->parse(skb, dev, haddr);
|
||||
}
|
||||
|
||||
static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)
|
||||
|
||||
@@ -193,14 +193,11 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(eth_type_trans);
|
||||
|
||||
/**
|
||||
* eth_header_parse - extract hardware address from packet
|
||||
* @skb: packet to extract header from
|
||||
* @haddr: destination buffer
|
||||
*/
|
||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const struct ethhdr *eth = eth_hdr(skb);
|
||||
|
||||
memcpy(haddr, eth->h_source, ETH_ALEN);
|
||||
return ETH_ALEN;
|
||||
}
|
||||
|
||||
@@ -919,7 +919,8 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
|
||||
return -(t->hlen + sizeof(*iph));
|
||||
}
|
||||
|
||||
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int ipgre_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
|
||||
memcpy(haddr, &iph->saddr, 4);
|
||||
|
||||
@@ -469,7 +469,9 @@ static int mac802154_header_create(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
static int
|
||||
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
mac802154_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
struct ieee802154_hdr hdr;
|
||||
|
||||
|
||||
@@ -129,9 +129,12 @@ static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
||||
static int pn_header_parse(const struct sk_buff *skb,
|
||||
const struct net_device *dev,
|
||||
unsigned char *haddr)
|
||||
{
|
||||
const u8 *media = skb_mac_header(skb);
|
||||
|
||||
*haddr = *media;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user