* [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
@ 2023-01-23 17:22 Hyunwoo Kim
2023-01-25 1:43 ` Kuniyuki Iwashima
0 siblings, 1 reply; 12+ messages in thread
From: Hyunwoo Kim @ 2023-01-23 17:22 UTC (permalink / raw)
To: ralf, davem, edumazet, kuba, pabeni, kuniyu
Cc: v4bel, imv4bel, linux-hams, netdev, syzbot+caa188bdfc1eeafeb418
If listen() and accept() are called on an AF_NETROM socket that
has already been connect()ed, accept() succeeds in connecting.
This is because nr_accept() dequeues the skb queued in
`sk->sk_receive_queue` in nr_connect().
This causes nr_accept() to allocate and return a sock with the
sk of the parent AF_NETROM socket. And here's where use-after-free
can happen through complex race conditions:
```
cpu0 cpu1
1. socket_2 = socket(AF_NETROM)
listen(socket_2)
accepted_socket = accept(socket_2) // loopback connection with socket_1
2. socket_1 = socket(AF_NETROM)
nr_create() // sk refcount : 1
connect(socket_1) // loopback connection with socket_2
nr_connect()
nr_establish_data_link()
nr_write_internal()
nr_transmit_buffer()
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame()
nr_process_rx_frame()
nr_state3_machine()
nr_queue_rx_frame()
sock_queue_rcv_skb()
sock_queue_rcv_skb_reason()
__sock_queue_rcv_skb()
__skb_queue_tail(list, skb); // list : sk->sk_receive_queue
3. listen(socket_1)
nr_listen()
uaf_socket = accept(socket_1)
nr_accept()
skb_dequeue(&sk->sk_receive_queue);
4. close(accepted_socket)
nr_release()
nr_write_internal(sk, NR_DISCREQ)
nr_transmit_buffer() // NR_DISCREQ
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame() // sk : socket_1's sk
nr_process_rx_frame() // NR_STATE_3
nr_state3_machine() // NR_DISCREQ
nr_disconnect()
nr_sk(sk)->state = NR_STATE_0;
5. close(socket_1) // sk refcount : 3
nr_release() // NR_STATE_0
sock_put(sk); // sk refcount : 0
sk_free(sk);
close(uaf_socket)
nr_release()
sock_hold(sk); // UAF
```
KASAN report by syzbot:
```
BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
print_address_description mm/kasan/report.c:306 [inline]
print_report+0x15e/0x461 mm/kasan/report.c:417
kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
check_region_inline mm/kasan/generic.c:183 [inline]
kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
__refcount_add include/linux/refcount.h:193 [inline]
__refcount_inc include/linux/refcount.h:250 [inline]
refcount_inc include/linux/refcount.h:267 [inline]
sock_hold include/net/sock.h:775 [inline]
nr_release+0x66/0x460 net/netrom/af_netrom.c:520
__sock_release+0xcd/0x280 net/socket.c:650
sock_close+0x1c/0x20 net/socket.c:1365
__fput+0x27c/0xa90 fs/file_table.c:320
task_work_run+0x16f/0x270 kernel/task_work.c:179
exit_task_work include/linux/task_work.h:38 [inline]
do_exit+0xaa8/0x2950 kernel/exit.c:867
do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
get_signal+0x21c3/0x2450 kernel/signal.c:2859
arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
__syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x63/0xcd
RIP: 0033:0x7f6c19e3c9b9
Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
</TASK>
Allocated by task 5128:
kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
____kasan_kmalloc mm/kasan/common.c:371 [inline]
____kasan_kmalloc mm/kasan/common.c:330 [inline]
__kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
kasan_kmalloc include/linux/kasan.h:211 [inline]
__do_kmalloc_node mm/slab_common.c:968 [inline]
__kmalloc+0x5a/0xd0 mm/slab_common.c:981
kmalloc include/linux/slab.h:584 [inline]
sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
__sock_create+0x359/0x790 net/socket.c:1515
sock_create net/socket.c:1566 [inline]
__sys_socket_create net/socket.c:1603 [inline]
__sys_socket_create net/socket.c:1588 [inline]
__sys_socket+0x133/0x250 net/socket.c:1636
__do_sys_socket net/socket.c:1649 [inline]
__se_sys_socket net/socket.c:1647 [inline]
__x64_sys_socket+0x73/0xb0 net/socket.c:1647
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
Freed by task 5128:
kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
kasan_slab_free include/linux/kasan.h:177 [inline]
__cache_free mm/slab.c:3394 [inline]
__do_kmem_cache_free mm/slab.c:3580 [inline]
__kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
sk_prot_free net/core/sock.c:2074 [inline]
__sk_destruct+0x5df/0x750 net/core/sock.c:2166
sk_destruct net/core/sock.c:2181 [inline]
__sk_free+0x175/0x460 net/core/sock.c:2192
sk_free+0x7c/0xa0 net/core/sock.c:2203
sock_put include/net/sock.h:1991 [inline]
nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
__sock_release+0xcd/0x280 net/socket.c:650
sock_close+0x1c/0x20 net/socket.c:1365
__fput+0x27c/0xa90 fs/file_table.c:320
task_work_run+0x16f/0x270 kernel/task_work.c:179
exit_task_work include/linux/task_work.h:38 [inline]
do_exit+0xaa8/0x2950 kernel/exit.c:867
do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
get_signal+0x21c3/0x2450 kernel/signal.c:2859
arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
__syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x63/0xcd
```
To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
---
net/netrom/af_netrom.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 6f7f4392cffb..5a4cb796150f 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
struct sock *sk = sock->sk;
lock_sock(sk);
+ if (sock->state != SS_UNCONNECTED) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+
if (sk->sk_state != TCP_LISTEN) {
memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
sk->sk_max_ack_backlog = backlog;
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
2023-01-23 17:22 [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket Hyunwoo Kim
@ 2023-01-25 1:43 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-25 1:43 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
Hi,
I think the diff looks good but changelog is not correct.
From: Hyunwoo Kim <v4bel@theori.io>
Date: Mon, 23 Jan 2023 09:22:33 -0800
> If listen() and accept() are called on an AF_NETROM socket that
> has already been connect()ed, accept() succeeds in connecting.
> This is because nr_accept() dequeues the skb queued in
> `sk->sk_receive_queue` in nr_connect().
This sentence is misleading. The skb sent by nr_connect() is queued
up for the peer's sk_receive_queue (socket_2 below), and also the reply
is not queued for connect()er (socket_1) because it is NR_CONNACK and
just consumed by nr_state1_machine() to transition to NR_STATE_3 and
TCP_ESTABLISHED.
>
> This causes nr_accept() to allocate and return a sock with the
> sk of the parent AF_NETROM socket.
This happens because the peer (socket_2) sends some data by nr_sendmsg(),
whose type is NR_INFO and the data is queued up for the connect()er's
(socket_1) sk_receive_queue by
- nr_state3_machine
- nr_queue_rx_frame
- sock_queue_rcv_skb
> And here's where use-after-free
> can happen through complex race conditions:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> listen(socket_2)
> accepted_socket = accept(socket_2) // loopback connection with socket_1
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1) // loopback connection with socket_2
> nr_connect()
> nr_establish_data_link()
> nr_write_internal()
This is NR_CONNREQ for socket_2.
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame()
So, nr_process_rx_frame() is not called from nr_rx_frame() because the
kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
and then responds with NR_CONNACK to socket_1.
And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
is called for socket_1 and the skb with sk pointing socket_1 is queued for
socket_1's sk_receive_queue.
I think this part is lacking in this UAF scenario.
What do you think ?
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
>
> 3. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 4. close(accepted_socket)
And I guess this close() is not so important in this case.
Even if we don't close the socket cleanly, the UAF will happen, right ?
(it might be caused in a different place like timer though)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 5. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
>
> KASAN report by syzbot:
> ```
> BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
>
> Call Trace:
> <TASK>
> __dump_stack lib/dump_stack.c:88 [inline]
> dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> print_address_description mm/kasan/report.c:306 [inline]
> print_report+0x15e/0x461 mm/kasan/report.c:417
> kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> check_region_inline mm/kasan/generic.c:183 [inline]
> kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> __refcount_add include/linux/refcount.h:193 [inline]
> __refcount_inc include/linux/refcount.h:250 [inline]
> refcount_inc include/linux/refcount.h:267 [inline]
> sock_hold include/net/sock.h:775 [inline]
> nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> RIP: 0033:0x7f6c19e3c9b9
> Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> </TASK>
>
> Allocated by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> kasan_kmalloc include/linux/kasan.h:211 [inline]
> __do_kmalloc_node mm/slab_common.c:968 [inline]
> __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> kmalloc include/linux/slab.h:584 [inline]
> sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> __sock_create+0x359/0x790 net/socket.c:1515
> sock_create net/socket.c:1566 [inline]
> __sys_socket_create net/socket.c:1603 [inline]
> __sys_socket_create net/socket.c:1588 [inline]
> __sys_socket+0x133/0x250 net/socket.c:1636
> __do_sys_socket net/socket.c:1649 [inline]
> __se_sys_socket net/socket.c:1647 [inline]
> __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
>
> Freed by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> __cache_free mm/slab.c:3394 [inline]
> __do_kmem_cache_free mm/slab.c:3580 [inline]
> __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> ```
>
> To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> ---
> net/netrom/af_netrom.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> index 6f7f4392cffb..5a4cb796150f 100644
> --- a/net/netrom/af_netrom.c
> +++ b/net/netrom/af_netrom.c
> @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> struct sock *sk = sock->sk;
>
> lock_sock(sk);
> + if (sock->state != SS_UNCONNECTED) {
> + release_sock(sk);
> + return -EINVAL;
> + }
> +
> if (sk->sk_state != TCP_LISTEN) {
> memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> sk->sk_max_ack_backlog = backlog;
> --
> 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
@ 2023-01-25 1:43 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-25 1:43 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
Hi,
I think the diff looks good but changelog is not correct.
From: Hyunwoo Kim <v4bel@theori.io>
Date: Mon, 23 Jan 2023 09:22:33 -0800
> If listen() and accept() are called on an AF_NETROM socket that
> has already been connect()ed, accept() succeeds in connecting.
> This is because nr_accept() dequeues the skb queued in
> `sk->sk_receive_queue` in nr_connect().
This sentence is misleading. The skb sent by nr_connect() is queued
up for the peer's sk_receive_queue (socket_2 below), and also the reply
is not queued for connect()er (socket_1) because it is NR_CONNACK and
just consumed by nr_state1_machine() to transition to NR_STATE_3 and
TCP_ESTABLISHED.
>
> This causes nr_accept() to allocate and return a sock with the
> sk of the parent AF_NETROM socket.
This happens because the peer (socket_2) sends some data by nr_sendmsg(),
whose type is NR_INFO and the data is queued up for the connect()er's
(socket_1) sk_receive_queue by
- nr_state3_machine
- nr_queue_rx_frame
- sock_queue_rcv_skb
> And here's where use-after-free
> can happen through complex race conditions:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> listen(socket_2)
> accepted_socket = accept(socket_2) // loopback connection with socket_1
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1) // loopback connection with socket_2
> nr_connect()
> nr_establish_data_link()
> nr_write_internal()
This is NR_CONNREQ for socket_2.
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame()
So, nr_process_rx_frame() is not called from nr_rx_frame() because the
kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
and then responds with NR_CONNACK to socket_1.
And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
is called for socket_1 and the skb with sk pointing socket_1 is queued for
socket_1's sk_receive_queue.
I think this part is lacking in this UAF scenario.
What do you think ?
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
>
> 3. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 4. close(accepted_socket)
And I guess this close() is not so important in this case.
Even if we don't close the socket cleanly, the UAF will happen, right ?
(it might be caused in a different place like timer though)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 5. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
>
> KASAN report by syzbot:
> ```
> BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
>
> Call Trace:
> <TASK>
> __dump_stack lib/dump_stack.c:88 [inline]
> dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> print_address_description mm/kasan/report.c:306 [inline]
> print_report+0x15e/0x461 mm/kasan/report.c:417
> kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> check_region_inline mm/kasan/generic.c:183 [inline]
> kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> __refcount_add include/linux/refcount.h:193 [inline]
> __refcount_inc include/linux/refcount.h:250 [inline]
> refcount_inc include/linux/refcount.h:267 [inline]
> sock_hold include/net/sock.h:775 [inline]
> nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> RIP: 0033:0x7f6c19e3c9b9
> Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> </TASK>
>
> Allocated by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> kasan_kmalloc include/linux/kasan.h:211 [inline]
> __do_kmalloc_node mm/slab_common.c:968 [inline]
> __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> kmalloc include/linux/slab.h:584 [inline]
> sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> __sock_create+0x359/0x790 net/socket.c:1515
> sock_create net/socket.c:1566 [inline]
> __sys_socket_create net/socket.c:1603 [inline]
> __sys_socket_create net/socket.c:1588 [inline]
> __sys_socket+0x133/0x250 net/socket.c:1636
> __do_sys_socket net/socket.c:1649 [inline]
> __se_sys_socket net/socket.c:1647 [inline]
> __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
>
> Freed by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> __cache_free mm/slab.c:3394 [inline]
> __do_kmem_cache_free mm/slab.c:3580 [inline]
> __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> ```
>
> To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> ---
> net/netrom/af_netrom.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> index 6f7f4392cffb..5a4cb796150f 100644
> --- a/net/netrom/af_netrom.c
> +++ b/net/netrom/af_netrom.c
> @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> struct sock *sk = sock->sk;
>
> lock_sock(sk);
> + if (sock->state != SS_UNCONNECTED) {
> + release_sock(sk);
> + return -EINVAL;
> + }
> +
> if (sk->sk_state != TCP_LISTEN) {
> memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> sk->sk_max_ack_backlog = backlog;
> --
> 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
2023-01-25 1:43 ` Kuniyuki Iwashima
(?)
@ 2023-01-25 9:17 ` Hyunwoo Kim
2023-01-25 16:40 ` Kuniyuki Iwashima
-1 siblings, 1 reply; 12+ messages in thread
From: Hyunwoo Kim @ 2023-01-25 9:17 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: davem, edumazet, v4bel, imv4bel, kuba, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> Hi,
>
> I think the diff looks good but changelog is not correct.
>
> From: Hyunwoo Kim <v4bel@theori.io>
> Date: Mon, 23 Jan 2023 09:22:33 -0800
> > If listen() and accept() are called on an AF_NETROM socket that
> > has already been connect()ed, accept() succeeds in connecting.
> > This is because nr_accept() dequeues the skb queued in
> > `sk->sk_receive_queue` in nr_connect().
>
> This sentence is misleading. The skb sent by nr_connect() is queued
> up for the peer's sk_receive_queue (socket_2 below), and also the reply
> is not queued for connect()er (socket_1) because it is NR_CONNACK and
> just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> TCP_ESTABLISHED.
>
>
> >
> > This causes nr_accept() to allocate and return a sock with the
> > sk of the parent AF_NETROM socket.
>
> This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> whose type is NR_INFO and the data is queued up for the connect()er's
> (socket_1) sk_receive_queue by
>
> - nr_state3_machine
> - nr_queue_rx_frame
> - sock_queue_rcv_skb
you're right.
I misanalyzed nr_rx_frame(). sorry.
>
>
> > And here's where use-after-free
> > can happen through complex race conditions:
> > ```
> > cpu0 cpu1
> > 1. socket_2 = socket(AF_NETROM)
> > listen(socket_2)
> > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > 2. socket_1 = socket(AF_NETROM)
> > nr_create() // sk refcount : 1
> > connect(socket_1) // loopback connection with socket_2
> > nr_connect()
> > nr_establish_data_link()
> > nr_write_internal()
>
> This is NR_CONNREQ for socket_2.
>
>
> > nr_transmit_buffer()
> > nr_route_frame()
> > nr_loopback_queue()
> > nr_loopback_timer()
> > nr_rx_frame()
> > nr_process_rx_frame()
>
> So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> and then responds with NR_CONNACK to socket_1.
>
> And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> is called for socket_1 and the skb with sk pointing socket_1 is queued for
> socket_1's sk_receive_queue.
>
> I think this part is lacking in this UAF scenario.
>
> What do you think ?
>
>
> > nr_state3_machine()
> > nr_queue_rx_frame()
> > sock_queue_rcv_skb()
> > sock_queue_rcv_skb_reason()
> > __sock_queue_rcv_skb()
> > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> >
> > 3. listen(socket_1)
> > nr_listen()
> > uaf_socket = accept(socket_1)
> > nr_accept()
> > skb_dequeue(&sk->sk_receive_queue);
> > 4. close(accepted_socket)
>
> And I guess this close() is not so important in this case.
> Even if we don't close the socket cleanly, the UAF will happen, right ?
> (it might be caused in a different place like timer though)
IMHO, I think this `close(accepted_socket)` is a necessary procedure.
This is because `case NR_STATE_3:` in nr_release() is executed here,
and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
`case NR_STATE_0:` in `close(socket_1)` and sk is not released.
This means you will not be able to trigger UAF on close(uaf_socket).
What do you think?
So the modified flow chart looks like this:
```
cpu0 cpu1
1. socket_2 = socket(AF_NETROM)
.
.
listen(socket_2)
accepted_socket = accept(socket_2)
2. socket_1 = socket(AF_NETROM)
nr_create() // sk refcount : 1
connect(socket_1)
nr_connect()
nr_establish_data_link()
nr_write_internal()
nr_transmit_buffer()
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame()
nr_process_rx_frame()
nr_state1_machine()
nr->state = NR_STATE_3;
3. write(accepted_socket)
nr_sendmsg()
nr_output()
nr_kick()
nr_send_iframe()
nr_transmit_buffer()
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_process_rx_frame(sk, skb); // sk : socket_1's sk
nr_state3_machine()
nr_queue_rx_frame()
sock_queue_rcv_skb()
sock_queue_rcv_skb_reason()
__sock_queue_rcv_skb()
__skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
4. listen(socket_1)
nr_listen()
uaf_socket = accept(socket_1)
nr_accept()
skb_dequeue(&sk->sk_receive_queue);
5. close(accepted_socket)
nr_release()
nr_write_internal(sk, NR_DISCREQ)
nr_transmit_buffer() // NR_DISCREQ
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame() // sk : socket_1's sk
nr_process_rx_frame() // NR_STATE_3
nr_state3_machine() // NR_DISCREQ
nr_disconnect()
nr_sk(sk)->state = NR_STATE_0;
6. close(socket_1) // sk refcount : 3
nr_release() // NR_STATE_0
sock_put(sk); // sk refcount : 0
sk_free(sk);
close(uaf_socket)
nr_release()
sock_hold(sk); // UAF
```
Anything wrong?
>
> > nr_release()
> > nr_write_internal(sk, NR_DISCREQ)
> > nr_transmit_buffer() // NR_DISCREQ
> > nr_route_frame()
> > nr_loopback_queue()
> > nr_loopback_timer()
> > nr_rx_frame() // sk : socket_1's sk
> > nr_process_rx_frame() // NR_STATE_3
> > nr_state3_machine() // NR_DISCREQ
> > nr_disconnect()
> > nr_sk(sk)->state = NR_STATE_0;
> > 5. close(socket_1) // sk refcount : 3
> > nr_release() // NR_STATE_0
> > sock_put(sk); // sk refcount : 0
> > sk_free(sk);
> > close(uaf_socket)
> > nr_release()
> > sock_hold(sk); // UAF
> > ```
> >
> > KASAN report by syzbot:
> > ```
> > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> >
> > Call Trace:
> > <TASK>
> > __dump_stack lib/dump_stack.c:88 [inline]
> > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > print_address_description mm/kasan/report.c:306 [inline]
> > print_report+0x15e/0x461 mm/kasan/report.c:417
> > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > check_region_inline mm/kasan/generic.c:183 [inline]
> > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > __refcount_add include/linux/refcount.h:193 [inline]
> > __refcount_inc include/linux/refcount.h:250 [inline]
> > refcount_inc include/linux/refcount.h:267 [inline]
> > sock_hold include/net/sock.h:775 [inline]
> > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > __sock_release+0xcd/0x280 net/socket.c:650
> > sock_close+0x1c/0x20 net/socket.c:1365
> > __fput+0x27c/0xa90 fs/file_table.c:320
> > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > exit_task_work include/linux/task_work.h:38 [inline]
> > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > RIP: 0033:0x7f6c19e3c9b9
> > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > </TASK>
> >
> > Allocated by task 5128:
> > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > kmalloc include/linux/slab.h:584 [inline]
> > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > __sock_create+0x359/0x790 net/socket.c:1515
> > sock_create net/socket.c:1566 [inline]
> > __sys_socket_create net/socket.c:1603 [inline]
> > __sys_socket_create net/socket.c:1588 [inline]
> > __sys_socket+0x133/0x250 net/socket.c:1636
> > __do_sys_socket net/socket.c:1649 [inline]
> > __se_sys_socket net/socket.c:1647 [inline]
> > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> >
> > Freed by task 5128:
> > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > kasan_slab_free include/linux/kasan.h:177 [inline]
> > __cache_free mm/slab.c:3394 [inline]
> > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > sk_prot_free net/core/sock.c:2074 [inline]
> > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > sk_destruct net/core/sock.c:2181 [inline]
> > __sk_free+0x175/0x460 net/core/sock.c:2192
> > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > sock_put include/net/sock.h:1991 [inline]
> > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > __sock_release+0xcd/0x280 net/socket.c:650
> > sock_close+0x1c/0x20 net/socket.c:1365
> > __fput+0x27c/0xa90 fs/file_table.c:320
> > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > exit_task_work include/linux/task_work.h:38 [inline]
> > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > ```
> >
> > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> >
> > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > ---
> > net/netrom/af_netrom.c | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > index 6f7f4392cffb..5a4cb796150f 100644
> > --- a/net/netrom/af_netrom.c
> > +++ b/net/netrom/af_netrom.c
> > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > struct sock *sk = sock->sk;
> >
> > lock_sock(sk);
> > + if (sock->state != SS_UNCONNECTED) {
> > + release_sock(sk);
> > + return -EINVAL;
> > + }
> > +
> > if (sk->sk_state != TCP_LISTEN) {
> > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > sk->sk_max_ack_backlog = backlog;
> > --
> > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
2023-01-25 9:17 ` Hyunwoo Kim
@ 2023-01-25 16:40 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-25 16:40 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
From: Hyunwoo Kim <v4bel@theori.io>
Date: Wed, 25 Jan 2023 01:17:10 -0800
> On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> > Hi,
> >
> > I think the diff looks good but changelog is not correct.
> >
> > From: Hyunwoo Kim <v4bel@theori.io>
> > Date: Mon, 23 Jan 2023 09:22:33 -0800
> > > If listen() and accept() are called on an AF_NETROM socket that
> > > has already been connect()ed, accept() succeeds in connecting.
> > > This is because nr_accept() dequeues the skb queued in
> > > `sk->sk_receive_queue` in nr_connect().
> >
> > This sentence is misleading. The skb sent by nr_connect() is queued
> > up for the peer's sk_receive_queue (socket_2 below), and also the reply
> > is not queued for connect()er (socket_1) because it is NR_CONNACK and
> > just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> > TCP_ESTABLISHED.
> >
> >
> > >
> > > This causes nr_accept() to allocate and return a sock with the
> > > sk of the parent AF_NETROM socket.
> >
> > This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> > whose type is NR_INFO and the data is queued up for the connect()er's
> > (socket_1) sk_receive_queue by
> >
> > - nr_state3_machine
> > - nr_queue_rx_frame
> > - sock_queue_rcv_skb
>
> you're right.
> I misanalyzed nr_rx_frame(). sorry.
>
> >
> >
> > > And here's where use-after-free
> > > can happen through complex race conditions:
> > > ```
> > > cpu0 cpu1
> > > 1. socket_2 = socket(AF_NETROM)
> > > listen(socket_2)
> > > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > > 2. socket_1 = socket(AF_NETROM)
> > > nr_create() // sk refcount : 1
> > > connect(socket_1) // loopback connection with socket_2
> > > nr_connect()
> > > nr_establish_data_link()
> > > nr_write_internal()
> >
> > This is NR_CONNREQ for socket_2.
> >
> >
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame()
> > > nr_process_rx_frame()
> >
> > So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> > kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> > and then responds with NR_CONNACK to socket_1.
> >
> > And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> > is called for socket_1 and the skb with sk pointing socket_1 is queued for
> > socket_1's sk_receive_queue.
> >
> > I think this part is lacking in this UAF scenario.
> >
> > What do you think ?
> >
> >
> > > nr_state3_machine()
> > > nr_queue_rx_frame()
> > > sock_queue_rcv_skb()
> > > sock_queue_rcv_skb_reason()
> > > __sock_queue_rcv_skb()
> > > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> > >
> > > 3. listen(socket_1)
> > > nr_listen()
> > > uaf_socket = accept(socket_1)
> > > nr_accept()
> > > skb_dequeue(&sk->sk_receive_queue);
> > > 4. close(accepted_socket)
> >
> > And I guess this close() is not so important in this case.
> > Even if we don't close the socket cleanly, the UAF will happen, right ?
> > (it might be caused in a different place like timer though)
>
> IMHO, I think this `close(accepted_socket)` is a necessary procedure.
> This is because `case NR_STATE_3:` in nr_release() is executed here,
> and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
> If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
> `case NR_STATE_0:` in `close(socket_1)` and sk is not released.
No, it's released by the heartbeat timer. The heartbeat timer finally
calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.
> This means you will not be able to trigger UAF on close(uaf_socket).
I didn't say close(uaf_socket) is not needed, I mean we can
trigger UAF without close(__accepted_socket__).
>
> What do you think?
>
> So the modified flow chart looks like this:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> .
> .
> listen(socket_2)
> accepted_socket = accept(socket_2)
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1)
> nr_connect()
> nr_establish_data_link()
> nr_write_internal()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame()
> nr_state1_machine()
> nr->state = NR_STATE_3;
If you write the connect()'s stack trace, you should note the state
change at the socket_1 side by NR_CONNACK. The NR_STATE_3 here is
for socket_2 by NR_CONNREQ. We don't need the details of socket_2.
Otherwise, you should just write connect(socket_1) only like the
step 1 (socket(), listen() etc).
> 3. write(accepted_socket)
> nr_sendmsg()
> nr_output()
> nr_kick()
> nr_send_iframe()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> 4. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 5. close(accepted_socket)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 6. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
>
> Anything wrong?
>
>
> >
> > > nr_release()
> > > nr_write_internal(sk, NR_DISCREQ)
> > > nr_transmit_buffer() // NR_DISCREQ
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame() // sk : socket_1's sk
> > > nr_process_rx_frame() // NR_STATE_3
> > > nr_state3_machine() // NR_DISCREQ
> > > nr_disconnect()
> > > nr_sk(sk)->state = NR_STATE_0;
> > > 5. close(socket_1) // sk refcount : 3
> > > nr_release() // NR_STATE_0
> > > sock_put(sk); // sk refcount : 0
> > > sk_free(sk);
> > > close(uaf_socket)
> > > nr_release()
> > > sock_hold(sk); // UAF
> > > ```
> > >
> > > KASAN report by syzbot:
> > > ```
> > > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> > >
> > > Call Trace:
> > > <TASK>
> > > __dump_stack lib/dump_stack.c:88 [inline]
> > > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > > print_address_description mm/kasan/report.c:306 [inline]
> > > print_report+0x15e/0x461 mm/kasan/report.c:417
> > > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > > check_region_inline mm/kasan/generic.c:183 [inline]
> > > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > > __refcount_add include/linux/refcount.h:193 [inline]
> > > __refcount_inc include/linux/refcount.h:250 [inline]
> > > refcount_inc include/linux/refcount.h:267 [inline]
> > > sock_hold include/net/sock.h:775 [inline]
> > > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > __sock_release+0xcd/0x280 net/socket.c:650
> > > sock_close+0x1c/0x20 net/socket.c:1365
> > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > exit_task_work include/linux/task_work.h:38 [inline]
> > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > RIP: 0033:0x7f6c19e3c9b9
> > > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > > </TASK>
> > >
> > > Allocated by task 5128:
> > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > > kmalloc include/linux/slab.h:584 [inline]
> > > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > > __sock_create+0x359/0x790 net/socket.c:1515
> > > sock_create net/socket.c:1566 [inline]
> > > __sys_socket_create net/socket.c:1603 [inline]
> > > __sys_socket_create net/socket.c:1588 [inline]
> > > __sys_socket+0x133/0x250 net/socket.c:1636
> > > __do_sys_socket net/socket.c:1649 [inline]
> > > __se_sys_socket net/socket.c:1647 [inline]
> > > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > >
> > > Freed by task 5128:
> > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > > kasan_slab_free include/linux/kasan.h:177 [inline]
> > > __cache_free mm/slab.c:3394 [inline]
> > > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > > sk_prot_free net/core/sock.c:2074 [inline]
> > > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > > sk_destruct net/core/sock.c:2181 [inline]
> > > __sk_free+0x175/0x460 net/core/sock.c:2192
> > > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > > sock_put include/net/sock.h:1991 [inline]
> > > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > > __sock_release+0xcd/0x280 net/socket.c:650
> > > sock_close+0x1c/0x20 net/socket.c:1365
> > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > exit_task_work include/linux/task_work.h:38 [inline]
> > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > ```
> > >
> > > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> > >
> > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > > ---
> > > net/netrom/af_netrom.c | 5 +++++
> > > 1 file changed, 5 insertions(+)
> > >
> > > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > > index 6f7f4392cffb..5a4cb796150f 100644
> > > --- a/net/netrom/af_netrom.c
> > > +++ b/net/netrom/af_netrom.c
> > > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > > struct sock *sk = sock->sk;
> > >
> > > lock_sock(sk);
> > > + if (sock->state != SS_UNCONNECTED) {
> > > + release_sock(sk);
> > > + return -EINVAL;
> > > + }
> > > +
> > > if (sk->sk_state != TCP_LISTEN) {
> > > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > > sk->sk_max_ack_backlog = backlog;
> > > --
> > > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
@ 2023-01-25 16:40 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-25 16:40 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
From: Hyunwoo Kim <v4bel@theori.io>
Date: Wed, 25 Jan 2023 01:17:10 -0800
> On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> > Hi,
> >
> > I think the diff looks good but changelog is not correct.
> >
> > From: Hyunwoo Kim <v4bel@theori.io>
> > Date: Mon, 23 Jan 2023 09:22:33 -0800
> > > If listen() and accept() are called on an AF_NETROM socket that
> > > has already been connect()ed, accept() succeeds in connecting.
> > > This is because nr_accept() dequeues the skb queued in
> > > `sk->sk_receive_queue` in nr_connect().
> >
> > This sentence is misleading. The skb sent by nr_connect() is queued
> > up for the peer's sk_receive_queue (socket_2 below), and also the reply
> > is not queued for connect()er (socket_1) because it is NR_CONNACK and
> > just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> > TCP_ESTABLISHED.
> >
> >
> > >
> > > This causes nr_accept() to allocate and return a sock with the
> > > sk of the parent AF_NETROM socket.
> >
> > This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> > whose type is NR_INFO and the data is queued up for the connect()er's
> > (socket_1) sk_receive_queue by
> >
> > - nr_state3_machine
> > - nr_queue_rx_frame
> > - sock_queue_rcv_skb
>
> you're right.
> I misanalyzed nr_rx_frame(). sorry.
>
> >
> >
> > > And here's where use-after-free
> > > can happen through complex race conditions:
> > > ```
> > > cpu0 cpu1
> > > 1. socket_2 = socket(AF_NETROM)
> > > listen(socket_2)
> > > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > > 2. socket_1 = socket(AF_NETROM)
> > > nr_create() // sk refcount : 1
> > > connect(socket_1) // loopback connection with socket_2
> > > nr_connect()
> > > nr_establish_data_link()
> > > nr_write_internal()
> >
> > This is NR_CONNREQ for socket_2.
> >
> >
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame()
> > > nr_process_rx_frame()
> >
> > So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> > kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> > and then responds with NR_CONNACK to socket_1.
> >
> > And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> > is called for socket_1 and the skb with sk pointing socket_1 is queued for
> > socket_1's sk_receive_queue.
> >
> > I think this part is lacking in this UAF scenario.
> >
> > What do you think ?
> >
> >
> > > nr_state3_machine()
> > > nr_queue_rx_frame()
> > > sock_queue_rcv_skb()
> > > sock_queue_rcv_skb_reason()
> > > __sock_queue_rcv_skb()
> > > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> > >
> > > 3. listen(socket_1)
> > > nr_listen()
> > > uaf_socket = accept(socket_1)
> > > nr_accept()
> > > skb_dequeue(&sk->sk_receive_queue);
> > > 4. close(accepted_socket)
> >
> > And I guess this close() is not so important in this case.
> > Even if we don't close the socket cleanly, the UAF will happen, right ?
> > (it might be caused in a different place like timer though)
>
> IMHO, I think this `close(accepted_socket)` is a necessary procedure.
> This is because `case NR_STATE_3:` in nr_release() is executed here,
> and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
> If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
> `case NR_STATE_0:` in `close(socket_1)` and sk is not released.
No, it's released by the heartbeat timer. The heartbeat timer finally
calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.
> This means you will not be able to trigger UAF on close(uaf_socket).
I didn't say close(uaf_socket) is not needed, I mean we can
trigger UAF without close(__accepted_socket__).
>
> What do you think?
>
> So the modified flow chart looks like this:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> .
> .
> listen(socket_2)
> accepted_socket = accept(socket_2)
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1)
> nr_connect()
> nr_establish_data_link()
> nr_write_internal()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame()
> nr_state1_machine()
> nr->state = NR_STATE_3;
If you write the connect()'s stack trace, you should note the state
change at the socket_1 side by NR_CONNACK. The NR_STATE_3 here is
for socket_2 by NR_CONNREQ. We don't need the details of socket_2.
Otherwise, you should just write connect(socket_1) only like the
step 1 (socket(), listen() etc).
> 3. write(accepted_socket)
> nr_sendmsg()
> nr_output()
> nr_kick()
> nr_send_iframe()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> 4. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 5. close(accepted_socket)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 6. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
>
> Anything wrong?
>
>
> >
> > > nr_release()
> > > nr_write_internal(sk, NR_DISCREQ)
> > > nr_transmit_buffer() // NR_DISCREQ
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame() // sk : socket_1's sk
> > > nr_process_rx_frame() // NR_STATE_3
> > > nr_state3_machine() // NR_DISCREQ
> > > nr_disconnect()
> > > nr_sk(sk)->state = NR_STATE_0;
> > > 5. close(socket_1) // sk refcount : 3
> > > nr_release() // NR_STATE_0
> > > sock_put(sk); // sk refcount : 0
> > > sk_free(sk);
> > > close(uaf_socket)
> > > nr_release()
> > > sock_hold(sk); // UAF
> > > ```
> > >
> > > KASAN report by syzbot:
> > > ```
> > > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> > >
> > > Call Trace:
> > > <TASK>
> > > __dump_stack lib/dump_stack.c:88 [inline]
> > > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > > print_address_description mm/kasan/report.c:306 [inline]
> > > print_report+0x15e/0x461 mm/kasan/report.c:417
> > > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > > check_region_inline mm/kasan/generic.c:183 [inline]
> > > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > > __refcount_add include/linux/refcount.h:193 [inline]
> > > __refcount_inc include/linux/refcount.h:250 [inline]
> > > refcount_inc include/linux/refcount.h:267 [inline]
> > > sock_hold include/net/sock.h:775 [inline]
> > > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > __sock_release+0xcd/0x280 net/socket.c:650
> > > sock_close+0x1c/0x20 net/socket.c:1365
> > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > exit_task_work include/linux/task_work.h:38 [inline]
> > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > RIP: 0033:0x7f6c19e3c9b9
> > > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > > </TASK>
> > >
> > > Allocated by task 5128:
> > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > > kmalloc include/linux/slab.h:584 [inline]
> > > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > > __sock_create+0x359/0x790 net/socket.c:1515
> > > sock_create net/socket.c:1566 [inline]
> > > __sys_socket_create net/socket.c:1603 [inline]
> > > __sys_socket_create net/socket.c:1588 [inline]
> > > __sys_socket+0x133/0x250 net/socket.c:1636
> > > __do_sys_socket net/socket.c:1649 [inline]
> > > __se_sys_socket net/socket.c:1647 [inline]
> > > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > >
> > > Freed by task 5128:
> > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > > kasan_slab_free include/linux/kasan.h:177 [inline]
> > > __cache_free mm/slab.c:3394 [inline]
> > > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > > sk_prot_free net/core/sock.c:2074 [inline]
> > > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > > sk_destruct net/core/sock.c:2181 [inline]
> > > __sk_free+0x175/0x460 net/core/sock.c:2192
> > > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > > sock_put include/net/sock.h:1991 [inline]
> > > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > > __sock_release+0xcd/0x280 net/socket.c:650
> > > sock_close+0x1c/0x20 net/socket.c:1365
> > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > exit_task_work include/linux/task_work.h:38 [inline]
> > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > ```
> > >
> > > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> > >
> > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > > ---
> > > net/netrom/af_netrom.c | 5 +++++
> > > 1 file changed, 5 insertions(+)
> > >
> > > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > > index 6f7f4392cffb..5a4cb796150f 100644
> > > --- a/net/netrom/af_netrom.c
> > > +++ b/net/netrom/af_netrom.c
> > > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > > struct sock *sk = sock->sk;
> > >
> > > lock_sock(sk);
> > > + if (sock->state != SS_UNCONNECTED) {
> > > + release_sock(sk);
> > > + return -EINVAL;
> > > + }
> > > +
> > > if (sk->sk_state != TCP_LISTEN) {
> > > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > > sk->sk_max_ack_backlog = backlog;
> > > --
> > > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
2023-01-25 16:40 ` Kuniyuki Iwashima
(?)
@ 2023-01-26 4:16 ` Hyunwoo Kim
2023-01-26 17:34 ` Kuniyuki Iwashima
-1 siblings, 1 reply; 12+ messages in thread
From: Hyunwoo Kim @ 2023-01-26 4:16 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: davem, edumazet, v4bel, imv4bel, kuba, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
On Wed, Jan 25, 2023 at 08:40:35AM -0800, Kuniyuki Iwashima wrote:
> From: Hyunwoo Kim <v4bel@theori.io>
> Date: Wed, 25 Jan 2023 01:17:10 -0800
> > On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> > > Hi,
> > >
> > > I think the diff looks good but changelog is not correct.
> > >
> > > From: Hyunwoo Kim <v4bel@theori.io>
> > > Date: Mon, 23 Jan 2023 09:22:33 -0800
> > > > If listen() and accept() are called on an AF_NETROM socket that
> > > > has already been connect()ed, accept() succeeds in connecting.
> > > > This is because nr_accept() dequeues the skb queued in
> > > > `sk->sk_receive_queue` in nr_connect().
> > >
> > > This sentence is misleading. The skb sent by nr_connect() is queued
> > > up for the peer's sk_receive_queue (socket_2 below), and also the reply
> > > is not queued for connect()er (socket_1) because it is NR_CONNACK and
> > > just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> > > TCP_ESTABLISHED.
> > >
> > >
> > > >
> > > > This causes nr_accept() to allocate and return a sock with the
> > > > sk of the parent AF_NETROM socket.
> > >
> > > This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> > > whose type is NR_INFO and the data is queued up for the connect()er's
> > > (socket_1) sk_receive_queue by
> > >
> > > - nr_state3_machine
> > > - nr_queue_rx_frame
> > > - sock_queue_rcv_skb
> >
> > you're right.
> > I misanalyzed nr_rx_frame(). sorry.
> >
> > >
> > >
> > > > And here's where use-after-free
> > > > can happen through complex race conditions:
> > > > ```
> > > > cpu0 cpu1
> > > > 1. socket_2 = socket(AF_NETROM)
> > > > listen(socket_2)
> > > > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > > > 2. socket_1 = socket(AF_NETROM)
> > > > nr_create() // sk refcount : 1
> > > > connect(socket_1) // loopback connection with socket_2
> > > > nr_connect()
> > > > nr_establish_data_link()
> > > > nr_write_internal()
> > >
> > > This is NR_CONNREQ for socket_2.
> > >
> > >
> > > > nr_transmit_buffer()
> > > > nr_route_frame()
> > > > nr_loopback_queue()
> > > > nr_loopback_timer()
> > > > nr_rx_frame()
> > > > nr_process_rx_frame()
> > >
> > > So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> > > kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> > > and then responds with NR_CONNACK to socket_1.
> > >
> > > And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> > > is called for socket_1 and the skb with sk pointing socket_1 is queued for
> > > socket_1's sk_receive_queue.
> > >
> > > I think this part is lacking in this UAF scenario.
> > >
> > > What do you think ?
> > >
> > >
> > > > nr_state3_machine()
> > > > nr_queue_rx_frame()
> > > > sock_queue_rcv_skb()
> > > > sock_queue_rcv_skb_reason()
> > > > __sock_queue_rcv_skb()
> > > > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> > > >
> > > > 3. listen(socket_1)
> > > > nr_listen()
> > > > uaf_socket = accept(socket_1)
> > > > nr_accept()
> > > > skb_dequeue(&sk->sk_receive_queue);
> > > > 4. close(accepted_socket)
> > >
> > > And I guess this close() is not so important in this case.
> > > Even if we don't close the socket cleanly, the UAF will happen, right ?
> > > (it might be caused in a different place like timer though)
> >
> > IMHO, I think this `close(accepted_socket)` is a necessary procedure.
> > This is because `case NR_STATE_3:` in nr_release() is executed here,
> > and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
> > If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
> > `case NR_STATE_0:` in `close(socket_1)` and sk is not released.
>
> No, it's released by the heartbeat timer. The heartbeat timer finally
> calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.
>
>
> > This means you will not be able to trigger UAF on close(uaf_socket).
>
> I didn't say close(uaf_socket) is not needed, I mean we can
> trigger UAF without close(__accepted_socket__).
ok. understand. The reason why I put close(accepted_socket)
is because Freed by task in the KASAN log I attached to the
patch description is as follows:
```
Freed by task 5128:
kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
kasan_slab_free include/linux/kasan.h:177 [inline]
__cache_free mm/slab.c:3394 [inline]
__do_kmem_cache_free mm/slab.c:3580 [inline]
__kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
sk_prot_free net/core/sock.c:2074 [inline]
__sk_destruct+0x5df/0x750 net/core/sock.c:2166
sk_destruct net/core/sock.c:2181 [inline]
__sk_free+0x175/0x460 net/core/sock.c:2192
sk_free+0x7c/0xa0 net/core/sock.c:2203
sock_put include/net/sock.h:1991 [inline]
nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
__sock_release+0xcd/0x280 net/socket.c:650
sock_close+0x1c/0x20 net/socket.c:1365
__fput+0x27c/0xa90 fs/file_table.c:320
task_work_run+0x16f/0x270 kernel/task_work.c:179
exit_task_work include/linux/task_work.h:38 [inline]
do_exit+0xaa8/0x2950 kernel/exit.c:867
do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
get_signal+0x21c3/0x2450 kernel/signal.c:2859
arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
__syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x63/0xcd
```
If, as you say, heartbeat is running and UAF is triggered,
the KASAN Freed log will look like this:
```
Freed by task 14094:
kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
kasan_set_track+0x25/0x30 mm/kasan/common.c:52
kasan_save_free_info+0x2e/0x40 mm/kasan/generic.c:518
____kasan_slab_free mm/kasan/common.c:236 [inline]
____kasan_slab_free+0x160/0x1c0 mm/kasan/common.c:200
kasan_slab_free include/linux/kasan.h:177 [inline]
slab_free_hook mm/slub.c:1781 [inline]
slab_free_freelist_hook+0x8b/0x1c0 mm/slub.c:1807
slab_free mm/slub.c:3787 [inline]
__kmem_cache_free+0xaf/0x3b0 mm/slub.c:3800
sk_prot_free net/core/sock.c:2074 [inline]
__sk_destruct+0x5df/0x750 net/core/sock.c:2166
sk_destruct net/core/sock.c:2181 [inline]
__sk_free+0x175/0x460 net/core/sock.c:2192
sk_free+0x7c/0xa0 net/core/sock.c:2203
sock_put include/net/sock.h:1991 [inline]
nr_heartbeat_expiry+0x1d7/0x460 net/netrom/nr_timer.c:148
call_timer_fn+0x1da/0x7c0 kernel/time/timer.c:1700
expire_timers+0x2c6/0x5c0 kernel/time/timer.c:1751
__run_timers kernel/time/timer.c:2022 [inline]
__run_timers kernel/time/timer.c:1995 [inline]
run_timer_softirq+0x326/0x910 kernel/time/timer.c:2035
__do_softirq+0x1fb/0xadc kernel/softirq.c:571
```
Anyway, I'm trying to keep close(accepted_socket) in the flow chart
because the KASAN log I added to the first patch description is the first one.
>
>
> >
> > What do you think?
> >
> > So the modified flow chart looks like this:
> > ```
> > cpu0 cpu1
> > 1. socket_2 = socket(AF_NETROM)
> > .
> > .
> > listen(socket_2)
> > accepted_socket = accept(socket_2)
> > 2. socket_1 = socket(AF_NETROM)
> > nr_create() // sk refcount : 1
> > connect(socket_1)
> > nr_connect()
> > nr_establish_data_link()
> > nr_write_internal()
> > nr_transmit_buffer()
> > nr_route_frame()
> > nr_loopback_queue()
> > nr_loopback_timer()
> > nr_rx_frame()
> > nr_process_rx_frame()
> > nr_state1_machine()
> > nr->state = NR_STATE_3;
>
> If you write the connect()'s stack trace, you should note the state
> change at the socket_1 side by NR_CONNACK. The NR_STATE_3 here is
> for socket_2 by NR_CONNREQ. We don't need the details of socket_2.
>
> Otherwise, you should just write connect(socket_1) only like the
> step 1 (socket(), listen() etc).
So, the modified flow chart is:
```
cpu0 cpu1
1. socket_2 = socket(AF_NETROM)
.
.
listen(socket_2)
accepted_socket = accept(socket_2)
2. socket_1 = socket(AF_NETROM)
nr_create() // sk refcount : 1
connect(socket_1)
3. write(accepted_socket)
nr_sendmsg()
nr_output()
nr_kick()
nr_send_iframe()
nr_transmit_buffer()
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame()
nr_process_rx_frame(sk, skb); // sk : socket_1's sk
nr_state3_machine()
nr_queue_rx_frame()
sock_queue_rcv_skb()
sock_queue_rcv_skb_reason()
__sock_queue_rcv_skb()
__skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
4. listen(socket_1)
nr_listen()
uaf_socket = accept(socket_1)
nr_accept()
skb_dequeue(&sk->sk_receive_queue);
5. close(accepted_socket)
nr_release()
nr_write_internal(sk, NR_DISCREQ)
nr_transmit_buffer() // NR_DISCREQ
nr_route_frame()
nr_loopback_queue()
nr_loopback_timer()
nr_rx_frame() // sk : socket_1's sk
nr_process_rx_frame() // NR_STATE_3
nr_state3_machine() // NR_DISCREQ
nr_disconnect()
nr_sk(sk)->state = NR_STATE_0;
6. close(socket_1) // sk refcount : 3
nr_release() // NR_STATE_0
sock_put(sk); // sk refcount : 0
sk_free(sk);
close(uaf_socket)
nr_release()
sock_hold(sk); // UAF
```
And sorry for sending the v3 netrom patch first.
I received an email that the v2 x25 patch with the wrong patch
description was applied to the tree,
so I made a v3 x25 patch in a hurry and sent the netrom as well.
>
>
> > 3. write(accepted_socket)
> > nr_sendmsg()
> > nr_output()
> > nr_kick()
> > nr_send_iframe()
> > nr_transmit_buffer()
> > nr_route_frame()
> > nr_loopback_queue()
> > nr_loopback_timer()
> > nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> > nr_state3_machine()
> > nr_queue_rx_frame()
> > sock_queue_rcv_skb()
> > sock_queue_rcv_skb_reason()
> > __sock_queue_rcv_skb()
> > __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> > 4. listen(socket_1)
> > nr_listen()
> > uaf_socket = accept(socket_1)
> > nr_accept()
> > skb_dequeue(&sk->sk_receive_queue);
> > 5. close(accepted_socket)
> > nr_release()
> > nr_write_internal(sk, NR_DISCREQ)
> > nr_transmit_buffer() // NR_DISCREQ
> > nr_route_frame()
> > nr_loopback_queue()
> > nr_loopback_timer()
> > nr_rx_frame() // sk : socket_1's sk
> > nr_process_rx_frame() // NR_STATE_3
> > nr_state3_machine() // NR_DISCREQ
> > nr_disconnect()
> > nr_sk(sk)->state = NR_STATE_0;
> > 6. close(socket_1) // sk refcount : 3
> > nr_release() // NR_STATE_0
> > sock_put(sk); // sk refcount : 0
> > sk_free(sk);
> > close(uaf_socket)
> > nr_release()
> > sock_hold(sk); // UAF
> > ```
> >
> > Anything wrong?
> >
> >
> > >
> > > > nr_release()
> > > > nr_write_internal(sk, NR_DISCREQ)
> > > > nr_transmit_buffer() // NR_DISCREQ
> > > > nr_route_frame()
> > > > nr_loopback_queue()
> > > > nr_loopback_timer()
> > > > nr_rx_frame() // sk : socket_1's sk
> > > > nr_process_rx_frame() // NR_STATE_3
> > > > nr_state3_machine() // NR_DISCREQ
> > > > nr_disconnect()
> > > > nr_sk(sk)->state = NR_STATE_0;
> > > > 5. close(socket_1) // sk refcount : 3
> > > > nr_release() // NR_STATE_0
> > > > sock_put(sk); // sk refcount : 0
> > > > sk_free(sk);
> > > > close(uaf_socket)
> > > > nr_release()
> > > > sock_hold(sk); // UAF
> > > > ```
> > > >
> > > > KASAN report by syzbot:
> > > > ```
> > > > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> > > >
> > > > Call Trace:
> > > > <TASK>
> > > > __dump_stack lib/dump_stack.c:88 [inline]
> > > > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > > > print_address_description mm/kasan/report.c:306 [inline]
> > > > print_report+0x15e/0x461 mm/kasan/report.c:417
> > > > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > > > check_region_inline mm/kasan/generic.c:183 [inline]
> > > > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > > > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > > > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > > > __refcount_add include/linux/refcount.h:193 [inline]
> > > > __refcount_inc include/linux/refcount.h:250 [inline]
> > > > refcount_inc include/linux/refcount.h:267 [inline]
> > > > sock_hold include/net/sock.h:775 [inline]
> > > > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > RIP: 0033:0x7f6c19e3c9b9
> > > > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > > > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > > > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > > > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > > > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > > > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > > > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > > > </TASK>
> > > >
> > > > Allocated by task 5128:
> > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > > > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > > > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > > > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > > > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > > > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > > > kmalloc include/linux/slab.h:584 [inline]
> > > > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > > > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > > > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > > > __sock_create+0x359/0x790 net/socket.c:1515
> > > > sock_create net/socket.c:1566 [inline]
> > > > __sys_socket_create net/socket.c:1603 [inline]
> > > > __sys_socket_create net/socket.c:1588 [inline]
> > > > __sys_socket+0x133/0x250 net/socket.c:1636
> > > > __do_sys_socket net/socket.c:1649 [inline]
> > > > __se_sys_socket net/socket.c:1647 [inline]
> > > > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > > > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > > > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > >
> > > > Freed by task 5128:
> > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > > > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > > > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > > > kasan_slab_free include/linux/kasan.h:177 [inline]
> > > > __cache_free mm/slab.c:3394 [inline]
> > > > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > > > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > > > sk_prot_free net/core/sock.c:2074 [inline]
> > > > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > > > sk_destruct net/core/sock.c:2181 [inline]
> > > > __sk_free+0x175/0x460 net/core/sock.c:2192
> > > > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > > > sock_put include/net/sock.h:1991 [inline]
> > > > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > ```
> > > >
> > > > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> > > >
> > > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > > > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > > > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > > > ---
> > > > net/netrom/af_netrom.c | 5 +++++
> > > > 1 file changed, 5 insertions(+)
> > > >
> > > > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > > > index 6f7f4392cffb..5a4cb796150f 100644
> > > > --- a/net/netrom/af_netrom.c
> > > > +++ b/net/netrom/af_netrom.c
> > > > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > > > struct sock *sk = sock->sk;
> > > >
> > > > lock_sock(sk);
> > > > + if (sock->state != SS_UNCONNECTED) {
> > > > + release_sock(sk);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > if (sk->sk_state != TCP_LISTEN) {
> > > > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > > > sk->sk_max_ack_backlog = backlog;
> > > > --
> > > > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
2023-01-26 4:16 ` Hyunwoo Kim
@ 2023-01-26 17:34 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-26 17:34 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
From: Hyunwoo Kim <v4bel@theori.io>
Date: Wed, 25 Jan 2023 20:16:36 -0800
> On Wed, Jan 25, 2023 at 08:40:35AM -0800, Kuniyuki Iwashima wrote:
> > From: Hyunwoo Kim <v4bel@theori.io>
> > Date: Wed, 25 Jan 2023 01:17:10 -0800
> > > On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> > > > Hi,
> > > >
> > > > I think the diff looks good but changelog is not correct.
> > > >
> > > > From: Hyunwoo Kim <v4bel@theori.io>
> > > > Date: Mon, 23 Jan 2023 09:22:33 -0800
> > > > > If listen() and accept() are called on an AF_NETROM socket that
> > > > > has already been connect()ed, accept() succeeds in connecting.
> > > > > This is because nr_accept() dequeues the skb queued in
> > > > > `sk->sk_receive_queue` in nr_connect().
> > > >
> > > > This sentence is misleading. The skb sent by nr_connect() is queued
> > > > up for the peer's sk_receive_queue (socket_2 below), and also the reply
> > > > is not queued for connect()er (socket_1) because it is NR_CONNACK and
> > > > just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> > > > TCP_ESTABLISHED.
> > > >
> > > >
> > > > >
> > > > > This causes nr_accept() to allocate and return a sock with the
> > > > > sk of the parent AF_NETROM socket.
> > > >
> > > > This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> > > > whose type is NR_INFO and the data is queued up for the connect()er's
> > > > (socket_1) sk_receive_queue by
> > > >
> > > > - nr_state3_machine
> > > > - nr_queue_rx_frame
> > > > - sock_queue_rcv_skb
> > >
> > > you're right.
> > > I misanalyzed nr_rx_frame(). sorry.
> > >
> > > >
> > > >
> > > > > And here's where use-after-free
> > > > > can happen through complex race conditions:
> > > > > ```
> > > > > cpu0 cpu1
> > > > > 1. socket_2 = socket(AF_NETROM)
> > > > > listen(socket_2)
> > > > > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > > > > 2. socket_1 = socket(AF_NETROM)
> > > > > nr_create() // sk refcount : 1
> > > > > connect(socket_1) // loopback connection with socket_2
> > > > > nr_connect()
> > > > > nr_establish_data_link()
> > > > > nr_write_internal()
> > > >
> > > > This is NR_CONNREQ for socket_2.
> > > >
> > > >
> > > > > nr_transmit_buffer()
> > > > > nr_route_frame()
> > > > > nr_loopback_queue()
> > > > > nr_loopback_timer()
> > > > > nr_rx_frame()
> > > > > nr_process_rx_frame()
> > > >
> > > > So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> > > > kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> > > > and then responds with NR_CONNACK to socket_1.
> > > >
> > > > And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> > > > is called for socket_1 and the skb with sk pointing socket_1 is queued for
> > > > socket_1's sk_receive_queue.
> > > >
> > > > I think this part is lacking in this UAF scenario.
> > > >
> > > > What do you think ?
> > > >
> > > >
> > > > > nr_state3_machine()
> > > > > nr_queue_rx_frame()
> > > > > sock_queue_rcv_skb()
> > > > > sock_queue_rcv_skb_reason()
> > > > > __sock_queue_rcv_skb()
> > > > > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> > > > >
> > > > > 3. listen(socket_1)
> > > > > nr_listen()
> > > > > uaf_socket = accept(socket_1)
> > > > > nr_accept()
> > > > > skb_dequeue(&sk->sk_receive_queue);
> > > > > 4. close(accepted_socket)
> > > >
> > > > And I guess this close() is not so important in this case.
> > > > Even if we don't close the socket cleanly, the UAF will happen, right ?
> > > > (it might be caused in a different place like timer though)
> > >
> > > IMHO, I think this `close(accepted_socket)` is a necessary procedure.
> > > This is because `case NR_STATE_3:` in nr_release() is executed here,
> > > and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
> > > If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
> > > `case NR_STATE_0:` in `close(socket_1)` and sk is not released.
> >
> > No, it's released by the heartbeat timer. The heartbeat timer finally
> > calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.
> >
> >
> > > This means you will not be able to trigger UAF on close(uaf_socket).
> >
> > I didn't say close(uaf_socket) is not needed, I mean we can
> > trigger UAF without close(__accepted_socket__).
>
> ok. understand. The reason why I put close(accepted_socket)
> is because Freed by task in the KASAN log I attached to the
> patch description is as follows:
Ah, right.
Sorry, I was confused with 3 close()s :/
> ```
> Freed by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> __cache_free mm/slab.c:3394 [inline]
> __do_kmem_cache_free mm/slab.c:3580 [inline]
> __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> ```
>
> If, as you say, heartbeat is running and UAF is triggered,
> the KASAN Freed log will look like this:
> ```
> Freed by task 14094:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2e/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x160/0x1c0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> slab_free_hook mm/slub.c:1781 [inline]
> slab_free_freelist_hook+0x8b/0x1c0 mm/slub.c:1807
> slab_free mm/slub.c:3787 [inline]
> __kmem_cache_free+0xaf/0x3b0 mm/slub.c:3800
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_heartbeat_expiry+0x1d7/0x460 net/netrom/nr_timer.c:148
> call_timer_fn+0x1da/0x7c0 kernel/time/timer.c:1700
> expire_timers+0x2c6/0x5c0 kernel/time/timer.c:1751
> __run_timers kernel/time/timer.c:2022 [inline]
> __run_timers kernel/time/timer.c:1995 [inline]
> run_timer_softirq+0x326/0x910 kernel/time/timer.c:2035
> __do_softirq+0x1fb/0xadc kernel/softirq.c:571
> ```
>
> Anyway, I'm trying to keep close(accepted_socket) in the flow chart
> because the KASAN log I added to the first patch description is the first one.
>
> >
> >
> > >
> > > What do you think?
> > >
> > > So the modified flow chart looks like this:
> > > ```
> > > cpu0 cpu1
> > > 1. socket_2 = socket(AF_NETROM)
> > > .
> > > .
> > > listen(socket_2)
> > > accepted_socket = accept(socket_2)
> > > 2. socket_1 = socket(AF_NETROM)
> > > nr_create() // sk refcount : 1
> > > connect(socket_1)
> > > nr_connect()
> > > nr_establish_data_link()
> > > nr_write_internal()
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame()
> > > nr_process_rx_frame()
> > > nr_state1_machine()
> > > nr->state = NR_STATE_3;
> >
> > If you write the connect()'s stack trace, you should note the state
> > change at the socket_1 side by NR_CONNACK. The NR_STATE_3 here is
> > for socket_2 by NR_CONNREQ. We don't need the details of socket_2.
> >
> > Otherwise, you should just write connect(socket_1) only like the
> > step 1 (socket(), listen() etc).
>
> So, the modified flow chart is:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> .
> .
> listen(socket_2)
> accepted_socket = accept(socket_2)
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1)
> 3. write(accepted_socket)
> nr_sendmsg()
> nr_output()
> nr_kick()
> nr_send_iframe()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> 4. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 5. close(accepted_socket)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 6. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
Ok, this looks good.
Please send v4 without my Reviewed-by tag.
Thank you.
>
> And sorry for sending the v3 netrom patch first.
> I received an email that the v2 x25 patch with the wrong patch
> description was applied to the tree,
> so I made a v3 x25 patch in a hurry and sent the netrom as well.
>
> >
> >
> > > 3. write(accepted_socket)
> > > nr_sendmsg()
> > > nr_output()
> > > nr_kick()
> > > nr_send_iframe()
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> > > nr_state3_machine()
> > > nr_queue_rx_frame()
> > > sock_queue_rcv_skb()
> > > sock_queue_rcv_skb_reason()
> > > __sock_queue_rcv_skb()
> > > __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> > > 4. listen(socket_1)
> > > nr_listen()
> > > uaf_socket = accept(socket_1)
> > > nr_accept()
> > > skb_dequeue(&sk->sk_receive_queue);
> > > 5. close(accepted_socket)
> > > nr_release()
> > > nr_write_internal(sk, NR_DISCREQ)
> > > nr_transmit_buffer() // NR_DISCREQ
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame() // sk : socket_1's sk
> > > nr_process_rx_frame() // NR_STATE_3
> > > nr_state3_machine() // NR_DISCREQ
> > > nr_disconnect()
> > > nr_sk(sk)->state = NR_STATE_0;
> > > 6. close(socket_1) // sk refcount : 3
> > > nr_release() // NR_STATE_0
> > > sock_put(sk); // sk refcount : 0
> > > sk_free(sk);
> > > close(uaf_socket)
> > > nr_release()
> > > sock_hold(sk); // UAF
> > > ```
> > >
> > > Anything wrong?
> > >
> > >
> > > >
> > > > > nr_release()
> > > > > nr_write_internal(sk, NR_DISCREQ)
> > > > > nr_transmit_buffer() // NR_DISCREQ
> > > > > nr_route_frame()
> > > > > nr_loopback_queue()
> > > > > nr_loopback_timer()
> > > > > nr_rx_frame() // sk : socket_1's sk
> > > > > nr_process_rx_frame() // NR_STATE_3
> > > > > nr_state3_machine() // NR_DISCREQ
> > > > > nr_disconnect()
> > > > > nr_sk(sk)->state = NR_STATE_0;
> > > > > 5. close(socket_1) // sk refcount : 3
> > > > > nr_release() // NR_STATE_0
> > > > > sock_put(sk); // sk refcount : 0
> > > > > sk_free(sk);
> > > > > close(uaf_socket)
> > > > > nr_release()
> > > > > sock_hold(sk); // UAF
> > > > > ```
> > > > >
> > > > > KASAN report by syzbot:
> > > > > ```
> > > > > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> > > > >
> > > > > Call Trace:
> > > > > <TASK>
> > > > > __dump_stack lib/dump_stack.c:88 [inline]
> > > > > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > > > > print_address_description mm/kasan/report.c:306 [inline]
> > > > > print_report+0x15e/0x461 mm/kasan/report.c:417
> > > > > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > > > > check_region_inline mm/kasan/generic.c:183 [inline]
> > > > > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > > > > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > > > > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > > > > __refcount_add include/linux/refcount.h:193 [inline]
> > > > > __refcount_inc include/linux/refcount.h:250 [inline]
> > > > > refcount_inc include/linux/refcount.h:267 [inline]
> > > > > sock_hold include/net/sock.h:775 [inline]
> > > > > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > > RIP: 0033:0x7f6c19e3c9b9
> > > > > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > > > > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > > > > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > > > > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > > > > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > > > > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > > > > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > > > > </TASK>
> > > > >
> > > > > Allocated by task 5128:
> > > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > > > > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > > > > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > > > > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > > > > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > > > > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > > > > kmalloc include/linux/slab.h:584 [inline]
> > > > > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > > > > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > > > > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > > > > __sock_create+0x359/0x790 net/socket.c:1515
> > > > > sock_create net/socket.c:1566 [inline]
> > > > > __sys_socket_create net/socket.c:1603 [inline]
> > > > > __sys_socket_create net/socket.c:1588 [inline]
> > > > > __sys_socket+0x133/0x250 net/socket.c:1636
> > > > > __do_sys_socket net/socket.c:1649 [inline]
> > > > > __se_sys_socket net/socket.c:1647 [inline]
> > > > > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > > > > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > > > > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > >
> > > > > Freed by task 5128:
> > > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > > > > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > > > > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > > > > kasan_slab_free include/linux/kasan.h:177 [inline]
> > > > > __cache_free mm/slab.c:3394 [inline]
> > > > > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > > > > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > > > > sk_prot_free net/core/sock.c:2074 [inline]
> > > > > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > > > > sk_destruct net/core/sock.c:2181 [inline]
> > > > > __sk_free+0x175/0x460 net/core/sock.c:2192
> > > > > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > > > > sock_put include/net/sock.h:1991 [inline]
> > > > > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > > ```
> > > > >
> > > > > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> > > > >
> > > > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > > > > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > > > > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > > > > ---
> > > > > net/netrom/af_netrom.c | 5 +++++
> > > > > 1 file changed, 5 insertions(+)
> > > > >
> > > > > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > > > > index 6f7f4392cffb..5a4cb796150f 100644
> > > > > --- a/net/netrom/af_netrom.c
> > > > > +++ b/net/netrom/af_netrom.c
> > > > > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > > > > struct sock *sk = sock->sk;
> > > > >
> > > > > lock_sock(sk);
> > > > > + if (sock->state != SS_UNCONNECTED) {
> > > > > + release_sock(sk);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > if (sk->sk_state != TCP_LISTEN) {
> > > > > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > > > > sk->sk_max_ack_backlog = backlog;
> > > > > --
> > > > > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket
@ 2023-01-26 17:34 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-01-26 17:34 UTC (permalink / raw)
To: v4bel
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418
From: Hyunwoo Kim <v4bel@theori.io>
Date: Wed, 25 Jan 2023 20:16:36 -0800
> On Wed, Jan 25, 2023 at 08:40:35AM -0800, Kuniyuki Iwashima wrote:
> > From: Hyunwoo Kim <v4bel@theori.io>
> > Date: Wed, 25 Jan 2023 01:17:10 -0800
> > > On Tue, Jan 24, 2023 at 05:43:47PM -0800, Kuniyuki Iwashima wrote:
> > > > Hi,
> > > >
> > > > I think the diff looks good but changelog is not correct.
> > > >
> > > > From: Hyunwoo Kim <v4bel@theori.io>
> > > > Date: Mon, 23 Jan 2023 09:22:33 -0800
> > > > > If listen() and accept() are called on an AF_NETROM socket that
> > > > > has already been connect()ed, accept() succeeds in connecting.
> > > > > This is because nr_accept() dequeues the skb queued in
> > > > > `sk->sk_receive_queue` in nr_connect().
> > > >
> > > > This sentence is misleading. The skb sent by nr_connect() is queued
> > > > up for the peer's sk_receive_queue (socket_2 below), and also the reply
> > > > is not queued for connect()er (socket_1) because it is NR_CONNACK and
> > > > just consumed by nr_state1_machine() to transition to NR_STATE_3 and
> > > > TCP_ESTABLISHED.
> > > >
> > > >
> > > > >
> > > > > This causes nr_accept() to allocate and return a sock with the
> > > > > sk of the parent AF_NETROM socket.
> > > >
> > > > This happens because the peer (socket_2) sends some data by nr_sendmsg(),
> > > > whose type is NR_INFO and the data is queued up for the connect()er's
> > > > (socket_1) sk_receive_queue by
> > > >
> > > > - nr_state3_machine
> > > > - nr_queue_rx_frame
> > > > - sock_queue_rcv_skb
> > >
> > > you're right.
> > > I misanalyzed nr_rx_frame(). sorry.
> > >
> > > >
> > > >
> > > > > And here's where use-after-free
> > > > > can happen through complex race conditions:
> > > > > ```
> > > > > cpu0 cpu1
> > > > > 1. socket_2 = socket(AF_NETROM)
> > > > > listen(socket_2)
> > > > > accepted_socket = accept(socket_2) // loopback connection with socket_1
> > > > > 2. socket_1 = socket(AF_NETROM)
> > > > > nr_create() // sk refcount : 1
> > > > > connect(socket_1) // loopback connection with socket_2
> > > > > nr_connect()
> > > > > nr_establish_data_link()
> > > > > nr_write_internal()
> > > >
> > > > This is NR_CONNREQ for socket_2.
> > > >
> > > >
> > > > > nr_transmit_buffer()
> > > > > nr_route_frame()
> > > > > nr_loopback_queue()
> > > > > nr_loopback_timer()
> > > > > nr_rx_frame()
> > > > > nr_process_rx_frame()
> > > >
> > > > So, nr_process_rx_frame() is not called from nr_rx_frame() because the
> > > > kernel finds socket_2 by nr_find_listener(), and creates accepted_socket,
> > > > and then responds with NR_CONNACK to socket_1.
> > > >
> > > > And accepted_socket sends some data with NR_INFO, then, nr_state3_machine()
> > > > is called for socket_1 and the skb with sk pointing socket_1 is queued for
> > > > socket_1's sk_receive_queue.
> > > >
> > > > I think this part is lacking in this UAF scenario.
> > > >
> > > > What do you think ?
> > > >
> > > >
> > > > > nr_state3_machine()
> > > > > nr_queue_rx_frame()
> > > > > sock_queue_rcv_skb()
> > > > > sock_queue_rcv_skb_reason()
> > > > > __sock_queue_rcv_skb()
> > > > > __skb_queue_tail(list, skb); // list : sk->sk_receive_queue
> > > > >
> > > > > 3. listen(socket_1)
> > > > > nr_listen()
> > > > > uaf_socket = accept(socket_1)
> > > > > nr_accept()
> > > > > skb_dequeue(&sk->sk_receive_queue);
> > > > > 4. close(accepted_socket)
> > > >
> > > > And I guess this close() is not so important in this case.
> > > > Even if we don't close the socket cleanly, the UAF will happen, right ?
> > > > (it might be caused in a different place like timer though)
> > >
> > > IMHO, I think this `close(accepted_socket)` is a necessary procedure.
> > > This is because `case NR_STATE_3:` in nr_release() is executed here,
> > > and nr_write_internal(sk, NR_DISCREQ) ~ nr_disconnect() sets socket_1's sk to NR_STATE_0.
> > > If sk of socket_1 is not set to NR_STATE_0, `case NR_STATE_3:` is executed instead of
> > > `case NR_STATE_0:` in `close(socket_1)` and sk is not released.
> >
> > No, it's released by the heartbeat timer. The heartbeat timer finally
> > calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.
> >
> >
> > > This means you will not be able to trigger UAF on close(uaf_socket).
> >
> > I didn't say close(uaf_socket) is not needed, I mean we can
> > trigger UAF without close(__accepted_socket__).
>
> ok. understand. The reason why I put close(accepted_socket)
> is because Freed by task in the KASAN log I attached to the
> patch description is as follows:
Ah, right.
Sorry, I was confused with 3 close()s :/
> ```
> Freed by task 5128:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> __cache_free mm/slab.c:3394 [inline]
> __do_kmem_cache_free mm/slab.c:3580 [inline]
> __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> __sock_release+0xcd/0x280 net/socket.c:650
> sock_close+0x1c/0x20 net/socket.c:1365
> __fput+0x27c/0xa90 fs/file_table.c:320
> task_work_run+0x16f/0x270 kernel/task_work.c:179
> exit_task_work include/linux/task_work.h:38 [inline]
> do_exit+0xaa8/0x2950 kernel/exit.c:867
> do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> get_signal+0x21c3/0x2450 kernel/signal.c:2859
> arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> entry_SYSCALL_64_after_hwframe+0x63/0xcd
> ```
>
> If, as you say, heartbeat is running and UAF is triggered,
> the KASAN Freed log will look like this:
> ```
> Freed by task 14094:
> kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> kasan_save_free_info+0x2e/0x40 mm/kasan/generic.c:518
> ____kasan_slab_free mm/kasan/common.c:236 [inline]
> ____kasan_slab_free+0x160/0x1c0 mm/kasan/common.c:200
> kasan_slab_free include/linux/kasan.h:177 [inline]
> slab_free_hook mm/slub.c:1781 [inline]
> slab_free_freelist_hook+0x8b/0x1c0 mm/slub.c:1807
> slab_free mm/slub.c:3787 [inline]
> __kmem_cache_free+0xaf/0x3b0 mm/slub.c:3800
> sk_prot_free net/core/sock.c:2074 [inline]
> __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> sk_destruct net/core/sock.c:2181 [inline]
> __sk_free+0x175/0x460 net/core/sock.c:2192
> sk_free+0x7c/0xa0 net/core/sock.c:2203
> sock_put include/net/sock.h:1991 [inline]
> nr_heartbeat_expiry+0x1d7/0x460 net/netrom/nr_timer.c:148
> call_timer_fn+0x1da/0x7c0 kernel/time/timer.c:1700
> expire_timers+0x2c6/0x5c0 kernel/time/timer.c:1751
> __run_timers kernel/time/timer.c:2022 [inline]
> __run_timers kernel/time/timer.c:1995 [inline]
> run_timer_softirq+0x326/0x910 kernel/time/timer.c:2035
> __do_softirq+0x1fb/0xadc kernel/softirq.c:571
> ```
>
> Anyway, I'm trying to keep close(accepted_socket) in the flow chart
> because the KASAN log I added to the first patch description is the first one.
>
> >
> >
> > >
> > > What do you think?
> > >
> > > So the modified flow chart looks like this:
> > > ```
> > > cpu0 cpu1
> > > 1. socket_2 = socket(AF_NETROM)
> > > .
> > > .
> > > listen(socket_2)
> > > accepted_socket = accept(socket_2)
> > > 2. socket_1 = socket(AF_NETROM)
> > > nr_create() // sk refcount : 1
> > > connect(socket_1)
> > > nr_connect()
> > > nr_establish_data_link()
> > > nr_write_internal()
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame()
> > > nr_process_rx_frame()
> > > nr_state1_machine()
> > > nr->state = NR_STATE_3;
> >
> > If you write the connect()'s stack trace, you should note the state
> > change at the socket_1 side by NR_CONNACK. The NR_STATE_3 here is
> > for socket_2 by NR_CONNREQ. We don't need the details of socket_2.
> >
> > Otherwise, you should just write connect(socket_1) only like the
> > step 1 (socket(), listen() etc).
>
> So, the modified flow chart is:
> ```
> cpu0 cpu1
> 1. socket_2 = socket(AF_NETROM)
> .
> .
> listen(socket_2)
> accepted_socket = accept(socket_2)
> 2. socket_1 = socket(AF_NETROM)
> nr_create() // sk refcount : 1
> connect(socket_1)
> 3. write(accepted_socket)
> nr_sendmsg()
> nr_output()
> nr_kick()
> nr_send_iframe()
> nr_transmit_buffer()
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame()
> nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> nr_state3_machine()
> nr_queue_rx_frame()
> sock_queue_rcv_skb()
> sock_queue_rcv_skb_reason()
> __sock_queue_rcv_skb()
> __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> 4. listen(socket_1)
> nr_listen()
> uaf_socket = accept(socket_1)
> nr_accept()
> skb_dequeue(&sk->sk_receive_queue);
> 5. close(accepted_socket)
> nr_release()
> nr_write_internal(sk, NR_DISCREQ)
> nr_transmit_buffer() // NR_DISCREQ
> nr_route_frame()
> nr_loopback_queue()
> nr_loopback_timer()
> nr_rx_frame() // sk : socket_1's sk
> nr_process_rx_frame() // NR_STATE_3
> nr_state3_machine() // NR_DISCREQ
> nr_disconnect()
> nr_sk(sk)->state = NR_STATE_0;
> 6. close(socket_1) // sk refcount : 3
> nr_release() // NR_STATE_0
> sock_put(sk); // sk refcount : 0
> sk_free(sk);
> close(uaf_socket)
> nr_release()
> sock_hold(sk); // UAF
> ```
Ok, this looks good.
Please send v4 without my Reviewed-by tag.
Thank you.
>
> And sorry for sending the v3 netrom patch first.
> I received an email that the v2 x25 patch with the wrong patch
> description was applied to the tree,
> so I made a v3 x25 patch in a hurry and sent the netrom as well.
>
> >
> >
> > > 3. write(accepted_socket)
> > > nr_sendmsg()
> > > nr_output()
> > > nr_kick()
> > > nr_send_iframe()
> > > nr_transmit_buffer()
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_process_rx_frame(sk, skb); // sk : socket_1's sk
> > > nr_state3_machine()
> > > nr_queue_rx_frame()
> > > sock_queue_rcv_skb()
> > > sock_queue_rcv_skb_reason()
> > > __sock_queue_rcv_skb()
> > > __skb_queue_tail(list, skb); // list : socket_1's sk->sk_receive_queue
> > > 4. listen(socket_1)
> > > nr_listen()
> > > uaf_socket = accept(socket_1)
> > > nr_accept()
> > > skb_dequeue(&sk->sk_receive_queue);
> > > 5. close(accepted_socket)
> > > nr_release()
> > > nr_write_internal(sk, NR_DISCREQ)
> > > nr_transmit_buffer() // NR_DISCREQ
> > > nr_route_frame()
> > > nr_loopback_queue()
> > > nr_loopback_timer()
> > > nr_rx_frame() // sk : socket_1's sk
> > > nr_process_rx_frame() // NR_STATE_3
> > > nr_state3_machine() // NR_DISCREQ
> > > nr_disconnect()
> > > nr_sk(sk)->state = NR_STATE_0;
> > > 6. close(socket_1) // sk refcount : 3
> > > nr_release() // NR_STATE_0
> > > sock_put(sk); // sk refcount : 0
> > > sk_free(sk);
> > > close(uaf_socket)
> > > nr_release()
> > > sock_hold(sk); // UAF
> > > ```
> > >
> > > Anything wrong?
> > >
> > >
> > > >
> > > > > nr_release()
> > > > > nr_write_internal(sk, NR_DISCREQ)
> > > > > nr_transmit_buffer() // NR_DISCREQ
> > > > > nr_route_frame()
> > > > > nr_loopback_queue()
> > > > > nr_loopback_timer()
> > > > > nr_rx_frame() // sk : socket_1's sk
> > > > > nr_process_rx_frame() // NR_STATE_3
> > > > > nr_state3_machine() // NR_DISCREQ
> > > > > nr_disconnect()
> > > > > nr_sk(sk)->state = NR_STATE_0;
> > > > > 5. close(socket_1) // sk refcount : 3
> > > > > nr_release() // NR_STATE_0
> > > > > sock_put(sk); // sk refcount : 0
> > > > > sk_free(sk);
> > > > > close(uaf_socket)
> > > > > nr_release()
> > > > > sock_hold(sk); // UAF
> > > > > ```
> > > > >
> > > > > KASAN report by syzbot:
> > > > > ```
> > > > > BUG: KASAN: use-after-free in nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > > Write of size 4 at addr ffff8880235d8080 by task syz-executor564/5128
> > > > >
> > > > > Call Trace:
> > > > > <TASK>
> > > > > __dump_stack lib/dump_stack.c:88 [inline]
> > > > > dump_stack_lvl+0xd1/0x138 lib/dump_stack.c:106
> > > > > print_address_description mm/kasan/report.c:306 [inline]
> > > > > print_report+0x15e/0x461 mm/kasan/report.c:417
> > > > > kasan_report+0xbf/0x1f0 mm/kasan/report.c:517
> > > > > check_region_inline mm/kasan/generic.c:183 [inline]
> > > > > kasan_check_range+0x141/0x190 mm/kasan/generic.c:189
> > > > > instrument_atomic_read_write include/linux/instrumented.h:102 [inline]
> > > > > atomic_fetch_add_relaxed include/linux/atomic/atomic-instrumented.h:116 [inline]
> > > > > __refcount_add include/linux/refcount.h:193 [inline]
> > > > > __refcount_inc include/linux/refcount.h:250 [inline]
> > > > > refcount_inc include/linux/refcount.h:267 [inline]
> > > > > sock_hold include/net/sock.h:775 [inline]
> > > > > nr_release+0x66/0x460 net/netrom/af_netrom.c:520
> > > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > > RIP: 0033:0x7f6c19e3c9b9
> > > > > Code: Unable to access opcode bytes at 0x7f6c19e3c98f.
> > > > > RSP: 002b:00007fffd4ba2ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
> > > > > RAX: 0000000000000116 RBX: 0000000000000003 RCX: 00007f6c19e3c9b9
> > > > > RDX: 0000000000000318 RSI: 00000000200bd000 RDI: 0000000000000006
> > > > > RBP: 0000000000000003 R08: 000000000000000d R09: 000000000000000d
> > > > > R10: 0000000000000000 R11: 0000000000000246 R12: 000055555566a2c0
> > > > > R13: 0000000000000011 R14: 0000000000000000 R15: 0000000000000000
> > > > > </TASK>
> > > > >
> > > > > Allocated by task 5128:
> > > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > > ____kasan_kmalloc mm/kasan/common.c:371 [inline]
> > > > > ____kasan_kmalloc mm/kasan/common.c:330 [inline]
> > > > > __kasan_kmalloc+0xa3/0xb0 mm/kasan/common.c:380
> > > > > kasan_kmalloc include/linux/kasan.h:211 [inline]
> > > > > __do_kmalloc_node mm/slab_common.c:968 [inline]
> > > > > __kmalloc+0x5a/0xd0 mm/slab_common.c:981
> > > > > kmalloc include/linux/slab.h:584 [inline]
> > > > > sk_prot_alloc+0x140/0x290 net/core/sock.c:2038
> > > > > sk_alloc+0x3a/0x7a0 net/core/sock.c:2091
> > > > > nr_create+0xb6/0x5f0 net/netrom/af_netrom.c:433
> > > > > __sock_create+0x359/0x790 net/socket.c:1515
> > > > > sock_create net/socket.c:1566 [inline]
> > > > > __sys_socket_create net/socket.c:1603 [inline]
> > > > > __sys_socket_create net/socket.c:1588 [inline]
> > > > > __sys_socket+0x133/0x250 net/socket.c:1636
> > > > > __do_sys_socket net/socket.c:1649 [inline]
> > > > > __se_sys_socket net/socket.c:1647 [inline]
> > > > > __x64_sys_socket+0x73/0xb0 net/socket.c:1647
> > > > > do_syscall_x64 arch/x86/entry/common.c:50 [inline]
> > > > > do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > >
> > > > > Freed by task 5128:
> > > > > kasan_save_stack+0x22/0x40 mm/kasan/common.c:45
> > > > > kasan_set_track+0x25/0x30 mm/kasan/common.c:52
> > > > > kasan_save_free_info+0x2b/0x40 mm/kasan/generic.c:518
> > > > > ____kasan_slab_free mm/kasan/common.c:236 [inline]
> > > > > ____kasan_slab_free+0x13b/0x1a0 mm/kasan/common.c:200
> > > > > kasan_slab_free include/linux/kasan.h:177 [inline]
> > > > > __cache_free mm/slab.c:3394 [inline]
> > > > > __do_kmem_cache_free mm/slab.c:3580 [inline]
> > > > > __kmem_cache_free+0xcd/0x3b0 mm/slab.c:3587
> > > > > sk_prot_free net/core/sock.c:2074 [inline]
> > > > > __sk_destruct+0x5df/0x750 net/core/sock.c:2166
> > > > > sk_destruct net/core/sock.c:2181 [inline]
> > > > > __sk_free+0x175/0x460 net/core/sock.c:2192
> > > > > sk_free+0x7c/0xa0 net/core/sock.c:2203
> > > > > sock_put include/net/sock.h:1991 [inline]
> > > > > nr_release+0x39e/0x460 net/netrom/af_netrom.c:554
> > > > > __sock_release+0xcd/0x280 net/socket.c:650
> > > > > sock_close+0x1c/0x20 net/socket.c:1365
> > > > > __fput+0x27c/0xa90 fs/file_table.c:320
> > > > > task_work_run+0x16f/0x270 kernel/task_work.c:179
> > > > > exit_task_work include/linux/task_work.h:38 [inline]
> > > > > do_exit+0xaa8/0x2950 kernel/exit.c:867
> > > > > do_group_exit+0xd4/0x2a0 kernel/exit.c:1012
> > > > > get_signal+0x21c3/0x2450 kernel/signal.c:2859
> > > > > arch_do_signal_or_restart+0x79/0x5c0 arch/x86/kernel/signal.c:306
> > > > > exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
> > > > > exit_to_user_mode_prepare+0x15f/0x250 kernel/entry/common.c:203
> > > > > __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
> > > > > syscall_exit_to_user_mode+0x1d/0x50 kernel/entry/common.c:296
> > > > > do_syscall_64+0x46/0xb0 arch/x86/entry/common.c:86
> > > > > entry_SYSCALL_64_after_hwframe+0x63/0xcd
> > > > > ```
> > > > >
> > > > > To fix this problem, nr_listen() returns -EINVAL for sockets that successfully nr_connect().
> > > > >
> > > > > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> > > > > Reported-by: syzbot+caa188bdfc1eeafeb418@syzkaller.appspotmail.com
> > > > > Signed-off-by: Hyunwoo Kim <v4bel@theori.io>
> > > > > ---
> > > > > net/netrom/af_netrom.c | 5 +++++
> > > > > 1 file changed, 5 insertions(+)
> > > > >
> > > > > diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
> > > > > index 6f7f4392cffb..5a4cb796150f 100644
> > > > > --- a/net/netrom/af_netrom.c
> > > > > +++ b/net/netrom/af_netrom.c
> > > > > @@ -400,6 +400,11 @@ static int nr_listen(struct socket *sock, int backlog)
> > > > > struct sock *sk = sock->sk;
> > > > >
> > > > > lock_sock(sk);
> > > > > + if (sock->state != SS_UNCONNECTED) {
> > > > > + release_sock(sk);
> > > > > + return -EINVAL;
> > > > > + }
> > > > > +
> > > > > if (sk->sk_state != TCP_LISTEN) {
> > > > > memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
> > > > > sk->sk_max_ack_backlog = backlog;
> > > > > --
> > > > > 2.25.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* KERNEL BUG LIKELY: Kernel Panic! MKISS related
2023-01-26 17:34 ` Kuniyuki Iwashima
(?)
@ 2023-03-15 16:54 ` Chris Maness
2023-03-16 0:14 ` Kuniyuki Iwashima
-1 siblings, 1 reply; 12+ messages in thread
From: Chris Maness @ 2023-03-15 16:54 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: v4bel, davem, edumazet, imv4bel, kuba, linux-hams, netdev,
committer Paolo Abeni, ralf, syzbot+caa188bdfc1eeafeb418
I noticed this on two systems except I did not get the kernel dump
readout as X was running. I thought it may have had to do with
VirtualBox, but then I am getting similar behavior on a real install.
I was lucky that I did not have X running and have nice output that I
OCR'd from a photo of the screen.
How to reproduce this:
Setup 3 pseudo tty's for loopback to FBB BBS
kissnetd -p 3 &
kissattach /dev/pts/1
kissparms -c 1 -p lb0
kissattach /dev/pts/2
kissparms -c 1 -p lb1
fbb configured with a real radio on /dev/ttyS0 for port 1
and the lb0 AX.25 kernel interface for port 2.
I leave the third pseudo tty for connecting JNOS to FBB over this
"loopback" net.
If I try to pass bulls (or if I remember correctly even connect from
JNOS) it locks cold.
Last night (where this screen shot kernel panic came from) was an
actual radio port where I was pushing bulls to a newly installed
instance of FBB on Arch Linux with the latest kernel 6.2.5. I have
not had issues in slackware (and I was also running the latest stable
kernel as I am too lazy to keep patching the LTS kernel, but I have
not played as much there. I think I may install slack on this box too
and see if I can get it to dump like this. If you want the photo,
just email me directly as it looks like the OCR is not that good, but
I do not know how photos will go over here.
Here is the screen dump:
11 fm KOolIP: 1 to NoTJ-1 ctI DISC: 1100216.0098271 BUG: kernel MULL
[106216.0109741 #PF supervisor read access in kernel mode
1106216.0121001 APE: error codetox0000)
not present page
[106216.0132301 PCD 0 P4D 0
[106216.0143551 Dops: 0000 [#11 PREEMPT SMP PTI
[106216.0151781 CPU: 0 PID: 39178 Comm: xibbd Tainted: G
DE
6.2.5-arch1-1 #1 Fel?0e9497e04500
[106216.0166331 Hardware name: Dell Inc. Optifiex 790/ONKUGV, BIOS A17
03/14/2013
[106216.0177931 RIP: 0010 :ax25_addr_ax25dev+0x44/0xb0 [ax251
[106216.0189621 Code: c1 53 ed 9 b3 61 P9 48 86 14 40 16 01 00 48 85
db 74 41 41 bc 01 00 00 00 eb 08 48 Bb 16
0 03 00 00 eB do fb M Tr 85 co 75 e1 48 Ba bb 90 00 00°
[106216.0214491 RSP: 0018: Frffa52b0107bdeB EFLAGS: 00010286
[106216.022714] RAX: 0000000000000000 RBX: FIff9457c84126c0 RCX:
0000000000000000
[106216.023976] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI:
ffffa5260107be68
[106216.025229] RBP: ffFfa52b0107be68 ROB: 0000000000000009 R09:
0000000000000000
[106216.0264951 R10: 0000000000000000 R11: 0000000000000000 R12:
0000000000000001
[106216.0277661 R13: 0000000000000000 R14: 0000000000000000 R15:
0000000000000000
[106216.029015] FS:
00007/7421a26740 (0000) GS:ffff9458a9c00000 (0000) knIGS: 0000000000000000
[106216.0302591 CS:
0010 DS: 0000 ES: 0000 CRO: 0000000080050033
[106216.031589] CR2: 0000000000000340 CR3: 000000008c804005 CR4:
0000000000060650
[106216.0330441 Call Trace:
[106216.0337581 <TASK>
[106216.0344601 ax25_bind+0x1e2/0x210 [ax25
0149579197c9004716ce47844d0cb0c56b9a4c841
[106216.0351811
_sys_bind+Oxe8/OxfO
[106216.0358931
_x64_sus_bind+0x18/0×20
[106216.0365951
[106216.037296]
do_suscal1_64+0x5f/0×90
? syscall_exit_to_user_mode+0x1b/0×40
[106216.038000]
? do_syscal1_64+0x6b/0x90 [106216.0386931
entry_SYSCALL_64_after_huframe+0x72/0xdc
[106216.039390] RIP: 0033:0x717421b3791b
[106216.0400931 Code: c3 66 0f 1 44 00 00 48 86 15 51 e4 0c 00 f7 d8
64 89 02 b8 ff fr if ff eb be of 11 44 00 00. 13 of 1e fa b8 31 00 00
00 of 05 <48> 34 01 1
0 ff ff 73 01 c3 48 86 0d 25 e4 0c 00 f7 d8 64 89 01 48
[106216.041578] RSP: 0026:00007ffd15dab688 EFLAGS: 00000206 ORIG RAX:
0000000000000031
[106216.0423321 RAX: fffffffffffffrda RBX: 00007ffd15dabac2 RCX: 000077421b37916
[106216.043092] RDX: 0000000000000048 RSI: 00007ffd15dab700 RDI:
0000000000000009
[106216.043853] RBP: 0000563ef2403900 ROB: 0000000000000004 R09:
00000000ffffffff
[106216.0446231 R10: 00007rd15dab6c0 R11: 0000000000000206 R12: 0000000000000009
[106216.045395] R13: 0000000000000048 R14: 0000563ef2403c00 R15:
0000000000000010
[106216.0461671
</TASK>
[106216.0469201 Modules linked in: mkiss ax25 crc16 cp210x tun rperdma
rdma_cm iw_cm ib_cm ib_core ufat fat intel_rap _msr intel_rapl common
×86_pkg_temp_therma I intel powerc lamp coretemp kum_ intel kum
(rqbupass cret10dif pcimul cre32 pcimul polyual cimulni poluual
generic grizimul ghash cimulni intel crypta sha512 53s e3 snd Ida
_codec_hdmi snd hda_codec_-realtek snd _hda_codec generic rapl ledtrig
_audio mousedev snd hda_intel intel _cstate at24 snd_intel_dspefg
snd_intel_sdu acp i snd_hda_codec snd_hda_core snd_hudep snd_pem
mei_pxp 12c_1801 intel_uncore mei_hdep snd_timer iTCO_wt snd dedbas
intel_pc_bxt iTCO_uendor_support mei wat cf gBO211 rikill soundcore
pespr 12c _smblis mei me mel lpe_ich mac hid e1000e nfsd auth epcyss
nfs acl lockd grace sunrpe uboxnetfit (OF) Uboxmetadp(OF) uboxdru(OF»
dm _mod loop fuse bpf_preload ip_tables x tables btrfs blakeZb
_generic xor raid_pq liberc32c usbhid cre32c _generic 1915 drm_buddy
intel_gtt crc32c_intel drm_di splay_helper sr_mod cdrom cec ttm video
uni
[106216.0526781 CRZ: 0000000000000340
[106216.053515] ---[ end trace 0000000000000000 1-
[106216.0543461 RIP: 0010 :ax25_ addr_ax25deu+0x44/Oxb0 Lax25]
[106216.055173] Code: c1 53 8 9 63 61 9 48 86 1d 40 16 01 00 48 85 ab
74 4f 41 bc 01 00 00 00 eb 0B 48 8b 16 48 85 b 74 31 48 86 43 08 48.
89 ef <48> 86 60
0 03 00 00 e8 do fb fr ff 85 cO 75 e1 48 8d bb 90 00 00
[106216.056921] RSP: 0018:ffffa52b0107bded EFLAGS: 00010286
1106216.0578041 RAX: 0000000000000000 RBX: fFff9457c84126c0 RCX:
0000000000000000
[106216.058688] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI: ffffa520107be68
[106216.059577] RBP: ffffa52b0107be68 ROB: 0000000000000009 R09:
0000000000000000
[106216.060473] R10: 0000000000000000 R11: 0000000000000000 R12:
0000000000000001
[106216.0613741 R13: 0000000000000000 R14: 0000000000000000 R15:
0000000000000000
[106216.0622811 FS*
0000757421a26740 (0000) GS:ffFf9458a9c00000(0000) knIGS:0000000000000000
[106216.063200] C8:
0010 DS: 0000 ES: 0000 CRO: 0000000080050033
[106216.0641291 CR2: 0000000000000340 CR3: 000000008c804005 CR4: 000000000006060
[106216.0650721 Kernel panic - not syncing: Fatal exception in interrupt
[106216.0662201 Kernel Offset: 0x38e00000 from Oxffffffff81000000
(relocation range: Oxfffffff80000000-oxfrrrrrrrrrrrrr)
[106216.0672191
---[ end Kernel panic
- not syncing: Fatal exception in interrupt ]-.
Regards,
Chris KQ6UP
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: KERNEL BUG LIKELY: Kernel Panic! MKISS related
2023-03-15 16:54 ` KERNEL BUG LIKELY: Kernel Panic! MKISS related Chris Maness
@ 2023-03-16 0:14 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-03-16 0:14 UTC (permalink / raw)
To: christopher.maness
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418, v4bel
Hi,
From: Chris Maness <christopher.maness@gmail.com>
Date: Wed, 15 Mar 2023 09:54:03 -0700
> I noticed this on two systems except I did not get the kernel dump
> readout as X was running. I thought it may have had to do with
> VirtualBox, but then I am getting similar behavior on a real install.
> I was lucky that I did not have X running and have nice output that I
> OCR'd from a photo of the screen.
>
> How to reproduce this:
>
> Setup 3 pseudo tty's for loopback to FBB BBS
> kissnetd -p 3 &
> kissattach /dev/pts/1
> kissparms -c 1 -p lb0
> kissattach /dev/pts/2
> kissparms -c 1 -p lb1
> fbb configured with a real radio on /dev/ttyS0 for port 1
> and the lb0 AX.25 kernel interface for port 2.
>
> I leave the third pseudo tty for connecting JNOS to FBB over this
> "loopback" net.
>
> If I try to pass bulls (or if I remember correctly even connect from
> JNOS) it locks cold.
>
> Last night (where this screen shot kernel panic came from) was an
> actual radio port where I was pushing bulls to a newly installed
> instance of FBB on Arch Linux with the latest kernel 6.2.5. I have
> not had issues in slackware (and I was also running the latest stable
> kernel as I am too lazy to keep patching the LTS kernel, but I have
> not played as much there. I think I may install slack on this box too
> and see if I can get it to dump like this. If you want the photo,
> just email me directly as it looks like the OCR is not that good, but
> I do not know how photos will go over here.
>
> Here is the screen dump:
>
> 11 fm KOolIP: 1 to NoTJ-1 ctI DISC: 1100216.0098271 BUG: kernel MULL
>
> [106216.0109741 #PF supervisor read access in kernel mode
>
> 1106216.0121001 APE: error codetox0000)
>
> not present page
>
> [106216.0132301 PCD 0 P4D 0
>
> [106216.0143551 Dops: 0000 [#11 PREEMPT SMP PTI
>
> [106216.0151781 CPU: 0 PID: 39178 Comm: xibbd Tainted: G
>
> DE
>
> 6.2.5-arch1-1 #1 Fel?0e9497e04500
>
> [106216.0166331 Hardware name: Dell Inc. Optifiex 790/ONKUGV, BIOS A17
> 03/14/2013
>
> [106216.0177931 RIP: 0010 :ax25_addr_ax25dev+0x44/0xb0 [ax251
>
> [106216.0189621 Code: c1 53 ed 9 b3 61 P9 48 86 14 40 16 01 00 48 85
> db 74 41 41 bc 01 00 00 00 eb 08 48 Bb 16
>
> 0 03 00 00 eB do fb M Tr 85 co 75 e1 48 Ba bb 90 00 00=C2=B0
>
> [106216.0214491 RSP: 0018: Frffa52b0107bdeB EFLAGS: 00010286
>
> [106216.022714] RAX: 0000000000000000 RBX: FIff9457c84126c0 RCX:
> 0000000000000000
>
> [106216.023976] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI:
> ffffa5260107be68
>
> [106216.025229] RBP: ffFfa52b0107be68 ROB: 0000000000000009 R09:
> 0000000000000000
>
> [106216.0264951 R10: 0000000000000000 R11: 0000000000000000 R12:
> 0000000000000001
>
> [106216.0277661 R13: 0000000000000000 R14: 0000000000000000 R15:
> 0000000000000000
>
> [106216.029015] FS:
>
> 00007/7421a26740 (0000) GS:ffff9458a9c00000 (0000) knIGS: 0000000000000000
>
> [106216.0302591 CS:
>
> 0010 DS: 0000 ES: 0000 CRO: 0000000080050033
>
> [106216.031589] CR2: 0000000000000340 CR3: 000000008c804005 CR4:
> 0000000000060650
>
> [106216.0330441 Call Trace:
>
> [106216.0337581 <TASK>
>
> [106216.0344601 ax25_bind+0x1e2/0x210 [ax25
> 0149579197c9004716ce47844d0cb0c56b9a4c841
It seems to be a new null-deref ?
I think at least this patch is not related to the issue and same
for other patches from Hyunwoom. All of these commits did not
touch ax25.
611792920925 ("netrom: Fix use-after-free caused by accept on already connected socket")
f2b0b5210f67 ("net/x25: Fix to not accept on connected socket")
14caefcf9837 ("net/rose: Fix to not accept on connected socket")
Thanks,
Kuniyuki
>
> [106216.0351811
>
> _sys_bind+Oxe8/OxfO
>
> [106216.0358931
>
> _x64_sus_bind+0x18/0=C3=9720
>
> [106216.0365951
>
> [106216.037296]
>
> do_suscal1_64+0x5f/0=C3=9790
>
> ? syscall_exit_to_user_mode+0x1b/0=C3=9740
>
> [106216.038000]
>
> ? do_syscal1_64+0x6b/0x90 [106216.0386931
> entry_SYSCALL_64_after_huframe+0x72/0xdc
>
> [106216.039390] RIP: 0033:0x717421b3791b
>
> [106216.0400931 Code: c3 66 0f 1 44 00 00 48 86 15 51 e4 0c 00 f7 d8
> 64 89 02 b8 ff fr if ff eb be of 11 44 00 00. 13 of 1e fa b8 31 00 00
> 00 of 05 <48> 34 01 1
>
> 0 ff ff 73 01 c3 48 86 0d 25 e4 0c 00 f7 d8 64 89 01 48
>
> [106216.041578] RSP: 0026:00007ffd15dab688 EFLAGS: 00000206 ORIG RAX:
> 0000000000000031
>
> [106216.0423321 RAX: fffffffffffffrda RBX: 00007ffd15dabac2 RCX: 000077421b=
> 37916
>
> [106216.043092] RDX: 0000000000000048 RSI: 00007ffd15dab700 RDI:
> 0000000000000009
>
> [106216.043853] RBP: 0000563ef2403900 ROB: 0000000000000004 R09:
> 00000000ffffffff
>
> [106216.0446231 R10: 00007rd15dab6c0 R11: 0000000000000206 R12: 00000000000=
> 00009
>
> [106216.045395] R13: 0000000000000048 R14: 0000563ef2403c00 R15:
> 0000000000000010
>
> [106216.0461671
>
> </TASK>
>
> [106216.0469201 Modules linked in: mkiss ax25 crc16 cp210x tun rperdma
> rdma_cm iw_cm ib_cm ib_core ufat fat intel_rap _msr intel_rapl common
> =C3=9786_pkg_temp_therma I intel powerc lamp coretemp kum_ intel kum
> (rqbupass cret10dif pcimul cre32 pcimul polyual cimulni poluual
> generic grizimul ghash cimulni intel crypta sha512 53s e3 snd Ida
> _codec_hdmi snd hda_codec_-realtek snd _hda_codec generic rapl ledtrig
> _audio mousedev snd hda_intel intel _cstate at24 snd_intel_dspefg
> snd_intel_sdu acp i snd_hda_codec snd_hda_core snd_hudep snd_pem
> mei_pxp 12c_1801 intel_uncore mei_hdep snd_timer iTCO_wt snd dedbas
> intel_pc_bxt iTCO_uendor_support mei wat cf gBO211 rikill soundcore
> pespr 12c _smblis mei me mel lpe_ich mac hid e1000e nfsd auth epcyss
> nfs acl lockd grace sunrpe uboxnetfit (OF) Uboxmetadp(OF) uboxdru(OF=C2=BB
> dm _mod loop fuse bpf_preload ip_tables x tables btrfs blakeZb
> _generic xor raid_pq liberc32c usbhid cre32c _generic 1915 drm_buddy
> intel_gtt crc32c_intel drm_di splay_helper sr_mod cdrom cec ttm video
> uni
>
> [106216.0526781 CRZ: 0000000000000340
>
> [106216.053515] ---[ end trace 0000000000000000 1-
>
> [106216.0543461 RIP: 0010 :ax25_ addr_ax25deu+0x44/Oxb0 Lax25]
>
> [106216.055173] Code: c1 53 8 9 63 61 9 48 86 1d 40 16 01 00 48 85 ab
> 74 4f 41 bc 01 00 00 00 eb 0B 48 8b 16 48 85 b 74 31 48 86 43 08 48.
> 89 ef <48> 86 60
>
> 0 03 00 00 e8 do fb fr ff 85 cO 75 e1 48 8d bb 90 00 00
>
> [106216.056921] RSP: 0018:ffffa52b0107bded EFLAGS: 00010286
>
> 1106216.0578041 RAX: 0000000000000000 RBX: fFff9457c84126c0 RCX:
> 0000000000000000
>
> [106216.058688] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI: ffffa52010=
> 7be68
>
> [106216.059577] RBP: ffffa52b0107be68 ROB: 0000000000000009 R09:
> 0000000000000000
>
> [106216.060473] R10: 0000000000000000 R11: 0000000000000000 R12:
> 0000000000000001
>
> [106216.0613741 R13: 0000000000000000 R14: 0000000000000000 R15:
> 0000000000000000
>
> [106216.0622811 FS*
>
> 0000757421a26740 (0000) GS:ffFf9458a9c00000(0000) knIGS:0000000000000000
>
> [106216.063200] C8:
>
> 0010 DS: 0000 ES: 0000 CRO: 0000000080050033
>
> [106216.0641291 CR2: 0000000000000340 CR3: 000000008c804005 CR4: 0000000000=
> 06060
>
> [106216.0650721 Kernel panic - not syncing: Fatal exception in interrupt
>
> [106216.0662201 Kernel Offset: 0x38e00000 from Oxffffffff81000000
> (relocation range: Oxfffffff80000000-oxfrrrrrrrrrrrrr)
>
> [106216.0672191
>
> ---[ end Kernel panic
>
> - not syncing: Fatal exception in interrupt ]-.
>
> Regards,
> Chris KQ6UP
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: KERNEL BUG LIKELY: Kernel Panic! MKISS related
@ 2023-03-16 0:14 ` Kuniyuki Iwashima
0 siblings, 0 replies; 12+ messages in thread
From: Kuniyuki Iwashima @ 2023-03-16 0:14 UTC (permalink / raw)
To: christopher.maness
Cc: davem, edumazet, imv4bel, kuba, kuniyu, linux-hams, netdev,
pabeni, ralf, syzbot+caa188bdfc1eeafeb418, v4bel
Hi,
From: Chris Maness <christopher.maness@gmail.com>
Date: Wed, 15 Mar 2023 09:54:03 -0700
> I noticed this on two systems except I did not get the kernel dump
> readout as X was running. I thought it may have had to do with
> VirtualBox, but then I am getting similar behavior on a real install.
> I was lucky that I did not have X running and have nice output that I
> OCR'd from a photo of the screen.
>
> How to reproduce this:
>
> Setup 3 pseudo tty's for loopback to FBB BBS
> kissnetd -p 3 &
> kissattach /dev/pts/1
> kissparms -c 1 -p lb0
> kissattach /dev/pts/2
> kissparms -c 1 -p lb1
> fbb configured with a real radio on /dev/ttyS0 for port 1
> and the lb0 AX.25 kernel interface for port 2.
>
> I leave the third pseudo tty for connecting JNOS to FBB over this
> "loopback" net.
>
> If I try to pass bulls (or if I remember correctly even connect from
> JNOS) it locks cold.
>
> Last night (where this screen shot kernel panic came from) was an
> actual radio port where I was pushing bulls to a newly installed
> instance of FBB on Arch Linux with the latest kernel 6.2.5. I have
> not had issues in slackware (and I was also running the latest stable
> kernel as I am too lazy to keep patching the LTS kernel, but I have
> not played as much there. I think I may install slack on this box too
> and see if I can get it to dump like this. If you want the photo,
> just email me directly as it looks like the OCR is not that good, but
> I do not know how photos will go over here.
>
> Here is the screen dump:
>
> 11 fm KOolIP: 1 to NoTJ-1 ctI DISC: 1100216.0098271 BUG: kernel MULL
>
> [106216.0109741 #PF supervisor read access in kernel mode
>
> 1106216.0121001 APE: error codetox0000)
>
> not present page
>
> [106216.0132301 PCD 0 P4D 0
>
> [106216.0143551 Dops: 0000 [#11 PREEMPT SMP PTI
>
> [106216.0151781 CPU: 0 PID: 39178 Comm: xibbd Tainted: G
>
> DE
>
> 6.2.5-arch1-1 #1 Fel?0e9497e04500
>
> [106216.0166331 Hardware name: Dell Inc. Optifiex 790/ONKUGV, BIOS A17
> 03/14/2013
>
> [106216.0177931 RIP: 0010 :ax25_addr_ax25dev+0x44/0xb0 [ax251
>
> [106216.0189621 Code: c1 53 ed 9 b3 61 P9 48 86 14 40 16 01 00 48 85
> db 74 41 41 bc 01 00 00 00 eb 08 48 Bb 16
>
> 0 03 00 00 eB do fb M Tr 85 co 75 e1 48 Ba bb 90 00 00=C2=B0
>
> [106216.0214491 RSP: 0018: Frffa52b0107bdeB EFLAGS: 00010286
>
> [106216.022714] RAX: 0000000000000000 RBX: FIff9457c84126c0 RCX:
> 0000000000000000
>
> [106216.023976] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI:
> ffffa5260107be68
>
> [106216.025229] RBP: ffFfa52b0107be68 ROB: 0000000000000009 R09:
> 0000000000000000
>
> [106216.0264951 R10: 0000000000000000 R11: 0000000000000000 R12:
> 0000000000000001
>
> [106216.0277661 R13: 0000000000000000 R14: 0000000000000000 R15:
> 0000000000000000
>
> [106216.029015] FS:
>
> 00007/7421a26740 (0000) GS:ffff9458a9c00000 (0000) knIGS: 0000000000000000
>
> [106216.0302591 CS:
>
> 0010 DS: 0000 ES: 0000 CRO: 0000000080050033
>
> [106216.031589] CR2: 0000000000000340 CR3: 000000008c804005 CR4:
> 0000000000060650
>
> [106216.0330441 Call Trace:
>
> [106216.0337581 <TASK>
>
> [106216.0344601 ax25_bind+0x1e2/0x210 [ax25
> 0149579197c9004716ce47844d0cb0c56b9a4c841
It seems to be a new null-deref ?
I think at least this patch is not related to the issue and same
for other patches from Hyunwoom. All of these commits did not
touch ax25.
611792920925 ("netrom: Fix use-after-free caused by accept on already connected socket")
f2b0b5210f67 ("net/x25: Fix to not accept on connected socket")
14caefcf9837 ("net/rose: Fix to not accept on connected socket")
Thanks,
Kuniyuki
>
> [106216.0351811
>
> _sys_bind+Oxe8/OxfO
>
> [106216.0358931
>
> _x64_sus_bind+0x18/0=C3=9720
>
> [106216.0365951
>
> [106216.037296]
>
> do_suscal1_64+0x5f/0=C3=9790
>
> ? syscall_exit_to_user_mode+0x1b/0=C3=9740
>
> [106216.038000]
>
> ? do_syscal1_64+0x6b/0x90 [106216.0386931
> entry_SYSCALL_64_after_huframe+0x72/0xdc
>
> [106216.039390] RIP: 0033:0x717421b3791b
>
> [106216.0400931 Code: c3 66 0f 1 44 00 00 48 86 15 51 e4 0c 00 f7 d8
> 64 89 02 b8 ff fr if ff eb be of 11 44 00 00. 13 of 1e fa b8 31 00 00
> 00 of 05 <48> 34 01 1
>
> 0 ff ff 73 01 c3 48 86 0d 25 e4 0c 00 f7 d8 64 89 01 48
>
> [106216.041578] RSP: 0026:00007ffd15dab688 EFLAGS: 00000206 ORIG RAX:
> 0000000000000031
>
> [106216.0423321 RAX: fffffffffffffrda RBX: 00007ffd15dabac2 RCX: 000077421b=
> 37916
>
> [106216.043092] RDX: 0000000000000048 RSI: 00007ffd15dab700 RDI:
> 0000000000000009
>
> [106216.043853] RBP: 0000563ef2403900 ROB: 0000000000000004 R09:
> 00000000ffffffff
>
> [106216.0446231 R10: 00007rd15dab6c0 R11: 0000000000000206 R12: 00000000000=
> 00009
>
> [106216.045395] R13: 0000000000000048 R14: 0000563ef2403c00 R15:
> 0000000000000010
>
> [106216.0461671
>
> </TASK>
>
> [106216.0469201 Modules linked in: mkiss ax25 crc16 cp210x tun rperdma
> rdma_cm iw_cm ib_cm ib_core ufat fat intel_rap _msr intel_rapl common
> =C3=9786_pkg_temp_therma I intel powerc lamp coretemp kum_ intel kum
> (rqbupass cret10dif pcimul cre32 pcimul polyual cimulni poluual
> generic grizimul ghash cimulni intel crypta sha512 53s e3 snd Ida
> _codec_hdmi snd hda_codec_-realtek snd _hda_codec generic rapl ledtrig
> _audio mousedev snd hda_intel intel _cstate at24 snd_intel_dspefg
> snd_intel_sdu acp i snd_hda_codec snd_hda_core snd_hudep snd_pem
> mei_pxp 12c_1801 intel_uncore mei_hdep snd_timer iTCO_wt snd dedbas
> intel_pc_bxt iTCO_uendor_support mei wat cf gBO211 rikill soundcore
> pespr 12c _smblis mei me mel lpe_ich mac hid e1000e nfsd auth epcyss
> nfs acl lockd grace sunrpe uboxnetfit (OF) Uboxmetadp(OF) uboxdru(OF=C2=BB
> dm _mod loop fuse bpf_preload ip_tables x tables btrfs blakeZb
> _generic xor raid_pq liberc32c usbhid cre32c _generic 1915 drm_buddy
> intel_gtt crc32c_intel drm_di splay_helper sr_mod cdrom cec ttm video
> uni
>
> [106216.0526781 CRZ: 0000000000000340
>
> [106216.053515] ---[ end trace 0000000000000000 1-
>
> [106216.0543461 RIP: 0010 :ax25_ addr_ax25deu+0x44/Oxb0 Lax25]
>
> [106216.055173] Code: c1 53 8 9 63 61 9 48 86 1d 40 16 01 00 48 85 ab
> 74 4f 41 bc 01 00 00 00 eb 0B 48 8b 16 48 85 b 74 31 48 86 43 08 48.
> 89 ef <48> 86 60
>
> 0 03 00 00 e8 do fb fr ff 85 cO 75 e1 48 8d bb 90 00 00
>
> [106216.056921] RSP: 0018:ffffa52b0107bded EFLAGS: 00010286
>
> 1106216.0578041 RAX: 0000000000000000 RBX: fFff9457c84126c0 RCX:
> 0000000000000000
>
> [106216.058688] RDX: 0000000000000001 RSI: ffffffffc1541100 RDI: ffffa52010=
> 7be68
>
> [106216.059577] RBP: ffffa52b0107be68 ROB: 0000000000000009 R09:
> 0000000000000000
>
> [106216.060473] R10: 0000000000000000 R11: 0000000000000000 R12:
> 0000000000000001
>
> [106216.0613741 R13: 0000000000000000 R14: 0000000000000000 R15:
> 0000000000000000
>
> [106216.0622811 FS*
>
> 0000757421a26740 (0000) GS:ffFf9458a9c00000(0000) knIGS:0000000000000000
>
> [106216.063200] C8:
>
> 0010 DS: 0000 ES: 0000 CRO: 0000000080050033
>
> [106216.0641291 CR2: 0000000000000340 CR3: 000000008c804005 CR4: 0000000000=
> 06060
>
> [106216.0650721 Kernel panic - not syncing: Fatal exception in interrupt
>
> [106216.0662201 Kernel Offset: 0x38e00000 from Oxffffffff81000000
> (relocation range: Oxfffffff80000000-oxfrrrrrrrrrrrrr)
>
> [106216.0672191
>
> ---[ end Kernel panic
>
> - not syncing: Fatal exception in interrupt ]-.
>
> Regards,
> Chris KQ6UP
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2023-03-16 0:15 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-23 17:22 [PATCH v2] netrom: Fix use-after-free caused by accept on already connected socket Hyunwoo Kim
2023-01-25 1:43 ` Kuniyuki Iwashima
2023-01-25 1:43 ` Kuniyuki Iwashima
2023-01-25 9:17 ` Hyunwoo Kim
2023-01-25 16:40 ` Kuniyuki Iwashima
2023-01-25 16:40 ` Kuniyuki Iwashima
2023-01-26 4:16 ` Hyunwoo Kim
2023-01-26 17:34 ` Kuniyuki Iwashima
2023-01-26 17:34 ` Kuniyuki Iwashima
2023-03-15 16:54 ` KERNEL BUG LIKELY: Kernel Panic! MKISS related Chris Maness
2023-03-16 0:14 ` Kuniyuki Iwashima
2023-03-16 0:14 ` Kuniyuki Iwashima
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.