Commit 6ddf0813 authored by Cong Wang's avatar Cong Wang Committed by Greg Kroah-Hartman

bonding: validate ip header before check IPPROTO_IGMP

[ Upstream commit 9d1bc24b ]

bond_xmit_roundrobin() checks for IGMP packets but it parses
the IP header even before checking skb->protocol.

We should validate the IP header with pskb_may_pull() before
using iph->protocol.

Reported-and-tested-by: syzbot+e5be16aa39ad6e755391@syzkaller.appspotmail.com
Fixes: a2fd940f ("bonding: fix broken multicast with round-robin mode")
Cc: Jay Vosburgh <j.vosburgh@gmail.com>
Cc: Veaceslav Falico <vfalico@gmail.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent f9cae712
...@@ -3866,8 +3866,8 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb, ...@@ -3866,8 +3866,8 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
struct net_device *bond_dev) struct net_device *bond_dev)
{ {
struct bonding *bond = netdev_priv(bond_dev); struct bonding *bond = netdev_priv(bond_dev);
struct iphdr *iph = ip_hdr(skb);
struct slave *slave; struct slave *slave;
int slave_cnt;
u32 slave_id; u32 slave_id;
/* Start with the curr_active_slave that joined the bond as the /* Start with the curr_active_slave that joined the bond as the
...@@ -3876,23 +3876,32 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb, ...@@ -3876,23 +3876,32 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
* send the join/membership reports. The curr_active_slave found * send the join/membership reports. The curr_active_slave found
* will send all of this type of traffic. * will send all of this type of traffic.
*/ */
if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) { if (skb->protocol == htons(ETH_P_IP)) {
int noff = skb_network_offset(skb);
struct iphdr *iph;
if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
goto non_igmp;
iph = ip_hdr(skb);
if (iph->protocol == IPPROTO_IGMP) {
slave = rcu_dereference(bond->curr_active_slave); slave = rcu_dereference(bond->curr_active_slave);
if (slave) if (slave)
bond_dev_queue_xmit(bond, skb, slave->dev); bond_dev_queue_xmit(bond, skb, slave->dev);
else else
bond_xmit_slave_id(bond, skb, 0); bond_xmit_slave_id(bond, skb, 0);
} else { return NETDEV_TX_OK;
int slave_cnt = READ_ONCE(bond->slave_cnt); }
}
non_igmp:
slave_cnt = READ_ONCE(bond->slave_cnt);
if (likely(slave_cnt)) { if (likely(slave_cnt)) {
slave_id = bond_rr_gen_slave_id(bond); slave_id = bond_rr_gen_slave_id(bond);
bond_xmit_slave_id(bond, skb, slave_id % slave_cnt); bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
} else { } else {
bond_tx_drop(bond_dev, skb); bond_tx_drop(bond_dev, skb);
} }
}
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment