提交 d47b2f0c 编写于 作者: J Jakub Kicinski 提交者: Yongqiang Liu

net: stream: don't purge sk_error_queue in sk_stream_kill_queues()

stable inclusion
from stable-v4.19.218
commit 8b8b3d738e450d2c2ccdc75f0ab5a951746c2a96
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6DPF8
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8b8b3d738e450d2c2ccdc75f0ab5a951746c2a96

--------------------------------

[ Upstream commit 24bcbe1c ]

sk_stream_kill_queues() can be called on close when there are
still outstanding skbs to transmit. Those skbs may try to queue
notifications to the error queue (e.g. timestamps).
If sk_stream_kill_queues() purges the queue without taking
its lock the queue may get corrupted, and skbs leaked.

This shows up as a warning about an rmem leak:

WARNING: CPU: 24 PID: 0 at net/ipv4/af_inet.c:154 inet_sock_destruct+0x...

The leak is always a multiple of 0x300 bytes (the value is in
%rax on my builds, so RAX: 0000000000000300). 0x300 is truesize of
an empty sk_buff. Indeed if we dump the socket state at the time
of the warning the sk_error_queue is often (but not always)
corrupted. The ->next pointer points back at the list head,
but not the ->prev pointer. Indeed we can find the leaked skb
by scanning the kernel memory for something that looks like
an skb with ->sk = socket in question, and ->truesize = 0x300.
The contents of ->cb[] of the skb confirms the suspicion that
it is indeed a timestamp notification (as generated in
__skb_complete_tx_timestamp()).

Removing purging of sk_error_queue should be okay, since
inet_sock_destruct() does it again once all socket refs
are gone. Eric suggests this may cause sockets that go
thru disconnect() to maintain notifications from the
previous incarnations of the socket, but that should be
okay since the race was there anyway, and disconnect()
is not exactly dependable.

Thanks to Jonathan Lemon and Omar Sandoval for help at various
stages of tracing the issue.

Fixes: cb9eff09 ("net: new user space API for time stamping of incoming and outgoing packets")
Signed-off-by: NJakub Kicinski <kuba@kernel.org>
Reviewed-by: NEric Dumazet <edumazet@google.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NLu Wei <luwei32@huawei.com>
Reviewed-by: NLiu Jian <liujian56@huawei.com>
Reviewed-by: NYue Haibing <yuehaibing@huawei.com>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 34b18eb0
...@@ -196,9 +196,6 @@ void sk_stream_kill_queues(struct sock *sk) ...@@ -196,9 +196,6 @@ void sk_stream_kill_queues(struct sock *sk)
/* First the read buffer. */ /* First the read buffer. */
__skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_receive_queue);
/* Next, the error queue. */
__skb_queue_purge(&sk->sk_error_queue);
/* Next, the write queue. */ /* Next, the write queue. */
WARN_ON(!skb_queue_empty(&sk->sk_write_queue)); WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册