| From b86d9419ae55fd04381f2e0a92d235939420e9ac Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 21 May 2022 09:03:04 +0100 |
| Subject: rxrpc: Fix listen() setting the bar too high for the prealloc rings |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit 88e22159750b0d55793302eeed8ee603f5c1a95c ] |
| |
| AF_RXRPC's listen() handler lets you set the backlog up to 32 (if you bump |
| up the sysctl), but whilst the preallocation circular buffers have 32 slots |
| in them, one of them has to be a dead slot because we're using CIRC_CNT(). |
| |
| This means that listen(rxrpc_sock, 32) will cause an oops when the socket |
| is closed because rxrpc_service_prealloc_one() allocated one too many calls |
| and rxrpc_discard_prealloc() won't then be able to get rid of them because |
| it'll think the ring is empty. rxrpc_release_calls_on_socket() then tries |
| to abort them, but oopses because call->peer isn't yet set. |
| |
| Fix this by setting the maximum backlog to RXRPC_BACKLOG_MAX - 1 to match |
| the ring capacity. |
| |
| BUG: kernel NULL pointer dereference, address: 0000000000000086 |
| ... |
| RIP: 0010:rxrpc_send_abort_packet+0x73/0x240 [rxrpc] |
| Call Trace: |
| <TASK> |
| ? __wake_up_common_lock+0x7a/0x90 |
| ? rxrpc_notify_socket+0x8e/0x140 [rxrpc] |
| ? rxrpc_abort_call+0x4c/0x60 [rxrpc] |
| rxrpc_release_calls_on_socket+0x107/0x1a0 [rxrpc] |
| rxrpc_release+0xc9/0x1c0 [rxrpc] |
| __sock_release+0x37/0xa0 |
| sock_close+0x11/0x20 |
| __fput+0x89/0x240 |
| task_work_run+0x59/0x90 |
| do_exit+0x319/0xaa0 |
| |
| Fixes: 00e907127e6f ("rxrpc: Preallocate peers, conns and calls for incoming service requests") |
| Reported-by: Marc Dionne <marc.dionne@auristor.com> |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| cc: linux-afs@lists.infradead.org |
| Link: https://lists.infradead.org/pipermail/linux-afs/2022-March/005079.html |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/rxrpc/sysctl.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c |
| index 34c706d2f79c..f9afc21b7e2c 100644 |
| --- a/net/rxrpc/sysctl.c |
| +++ b/net/rxrpc/sysctl.c |
| @@ -18,7 +18,7 @@ static struct ctl_table_header *rxrpc_sysctl_reg_table; |
| static const unsigned int zero = 0; |
| static const unsigned int one = 1; |
| static const unsigned int four = 4; |
| -static const unsigned int thirtytwo = 32; |
| +static const unsigned int max_backlog = RXRPC_BACKLOG_MAX - 1; |
| static const unsigned int n_65535 = 65535; |
| static const unsigned int n_max_acks = RXRPC_RXTX_BUFF_SIZE - 1; |
| |
| @@ -114,7 +114,7 @@ static struct ctl_table rxrpc_sysctl_table[] = { |
| .mode = 0644, |
| .proc_handler = proc_dointvec_minmax, |
| .extra1 = (void *)&four, |
| - .extra2 = (void *)&thirtytwo, |
| + .extra2 = (void *)&max_backlog, |
| }, |
| { |
| .procname = "rx_window_size", |
| -- |
| 2.35.1 |
| |