Blamed commit forgot that set_rps_cpu() was reloading rxqueue->rps_flow_table. If this pointer has changed between get_rps_cpu() read it initially, and the new table size is smaller than @flow_id, we can access out-of-bound data and either corrupt memory or crash. Fix this by passing the flow_table pointer from get_rps_cpu() to set_rps_cpu(), more in line with RCU rules. Fixes: 48aa30443e52 ("net: Cache hash and flow_id to avoid recalculation") Signed-off-by: Eric Dumazet Cc: Krishna Kumar --- net/core/dev.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 096b3ff13f6b9bf685cb74d0e762a2b00e97d9de..7c5e69c771caf7fd590e602384be49019853b490 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4993,13 +4993,11 @@ static bool rps_flow_is_active(struct rps_dev_flow *rflow, static struct rps_dev_flow * set_rps_cpu(struct net_device *dev, struct sk_buff *skb, struct rps_dev_flow *rflow, u16 next_cpu, u32 hash, - u32 flow_id) + u32 flow_id, struct rps_dev_flow_table *flow_table) { if (next_cpu < nr_cpu_ids) { u32 head; #ifdef CONFIG_RFS_ACCEL - struct netdev_rx_queue *rxqueue; - struct rps_dev_flow_table *flow_table; struct rps_dev_flow *old_rflow; struct rps_dev_flow *tmp_rflow; unsigned int tmp_cpu; @@ -5014,11 +5012,6 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb, if (rxq_index == skb_get_rx_queue(skb)) goto out; - rxqueue = dev->_rx + rxq_index; - flow_table = rcu_dereference(rxqueue->rps_flow_table); - if (!flow_table) - goto out; - tmp_rflow = &flow_table->flows[flow_id]; tmp_cpu = READ_ONCE(tmp_rflow->cpu); @@ -5134,7 +5127,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, rflow->last_qtail)) >= 0)) { tcpu = next_cpu; rflow = set_rps_cpu(dev, skb, rflow, next_cpu, hash, - flow_id); + flow_id, flow_table); } if (tcpu < nr_cpu_ids && cpu_online(tcpu)) { -- 2.53.0.345.g96ddfc5eaa-goog