mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 15:03:53 +02:00
af_unix: Don't set -ECONNRESET for consumed OOB skb.
[ Upstream commit2a5a484184
] Christian Brauner reported that even after MSG_OOB data is consumed, calling close() on the receiver socket causes the peer's recv() to return -ECONNRESET: 1. send() and recv() an OOB data. >>> from socket import * >>> s1, s2 = socketpair(AF_UNIX, SOCK_STREAM) >>> s1.send(b'x', MSG_OOB) 1 >>> s2.recv(1, MSG_OOB) b'x' 2. close() for s2 sets ECONNRESET to s1->sk_err even though s2 consumed the OOB data >>> s2.close() >>> s1.recv(10, MSG_DONTWAIT) ... ConnectionResetError: [Errno 104] Connection reset by peer Even after being consumed, the skb holding the OOB 1-byte data stays in the recv queue to mark the OOB boundary and break recv() at that point. This must be considered while close()ing a socket. Let's skip the leading consumed OOB skb while checking the -ECONNRESET condition in unix_release_sock(). Fixes:314001f0bf
("af_unix: Add OOB support") Reported-by: Christian Brauner <brauner@kernel.org> Closes: https://lore.kernel.org/netdev/20250529-sinkt-abfeuern-e7b08200c6b0@brauner/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Acked-by: Christian Brauner <brauner@kernel.org> Link: https://patch.msgid.link/20250619041457.1132791-4-kuni1840@gmail.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
4c3e0c11ba
commit
d9ac9826f5
|
@ -577,6 +577,11 @@ static void unix_sock_destructor(struct sock *sk)
|
|||
#endif
|
||||
}
|
||||
|
||||
static unsigned int unix_skb_len(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->len - UNIXCB(skb).consumed;
|
||||
}
|
||||
|
||||
static void unix_release_sock(struct sock *sk, int embrion)
|
||||
{
|
||||
struct unix_sock *u = unix_sk(sk);
|
||||
|
@ -611,10 +616,16 @@ static void unix_release_sock(struct sock *sk, int embrion)
|
|||
|
||||
if (skpair != NULL) {
|
||||
if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
|
||||
struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
|
||||
|
||||
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
|
||||
if (skb && !unix_skb_len(skb))
|
||||
skb = skb_peek_next(skb, &sk->sk_receive_queue);
|
||||
#endif
|
||||
unix_state_lock(skpair);
|
||||
/* No more writes */
|
||||
WRITE_ONCE(skpair->sk_shutdown, SHUTDOWN_MASK);
|
||||
if (!skb_queue_empty_lockless(&sk->sk_receive_queue) || embrion)
|
||||
if (skb || embrion)
|
||||
WRITE_ONCE(skpair->sk_err, ECONNRESET);
|
||||
unix_state_unlock(skpair);
|
||||
skpair->sk_state_change(skpair);
|
||||
|
@ -2593,11 +2604,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
|
|||
return timeo;
|
||||
}
|
||||
|
||||
static unsigned int unix_skb_len(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->len - UNIXCB(skb).consumed;
|
||||
}
|
||||
|
||||
struct unix_stream_read_state {
|
||||
int (*recv_actor)(struct sk_buff *, int, int,
|
||||
struct unix_stream_read_state *);
|
||||
|
|
Loading…
Reference in New Issue
Block a user