mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04: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);
|
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;
|
return FWNET_ALEN;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1530,9 +1530,11 @@ static int bond_header_create(struct sk_buff *skb, struct net_device *bond_dev,
|
|||||||
return ret;
|
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;
|
const struct header_ops *slave_ops;
|
||||||
struct slave *slave;
|
struct slave *slave;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -1542,7 +1544,7 @@ static int bond_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
|||||||
if (slave) {
|
if (slave) {
|
||||||
slave_ops = READ_ONCE(slave->dev->header_ops);
|
slave_ops = READ_ONCE(slave->dev->header_ops);
|
||||||
if (slave_ops && slave_ops->parse)
|
if (slave_ops && slave_ops->parse)
|
||||||
ret = slave_ops->parse(skb, haddr);
|
ret = slave_ops->parse(skb, slave->dev, haddr);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return ret;
|
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,
|
int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
|
||||||
const void *daddr, const void *saddr, unsigned len);
|
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,
|
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
|
||||||
__be16 type);
|
__be16 type);
|
||||||
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
|
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);
|
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);
|
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,
|
int (*create) (struct sk_buff *skb, struct net_device *dev,
|
||||||
unsigned short type, const void *daddr,
|
unsigned short type, const void *daddr,
|
||||||
const void *saddr, unsigned int len);
|
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);
|
int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type);
|
||||||
void (*cache_update)(struct hh_cache *hh,
|
void (*cache_update)(struct hh_cache *hh,
|
||||||
const struct net_device *dev,
|
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)
|
if (!dev->header_ops || !dev->header_ops->parse)
|
||||||
return 0;
|
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)
|
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);
|
EXPORT_SYMBOL(eth_type_trans);
|
||||||
|
|
||||||
/**
|
int eth_header_parse(const struct sk_buff *skb, const struct net_device *dev,
|
||||||
* eth_header_parse - extract hardware address from packet
|
unsigned char *haddr)
|
||||||
* @skb: packet to extract header from
|
|
||||||
* @haddr: destination buffer
|
|
||||||
*/
|
|
||||||
int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr)
|
|
||||||
{
|
{
|
||||||
const struct ethhdr *eth = eth_hdr(skb);
|
const struct ethhdr *eth = eth_hdr(skb);
|
||||||
|
|
||||||
memcpy(haddr, eth->h_source, ETH_ALEN);
|
memcpy(haddr, eth->h_source, ETH_ALEN);
|
||||||
return 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));
|
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);
|
const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb);
|
||||||
memcpy(haddr, &iph->saddr, 4);
|
memcpy(haddr, &iph->saddr, 4);
|
||||||
|
|||||||
@@ -469,7 +469,9 @@ static int mac802154_header_create(struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct ieee802154_hdr hdr;
|
||||||
|
|
||||||
|
|||||||
@@ -129,9 +129,12 @@ static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
|
|||||||
return 1;
|
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);
|
const u8 *media = skb_mac_header(skb);
|
||||||
|
|
||||||
*haddr = *media;
|
*haddr = *media;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user