| From foo@baz Mon 17 Aug 2020 11:30:21 AM CEST |
| From: John Ogness <john.ogness@linutronix.de> |
| Date: Thu, 13 Aug 2020 21:45:25 +0206 |
| Subject: af_packet: TPACKET_V3: fix fill status rwlock imbalance |
| |
| From: John Ogness <john.ogness@linutronix.de> |
| |
| [ Upstream commit 88fd1cb80daa20af063bce81e1fad14e945a8dc4 ] |
| |
| After @blk_fill_in_prog_lock is acquired there is an early out vnet |
| situation that can occur. In that case, the rwlock needs to be |
| released. |
| |
| Also, since @blk_fill_in_prog_lock is only acquired when @tp_version |
| is exactly TPACKET_V3, only release it on that exact condition as |
| well. |
| |
| And finally, add sparse annotation so that it is clearer that |
| prb_fill_curr_block() and prb_clear_blk_fill_status() are acquiring |
| and releasing @blk_fill_in_prog_lock, respectively. sparse is still |
| unable to understand the balance, but the warnings are now on a |
| higher level that make more sense. |
| |
| Fixes: 632ca50f2cbd ("af_packet: TPACKET_V3: replace busy-wait loop") |
| Signed-off-by: John Ogness <john.ogness@linutronix.de> |
| Reported-by: kernel test robot <lkp@intel.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/packet/af_packet.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/net/packet/af_packet.c |
| +++ b/net/packet/af_packet.c |
| @@ -942,6 +942,7 @@ static int prb_queue_frozen(struct tpack |
| } |
| |
| static void prb_clear_blk_fill_status(struct packet_ring_buffer *rb) |
| + __releases(&pkc->blk_fill_in_prog_lock) |
| { |
| struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb); |
| atomic_dec(&pkc->blk_fill_in_prog); |
| @@ -989,6 +990,7 @@ static void prb_fill_curr_block(char *cu |
| struct tpacket_kbdq_core *pkc, |
| struct tpacket_block_desc *pbd, |
| unsigned int len) |
| + __acquires(&pkc->blk_fill_in_prog_lock) |
| { |
| struct tpacket3_hdr *ppd; |
| |
| @@ -2286,8 +2288,11 @@ static int tpacket_rcv(struct sk_buff *s |
| if (do_vnet && |
| virtio_net_hdr_from_skb(skb, h.raw + macoff - |
| sizeof(struct virtio_net_hdr), |
| - vio_le(), true, 0)) |
| + vio_le(), true, 0)) { |
| + if (po->tp_version == TPACKET_V3) |
| + prb_clear_blk_fill_status(&po->rx_ring); |
| goto drop_n_account; |
| + } |
| |
| if (po->tp_version <= TPACKET_V2) { |
| packet_increment_rx_head(po, &po->rx_ring); |
| @@ -2393,7 +2398,7 @@ static int tpacket_rcv(struct sk_buff *s |
| __clear_bit(slot_id, po->rx_ring.rx_owner_map); |
| spin_unlock(&sk->sk_receive_queue.lock); |
| sk->sk_data_ready(sk); |
| - } else { |
| + } else if (po->tp_version == TPACKET_V3) { |
| prb_clear_blk_fill_status(&po->rx_ring); |
| } |
| |