af_packet: fix the SO_SNDTIMEO constraint not effective on tpacked_snd()

commit c1ba3c0cbdb5e53a8ec5d708e99cd4c497028a13 upstream.

Due to the changes in commit 581073f626e3 ("af_packet: do not call
packet_read_pending() from tpacket_destruct_skb()"), every time
tpacket_destruct_skb() is executed, the skb_completion is marked as
completed. When wait_for_completion_interruptible_timeout() returns
completed, the pending_refcnt has not yet been reduced to zero.
Therefore, when ph is NULL, the wait function may need to be called
multiple times until packet_read_pending() finally returns zero.

We should call sock_sndtimeo() only once, otherwise the SO_SNDTIMEO
constraint could be way off.

Fixes: 581073f626e3 ("af_packet: do not call packet_read_pending() from tpacket_destruct_skb()")
Cc: stable@kernel.org
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Yun Lu <luyun@kylinos.cn>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Yun Lu
2025-07-11 17:32:59 +08:00
committed by Greg Kroah-Hartman
parent e51cf5d4aa
commit 67ea5f37b2

View File

@@ -2791,7 +2791,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
int len_sum = 0; int len_sum = 0;
int status = TP_STATUS_AVAILABLE; int status = TP_STATUS_AVAILABLE;
int hlen, tlen, copylen = 0; int hlen, tlen, copylen = 0;
long timeo = 0; long timeo;
mutex_lock(&po->pg_vec_lock); mutex_lock(&po->pg_vec_lock);
@@ -2845,6 +2845,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
if ((size_max > dev->mtu + reserve + VLAN_HLEN) && !vnet_hdr_sz) if ((size_max > dev->mtu + reserve + VLAN_HLEN) && !vnet_hdr_sz)
size_max = dev->mtu + reserve + VLAN_HLEN; size_max = dev->mtu + reserve + VLAN_HLEN;
timeo = sock_sndtimeo(&po->sk, msg->msg_flags & MSG_DONTWAIT);
reinit_completion(&po->skb_completion); reinit_completion(&po->skb_completion);
do { do {
@@ -2852,7 +2853,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
TP_STATUS_SEND_REQUEST); TP_STATUS_SEND_REQUEST);
if (unlikely(ph == NULL)) { if (unlikely(ph == NULL)) {
if (need_wait && skb) { if (need_wait && skb) {
timeo = sock_sndtimeo(&po->sk, msg->msg_flags & MSG_DONTWAIT);
timeo = wait_for_completion_interruptible_timeout(&po->skb_completion, timeo); timeo = wait_for_completion_interruptible_timeout(&po->skb_completion, timeo);
if (timeo <= 0) { if (timeo <= 0) {
err = !timeo ? -ETIMEDOUT : -ERESTARTSYS; err = !timeo ? -ETIMEDOUT : -ERESTARTSYS;