From 3f06e4098c103409dbbe70d3f89f7498b23cd30f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 29 Sep 2025 15:41:25 +0200 Subject: [PATCH] 5.15-stable patches added patches: af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch --- ...-leave-consecutive-consumed-oob-skbs.patch | 202 ++++++++++++++++++ queue-5.15/series | 1 + 2 files changed, 203 insertions(+) create mode 100644 queue-5.15/af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch diff --git a/queue-5.15/af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch b/queue-5.15/af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch new file mode 100644 index 0000000000..743592e5ec --- /dev/null +++ b/queue-5.15/af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch @@ -0,0 +1,202 @@ +From 32ca245464e1479bfea8592b9db227fdc1641705 Mon Sep 17 00:00:00 2001 +From: Kuniyuki Iwashima +Date: Wed, 18 Jun 2025 21:13:55 -0700 +Subject: af_unix: Don't leave consecutive consumed OOB skbs. + +From: Kuniyuki Iwashima + +commit 32ca245464e1479bfea8592b9db227fdc1641705 upstream. + +Jann Horn reported a use-after-free in unix_stream_read_generic(). + +The following sequences reproduce the issue: + + $ python3 + from socket import * + s1, s2 = socketpair(AF_UNIX, SOCK_STREAM) + s1.send(b'x', MSG_OOB) + s2.recv(1, MSG_OOB) # leave a consumed OOB skb + s1.send(b'y', MSG_OOB) + s2.recv(1, MSG_OOB) # leave a consumed OOB skb + s1.send(b'z', MSG_OOB) + s2.recv(1) # recv 'z' illegally + s2.recv(1, MSG_OOB) # access 'z' skb (use-after-free) + +Even though a user reads OOB data, the skb holding the data stays on +the recv queue to mark the OOB boundary and break the next recv(). + +After the last send() in the scenario above, the sk2's recv queue has +2 leading consumed OOB skbs and 1 real OOB skb. + +Then, the following happens during the next recv() without MSG_OOB + + 1. unix_stream_read_generic() peeks the first consumed OOB skb + 2. manage_oob() returns the next consumed OOB skb + 3. unix_stream_read_generic() fetches the next not-yet-consumed OOB skb + 4. unix_stream_read_generic() reads and frees the OOB skb + +, and the last recv(MSG_OOB) triggers KASAN splat. + +The 3. above occurs because of the SO_PEEK_OFF code, which does not +expect unix_skb_len(skb) to be 0, but this is true for such consumed +OOB skbs. + + while (skip >= unix_skb_len(skb)) { + skip -= unix_skb_len(skb); + skb = skb_peek_next(skb, &sk->sk_receive_queue); + ... + } + +In addition to this use-after-free, there is another issue that +ioctl(SIOCATMARK) does not function properly with consecutive consumed +OOB skbs. + +So, nothing good comes out of such a situation. + +Instead of complicating manage_oob(), ioctl() handling, and the next +ECONNRESET fix by introducing a loop for consecutive consumed OOB skbs, +let's not leave such consecutive OOB unnecessarily. + +Now, while receiving an OOB skb in unix_stream_recv_urg(), if its +previous skb is a consumed OOB skb, it is freed. + +[0]: +BUG: KASAN: slab-use-after-free in unix_stream_read_actor (net/unix/af_unix.c:3027) +Read of size 4 at addr ffff888106ef2904 by task python3/315 + +CPU: 2 UID: 0 PID: 315 Comm: python3 Not tainted 6.16.0-rc1-00407-gec315832f6f9 #8 PREEMPT(voluntary) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-4.fc42 04/01/2014 +Call Trace: + + dump_stack_lvl (lib/dump_stack.c:122) + print_report (mm/kasan/report.c:409 mm/kasan/report.c:521) + kasan_report (mm/kasan/report.c:636) + unix_stream_read_actor (net/unix/af_unix.c:3027) + unix_stream_read_generic (net/unix/af_unix.c:2708 net/unix/af_unix.c:2847) + unix_stream_recvmsg (net/unix/af_unix.c:3048) + sock_recvmsg (net/socket.c:1063 (discriminator 20) net/socket.c:1085 (discriminator 20)) + __sys_recvfrom (net/socket.c:2278) + __x64_sys_recvfrom (net/socket.c:2291 (discriminator 1) net/socket.c:2287 (discriminator 1) net/socket.c:2287 (discriminator 1)) + do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) +RIP: 0033:0x7f8911fcea06 +Code: 5d e8 41 8b 93 08 03 00 00 59 5e 48 83 f8 fc 75 19 83 e2 39 83 fa 08 75 11 e8 26 ff ff ff 66 0f 1f 44 00 00 48 8b 45 10 0f 05 <48> 8b 5d f8 c9 c3 0f 1f 40 00 f3 0f 1e fa 55 48 89 e5 48 83 ec 08 +RSP: 002b:00007fffdb0dccb0 EFLAGS: 00000202 ORIG_RAX: 000000000000002d +RAX: ffffffffffffffda RBX: 00007fffdb0dcdc8 RCX: 00007f8911fcea06 +RDX: 0000000000000001 RSI: 00007f8911a5e060 RDI: 0000000000000006 +RBP: 00007fffdb0dccd0 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000001 R11: 0000000000000202 R12: 00007f89119a7d20 +R13: ffffffffc4653600 R14: 0000000000000000 R15: 0000000000000000 + + +Allocated by task 315: + kasan_save_stack (mm/kasan/common.c:48) + kasan_save_track (mm/kasan/common.c:60 (discriminator 1) mm/kasan/common.c:69 (discriminator 1)) + __kasan_slab_alloc (mm/kasan/common.c:348) + kmem_cache_alloc_node_noprof (./include/linux/kasan.h:250 mm/slub.c:4148 mm/slub.c:4197 mm/slub.c:4249) + __alloc_skb (net/core/skbuff.c:660 (discriminator 4)) + alloc_skb_with_frags (./include/linux/skbuff.h:1336 net/core/skbuff.c:6668) + sock_alloc_send_pskb (net/core/sock.c:2993) + unix_stream_sendmsg (./include/net/sock.h:1847 net/unix/af_unix.c:2256 net/unix/af_unix.c:2418) + __sys_sendto (net/socket.c:712 (discriminator 20) net/socket.c:727 (discriminator 20) net/socket.c:2226 (discriminator 20)) + __x64_sys_sendto (net/socket.c:2233 (discriminator 1) net/socket.c:2229 (discriminator 1) net/socket.c:2229 (discriminator 1)) + do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +Freed by task 315: + kasan_save_stack (mm/kasan/common.c:48) + kasan_save_track (mm/kasan/common.c:60 (discriminator 1) mm/kasan/common.c:69 (discriminator 1)) + kasan_save_free_info (mm/kasan/generic.c:579 (discriminator 1)) + __kasan_slab_free (mm/kasan/common.c:271) + kmem_cache_free (mm/slub.c:4643 (discriminator 3) mm/slub.c:4745 (discriminator 3)) + unix_stream_read_generic (net/unix/af_unix.c:3010) + unix_stream_recvmsg (net/unix/af_unix.c:3048) + sock_recvmsg (net/socket.c:1063 (discriminator 20) net/socket.c:1085 (discriminator 20)) + __sys_recvfrom (net/socket.c:2278) + __x64_sys_recvfrom (net/socket.c:2291 (discriminator 1) net/socket.c:2287 (discriminator 1) net/socket.c:2287 (discriminator 1)) + do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1)) + entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) + +The buggy address belongs to the object at ffff888106ef28c0 + which belongs to the cache skbuff_head_cache of size 224 +The buggy address is located 68 bytes inside of + freed 224-byte region [ffff888106ef28c0, ffff888106ef29a0) + +The buggy address belongs to the physical page: +page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888106ef3cc0 pfn:0x106ef2 +head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0 +flags: 0x200000000000040(head|node=0|zone=2) +page_type: f5(slab) +raw: 0200000000000040 ffff8881001d28c0 ffffea000422fe00 0000000000000004 +raw: ffff888106ef3cc0 0000000080190010 00000000f5000000 0000000000000000 +head: 0200000000000040 ffff8881001d28c0 ffffea000422fe00 0000000000000004 +head: ffff888106ef3cc0 0000000080190010 00000000f5000000 0000000000000000 +head: 0200000000000001 ffffea00041bbc81 00000000ffffffff 00000000ffffffff +head: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff888106ef2800: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc + ffff888106ef2880: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb +>ffff888106ef2900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + ^ + ffff888106ef2980: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc + ffff888106ef2a00: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb + +Fixes: 314001f0bf92 ("af_unix: Add OOB support") +Reported-by: Jann Horn +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Jann Horn +Link: https://patch.msgid.link/20250619041457.1132791-2-kuni1840@gmail.com +Signed-off-by: Paolo Abeni +[Lee: Shifted hunk inside the if() statement and surrounded the else with {}'s) +Signed-off-by: Lee Jones +Signed-off-by: Greg Kroah-Hartman +--- + net/unix/af_unix.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -2504,11 +2504,11 @@ struct unix_stream_read_state { + #if IS_ENABLED(CONFIG_AF_UNIX_OOB) + static int unix_stream_recv_urg(struct unix_stream_read_state *state) + { ++ struct sk_buff *oob_skb, *read_skb = NULL; + struct socket *sock = state->socket; + struct sock *sk = sock->sk; + struct unix_sock *u = unix_sk(sk); + int chunk = 1; +- struct sk_buff *oob_skb; + + mutex_lock(&u->iolock); + unix_state_lock(sk); +@@ -2523,10 +2523,17 @@ static int unix_stream_recv_urg(struct u + + oob_skb = u->oob_skb; + +- if (!(state->flags & MSG_PEEK)) ++ if (!(state->flags & MSG_PEEK)) { + WRITE_ONCE(u->oob_skb, NULL); +- else ++ ++ if (oob_skb->prev != (struct sk_buff *)&sk->sk_receive_queue && ++ !unix_skb_len(oob_skb->prev)) { ++ read_skb = oob_skb->prev; ++ __skb_unlink(read_skb, &sk->sk_receive_queue); ++ } ++ } else { + skb_get(oob_skb); ++ } + + spin_unlock(&sk->sk_receive_queue.lock); + unix_state_unlock(sk); +@@ -2540,6 +2547,8 @@ static int unix_stream_recv_urg(struct u + + mutex_unlock(&u->iolock); + ++ consume_skb(read_skb); ++ + if (chunk < 0) + return -EFAULT; + diff --git a/queue-5.15/series b/queue-5.15/series index e77bd26a32..83205fa7f6 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -142,3 +142,4 @@ i40e-add-mask-to-apply-valid-bits-for-itr_idx.patch tracing-dynevent-add-a-missing-lockdown-check-on-dynevent.patch fbcon-fix-integer-overflow-in-fbcon_do_set_font.patch fbcon-fix-oob-access-in-font-allocation.patch +af_unix-don-t-leave-consecutive-consumed-oob-skbs.patch -- 2.47.3