The bug is here: ret = i40e_add_macvlan_filter(hw, ch->seid, vdev->dev_addr, &aq_err); The list iterator 'ch' will point to a bogus position containing HEAD if the list is empty or no element is found. This case must be checked before any use of the iterator, otherwise it will lead to a invalid memory access. To fix this bug, use a new variable 'iter' as the list iterator, while use the origin variable 'ch' as a dedicated pointer to point to the found element.
Unified · Split
| @@ -7549,42 +7549,43 @@ static void i40e_free_macvlan_channels(struct i40e_vsi *vsi) · 7548 unmodified lines | |||
| 7549 | static int i40e_fwd_ring_up(struct i40e_vsi *vsi, struct net_device *vdev, | 7549 | static int i40e_fwd_ring_up(struct i40e_vsi *vsi, struct net_device *vdev, |
| 7550 | struct i40e_fwd_adapter *fwd) | 7550 | struct i40e_fwd_adapter *fwd) |
| 7551 | { | 7551 | { |
| 7552 | struct i40e_channel *ch = NULL, *ch_tmp, *iter; | ||
| 7552 | int ret = 0, num_tc = 1, i, aq_err; | 7553 | int ret = 0, num_tc = 1, i, aq_err; |
| 7553 | struct i40e_channel *ch, *ch_tmp; | ||
| 7554 | struct i40e_pf *pf = vsi->back; | 7554 | struct i40e_pf *pf = vsi->back; |
| 7555 | struct i40e_hw *hw = &pf->hw; | 7555 | struct i40e_hw *hw = &pf->hw; |
| 7556 | 7556 | ||
| 7557 | if (list_empty(&vsi->macvlan_list)) | ||
| 7558 | return -EINVAL; | ||
| 7559 | |||
| 7560 | /* Go through the list and find an available channel */ | 7557 | /* Go through the list and find an available channel */ |
| 7561 | list_for_each_entry_safe(ch, ch_tmp, &vsi->macvlan_list, list) { | 7558 | list_for_each_entry_safe(iter, ch_tmp, &vsi->macvlan_list, list) { |
| 7562 | if (!i40e_is_channel_macvlan(ch)) { | 7559 | if (!i40e_is_channel_macvlan(iter)) { |
| 7563 | ch->fwd = fwd; | 7560 | iter->fwd = fwd; |
| 7564 | /* record configuration for macvlan interface in vdev */ | 7561 | /* record configuration for macvlan interface in vdev */ |
| 7565 | for (i = 0; i < num_tc; i++) | 7562 | for (i = 0; i < num_tc; i++) |
| 7566 | netdev_bind_sb_channel_queue(vsi->netdev, vdev, | 7563 | netdev_bind_sb_channel_queue(vsi->netdev, vdev, |
| 7567 | i, | 7564 | i, |
| 7568 | ch->num_queue_pairs, | 7565 | iter->num_queue_pairs, |
| 7569 | ch->base_queue); | 7566 | iter->base_queue); |
| 7570 | for (i = 0; i < ch->num_queue_pairs; i++) { | 7567 | for (i = 0; i < iter->num_queue_pairs; i++) { |
| 7571 | struct i40e_ring *tx_ring, *rx_ring; | 7568 | struct i40e_ring *tx_ring, *rx_ring; |
| 7572 | u16 pf_q; | 7569 | u16 pf_q; |
| 7573 | 7570 | ||
| 7574 | pf_q = ch->base_queue + i; | 7571 | pf_q = iter->base_queue + i; |
| 7575 | 7572 | ||
| 7576 | /* Get to TX ring ptr */ | 7573 | /* Get to TX ring ptr */ |
| 7577 | tx_ring = vsi->tx_rings[pf_q]; | 7574 | tx_ring = vsi->tx_rings[pf_q]; |
| 7578 | tx_ring->ch = ch; | 7575 | tx_ring->ch = iter; |
| 7579 | 7576 | ||
| 7580 | /* Get the RX ring ptr */ | 7577 | /* Get the RX ring ptr */ |
| 7581 | rx_ring = vsi->rx_rings[pf_q]; | 7578 | rx_ring = vsi->rx_rings[pf_q]; |
| 7582 | rx_ring->ch = ch; | 7579 | rx_ring->ch = iter; |
| 7583 | } | 7580 | } |
| 7581 | ch = iter; | ||
| 7584 | break; | 7582 | break; |
| 7585 | } | 7583 | } |
| 7586 | } | 7584 | } |
| 7587 | 7585 | ||
| 7586 | if (!ch) | ||
| 7587 | return -EINVAL; | ||
| 7588 | |||
| 7588 | /* Guarantee all rings are updated before we update the | 7589 | /* Guarantee all rings are updated before we update the |
| 7589 | * MAC address filter. | 7590 | * MAC address filter. |
| 7590 | */ | 7591 | */ |