[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1572026582.768948953@decadent.org.uk>
Date: Fri, 25 Oct 2019 19:03:36 +0100
From: Ben Hutchings <ben@...adent.org.uk>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC: akpm@...ux-foundation.org, Denis Kirjanov <kda@...ux-powerpc.org>,
"Jay Vosburgh" <j.vosburgh@...il.com>,
"Andy Gospodarek" <andy@...yhouse.net>,
"David S. Miller" <davem@...emloft.net>,
"Cong Wang" <xiyou.wangcong@...il.com>,
"Veaceslav Falico" <vfalico@...il.com>
Subject: [PATCH 3.16 35/47] bonding: validate ip header before check
IPPROTO_IGMP
3.16.76-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Cong Wang <xiyou.wangcong@...il.com>
commit 9d1bc24b52fb8c5d859f9a47084bf1179470e04c upstream.
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@...kaller.appspotmail.com
Fixes: a2fd940f4cff ("bonding: fix broken multicast with round-robin mode")
Cc: Jay Vosburgh <j.vosburgh@...il.com>
Cc: Veaceslav Falico <vfalico@...il.com>
Cc: Andy Gospodarek <andy@...yhouse.net>
Signed-off-by: Cong Wang <xiyou.wangcong@...il.com>
Signed-off-by: David S. Miller <davem@...emloft.net>
[bwh: Backported to 3.16:
- Keep using ACCESS_ONCE(), dev_kfree_skb_any(), …_can_tx()
- Adjust context]
Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
drivers/net/bonding/bond_main.c | 37 ++++++++++++++++++++-------------
1 file changed, 23 insertions(+), 14 deletions(-)
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3700,8 +3700,8 @@ static u32 bond_rr_gen_slave_id(struct b
static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct iphdr *iph = ip_hdr(skb);
struct slave *slave;
+ int slave_cnt;
u32 slave_id;
/* Start with the curr_active_slave that joined the bond as the
@@ -3710,23 +3710,32 @@ static int bond_xmit_roundrobin(struct s
* send the join/membership reports. The curr_active_slave found
* will send all of this type of traffic.
*/
- if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
- slave = rcu_dereference(bond->curr_active_slave);
- if (slave && bond_slave_can_tx(slave))
- bond_dev_queue_xmit(bond, skb, slave->dev);
- else
- bond_xmit_slave_id(bond, skb, 0);
- } else {
- int slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+ 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;
- if (likely(slave_cnt)) {
- slave_id = bond_rr_gen_slave_id(bond);
- bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
- } else {
- dev_kfree_skb_any(skb);
+ iph = ip_hdr(skb);
+ if (iph->protocol == IPPROTO_IGMP) {
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave && bond_slave_can_tx(slave))
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
+ bond_xmit_slave_id(bond, skb, 0);
+ return NETDEV_TX_OK;
}
}
+non_igmp:
+ slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+ if (likely(slave_cnt)) {
+ slave_id = bond_rr_gen_slave_id(bond);
+ bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
+ } else {
+ dev_kfree_skb_any(skb);
+ }
return NETDEV_TX_OK;
}
Powered by blists - more mailing lists