Skip to contentSkip to conversation

netrom: Fix use-after-free caused by accept on already connected socket

PATCH Superseded Hyunwoo Kim 3 participants 8 messages Jan 23, 2023 – Mar 16, 2023

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 netrom: Fix use-after-free caused by accept on already connected socket

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#1 lore raw

Hi,

I think the diff looks good but changelog is not correct.

From:   Hyunwoo Kim <[email protected]>
Date:   Mon, 23 Jan 2023 09:22:33 -0800
Quoted 4 lines

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.

Quoted 3 lines

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

Quoted 5 lines

And here's where use-after-free
can happen through complex race conditions:
```
cpu0 cpu1
1. socket_2 = socket(AF_NETROM)

Quoted 8 lines

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.

Quoted 6 lines
            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 ?

Quoted 5 lines
            nr_state3_machine()
            nr_queue_rx_frame()
            sock_queue_rcv_skb()
            sock_queue_rcv_skb_reason()
            __sock_queue_rcv_skb()
Quoted 8 lines
            __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)

Quoted 152 lines

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#2 lore raw
Quoted 22 lines · Kuniyuki Iwashima

Hi,

I think the diff looks good but changelog is not correct.

From:   Hyunwoo Kim <[email protected]>
Date:   Mon, 23 Jan 2023 09:22:33 -0800
Quoted 4 lines

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.

Quoted 3 lines

This causes nr_accept() to allocate and return a sock with the sk of the parent AF_NETROM socket.

Quoted 7 lines

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.

Quoted 53 lines
Quoted 15 lines

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.

Quoted 6 lines
            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 ?

Quoted 5 lines
            nr_state3_machine()
            nr_queue_rx_frame()
            sock_queue_rcv_skb()
            sock_queue_rcv_skb_reason()
            __sock_queue_rcv_skb()
Quoted 8 lines
            __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)
Quoted 3 lines

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?

Quoted 153 lines
Quoted 153 lines

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#3 lore raw
From:   Hyunwoo Kim <[email protected]>
Date:   Wed, 25 Jan 2023 01:17:10 -0800
Quoted 91 lines · Kuniyuki Iwashima
Quoted 22 lines

Hi,

I think the diff looks good but changelog is not correct.

From:   Hyunwoo Kim <[email protected]>
Date:   Mon, 23 Jan 2023 09:22:33 -0800
Quoted 4 lines

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.

Quoted 3 lines

This causes nr_accept() to allocate and return a sock with the sk of the parent AF_NETROM socket.

Quoted 7 lines

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.

Quoted 53 lines
Quoted 15 lines

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.

Quoted 6 lines
            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 ?

Quoted 5 lines
            nr_state3_machine()
            nr_queue_rx_frame()
            sock_queue_rcv_skb()
            sock_queue_rcv_skb_reason()
            __sock_queue_rcv_skb()
Quoted 8 lines
            __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)
Quoted 3 lines

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)

Quoted 5 lines

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.

Quoted 1 line

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__).

Quoted 17 lines

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()
Quoted 8 lines
            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).

Quoted 198 lines
                                                               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?

Quoted 153 lines
Quoted 153 lines

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#4 lore raw
Quoted 99 lines · Kuniyuki Iwashima
From:   Hyunwoo Kim <[email protected]>
Date:   Wed, 25 Jan 2023 01:17:10 -0800
Quoted 91 lines · Kuniyuki Iwashima
Quoted 22 lines

Hi,

I think the diff looks good but changelog is not correct.

From:   Hyunwoo Kim <[email protected]>
Date:   Mon, 23 Jan 2023 09:22:33 -0800
Quoted 4 lines

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.

Quoted 3 lines

This causes nr_accept() to allocate and return a sock with the sk of the parent AF_NETROM socket.

Quoted 7 lines

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.

Quoted 53 lines
Quoted 15 lines

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.

Quoted 6 lines
            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 ?

Quoted 5 lines
            nr_state3_machine()
            nr_queue_rx_frame()
            sock_queue_rcv_skb()
            sock_queue_rcv_skb_reason()
            __sock_queue_rcv_skb()
Quoted 8 lines
            __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)
Quoted 3 lines

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)

Quoted 5 lines

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.

Quoted 8 lines

No, it's released by the heartbeat timer. The heartbeat timer finally calls nr_destroy_socket() as SOCK_DESTROY is flagged to the sk.

Quoted 1 line

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.

Quoted 28 lines
Quoted 19 lines

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()
Quoted 8 lines
            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;
Quoted 6 lines

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.

Quoted 200 lines
Quoted 200 lines

                                                               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?

Quoted 153 lines
Quoted 153 lines

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#5 lore raw
From:   Hyunwoo Kim <[email protected]>
Date:   Wed, 25 Jan 2023 20:16:36 -0800
Quoted 104 lines · Kuniyuki Iwashima
Quoted 103 lines
From:   Hyunwoo Kim <[email protected]>
Date:   Wed, 25 Jan 2023 01:17:10 -0800
Quoted 91 lines · Kuniyuki Iwashima
Quoted 22 lines

Hi,

I think the diff looks good but changelog is not correct.

From:   Hyunwoo Kim <[email protected]>
Date:   Mon, 23 Jan 2023 09:22:33 -0800
Quoted 4 lines

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.

Quoted 3 lines

This causes nr_accept() to allocate and return a sock with the sk of the parent AF_NETROM socket.

Quoted 7 lines

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.

Quoted 53 lines
Quoted 15 lines

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.

Quoted 6 lines
            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 ?

Quoted 5 lines
            nr_state3_machine()
            nr_queue_rx_frame()
            sock_queue_rcv_skb()
            sock_queue_rcv_skb_reason()
            __sock_queue_rcv_skb()
Quoted 8 lines
            __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)
Quoted 3 lines

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)

Quoted 5 lines

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.

Quoted 8 lines
Quoted 4 lines
Quoted 1 line

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 :/

Quoted 147 lines
```
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.

Quoted 28 lines
Quoted 19 lines

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()
Quoted 8 lines
            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;
Quoted 6 lines

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;
Quoted 8 lines
       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.

Quoted 206 lines

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.

Quoted 200 lines
Quoted 200 lines

                                                               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?

Quoted 153 lines
Quoted 153 lines

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 [email protected]
---
 net/netrom/af_netrom.c | 5 +++++
 1 file changed, 5 insertions(+)
net/netrom/af_netrom.c +5 -0
index 6f7f4392cffb..5a4cb796150f 100644
@@ -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;
Signature · 1 line
2.25.1
#6 lore raw

KERNEL BUG LIKELY: Kernel Panic! MKISS related

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

#7 lore raw

Re: KERNEL BUG LIKELY: Kernel Panic! MKISS related

Hi,

From:   Chris Maness <[email protected]>
Date:   Wed, 15 Mar 2023 09:54:03 -0700
Quoted 89 lines

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:
Quoted 8 lines

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

Quoted 122 lines

[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