From: Greg Kroah-Hartman Date: Tue, 8 Oct 2024 10:44:34 +0000 (+0200) Subject: 6.10-stable patches X-Git-Tag: v6.6.55~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b2bfcc7de7aa60c713040336e5200ae0484368e8;p=thirdparty%2Fkernel%2Fstable-queue.git 6.10-stable patches added patches: rxrpc-fix-a-race-between-socket-set-up-and-i-o-thread-creation.patch vhost-scsi-null-ptr-dereference-in-vhost_scsi_get_req.patch --- diff --git a/queue-6.10/rxrpc-fix-a-race-between-socket-set-up-and-i-o-thread-creation.patch b/queue-6.10/rxrpc-fix-a-race-between-socket-set-up-and-i-o-thread-creation.patch new file mode 100644 index 00000000000..720653f2ae7 --- /dev/null +++ b/queue-6.10/rxrpc-fix-a-race-between-socket-set-up-and-i-o-thread-creation.patch @@ -0,0 +1,97 @@ +From bc212465326e8587325f520a052346f0b57360e6 Mon Sep 17 00:00:00 2001 +From: David Howells +Date: Tue, 1 Oct 2024 14:26:58 +0100 +Subject: rxrpc: Fix a race between socket set up and I/O thread creation + +From: David Howells + +commit bc212465326e8587325f520a052346f0b57360e6 upstream. + +In rxrpc_open_socket(), it sets up the socket and then sets up the I/O +thread that will handle it. This is a problem, however, as there's a gap +between the two phases in which a packet may come into rxrpc_encap_rcv() +from the UDP packet but we oops when trying to wake the not-yet created I/O +thread. + +As a quick fix, just make rxrpc_encap_rcv() discard the packet if there's +no I/O thread yet. + +A better, but more intrusive fix would perhaps be to rearrange things such +that the socket creation is done by the I/O thread. + +Fixes: a275da62e8c1 ("rxrpc: Create a per-local endpoint receive queue and I/O thread") +Signed-off-by: David Howells +cc: yuxuanzhe@outlook.com +cc: Marc Dionne +cc: Simon Horman +cc: linux-afs@lists.infradead.org +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20241001132702.3122709-2-dhowells@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/rxrpc/ar-internal.h | 2 +- + net/rxrpc/io_thread.c | 10 ++++++++-- + net/rxrpc/local_object.c | 2 +- + 3 files changed, 10 insertions(+), 4 deletions(-) + +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -1058,7 +1058,7 @@ bool rxrpc_direct_abort(struct sk_buff * + int rxrpc_io_thread(void *data); + static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local) + { +- wake_up_process(local->io_thread); ++ wake_up_process(READ_ONCE(local->io_thread)); + } + + static inline bool rxrpc_protocol_error(struct sk_buff *skb, enum rxrpc_abort_reason why) +--- a/net/rxrpc/io_thread.c ++++ b/net/rxrpc/io_thread.c +@@ -27,11 +27,17 @@ int rxrpc_encap_rcv(struct sock *udp_sk, + { + struct sk_buff_head *rx_queue; + struct rxrpc_local *local = rcu_dereference_sk_user_data(udp_sk); ++ struct task_struct *io_thread; + + if (unlikely(!local)) { + kfree_skb(skb); + return 0; + } ++ io_thread = READ_ONCE(local->io_thread); ++ if (!io_thread) { ++ kfree_skb(skb); ++ return 0; ++ } + if (skb->tstamp == 0) + skb->tstamp = ktime_get_real(); + +@@ -47,7 +53,7 @@ int rxrpc_encap_rcv(struct sock *udp_sk, + #endif + + skb_queue_tail(rx_queue, skb); +- rxrpc_wake_up_io_thread(local); ++ wake_up_process(io_thread); + return 0; + } + +@@ -565,7 +571,7 @@ int rxrpc_io_thread(void *data) + __set_current_state(TASK_RUNNING); + rxrpc_see_local(local, rxrpc_local_stop); + rxrpc_destroy_local(local); +- local->io_thread = NULL; ++ WRITE_ONCE(local->io_thread, NULL); + rxrpc_see_local(local, rxrpc_local_stopped); + return 0; + } +--- a/net/rxrpc/local_object.c ++++ b/net/rxrpc/local_object.c +@@ -232,7 +232,7 @@ static int rxrpc_open_socket(struct rxrp + } + + wait_for_completion(&local->io_thread_ready); +- local->io_thread = io_thread; ++ WRITE_ONCE(local->io_thread, io_thread); + _leave(" = 0"); + return 0; + diff --git a/queue-6.10/series b/queue-6.10/series index 488fc0bcc4c..239431d9fbe 100644 --- a/queue-6.10/series +++ b/queue-6.10/series @@ -473,3 +473,5 @@ acpi-battery-fix-possible-crash-when-unregistering-a.patch drm-rockchip-vop-enable-vop_feature_internal_rgb-on-rk3066.patch revert-drm-amd-display-skip-recompute-dsc-params-if-no-stream-on-link.patch drm-sched-revert-always-increment-correct-scheduler-score.patch +rxrpc-fix-a-race-between-socket-set-up-and-i-o-thread-creation.patch +vhost-scsi-null-ptr-dereference-in-vhost_scsi_get_req.patch diff --git a/queue-6.10/vhost-scsi-null-ptr-dereference-in-vhost_scsi_get_req.patch b/queue-6.10/vhost-scsi-null-ptr-dereference-in-vhost_scsi_get_req.patch new file mode 100644 index 00000000000..eca28c5b4a8 --- /dev/null +++ b/queue-6.10/vhost-scsi-null-ptr-dereference-in-vhost_scsi_get_req.patch @@ -0,0 +1,115 @@ +From 221af82f606d928ccef19a16d35633c63026f1be Mon Sep 17 00:00:00 2001 +From: Haoran Zhang +Date: Tue, 1 Oct 2024 15:14:15 -0500 +Subject: vhost/scsi: null-ptr-dereference in vhost_scsi_get_req() + +From: Haoran Zhang + +commit 221af82f606d928ccef19a16d35633c63026f1be upstream. + +Since commit 3f8ca2e115e5 ("vhost/scsi: Extract common handling code +from control queue handler") a null pointer dereference bug can be +triggered when guest sends an SCSI AN request. + +In vhost_scsi_ctl_handle_vq(), `vc.target` is assigned with +`&v_req.tmf.lun[1]` within a switch-case block and is then passed to +vhost_scsi_get_req() which extracts `vc->req` and `tpg`. However, for +a `VIRTIO_SCSI_T_AN_*` request, tpg is not required, so `vc.target` is +set to NULL in this branch. Later, in vhost_scsi_get_req(), +`vc->target` is dereferenced without being checked, leading to a null +pointer dereference bug. This bug can be triggered from guest. + +When this bug occurs, the vhost_worker process is killed while holding +`vq->mutex` and the corresponding tpg will remain occupied +indefinitely. + +Below is the KASAN report: +Oops: general protection fault, probably for non-canonical address +0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI +KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] +CPU: 1 PID: 840 Comm: poc Not tainted 6.10.0+ #1 +Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS +1.16.3-debian-1.16.3-2 04/01/2014 +RIP: 0010:vhost_scsi_get_req+0x165/0x3a0 +Code: 00 fc ff df 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 2b 02 00 00 +48 b8 00 00 00 00 00 fc ff df 4d 8b 65 30 4c 89 e2 48 c1 ea 03 <0f> b6 +04 02 4c 89 e2 83 e2 07 38 d0 7f 08 84 c0 0f 85 be 01 00 00 +RSP: 0018:ffff888017affb50 EFLAGS: 00010246 +RAX: dffffc0000000000 RBX: ffff88801b000000 RCX: 0000000000000000 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff888017affcb8 +RBP: ffff888017affb80 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 +R13: ffff888017affc88 R14: ffff888017affd1c R15: ffff888017993000 +FS: 000055556e076500(0000) GS:ffff88806b100000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00000000200027c0 CR3: 0000000010ed0004 CR4: 0000000000370ef0 +Call Trace: + + ? show_regs+0x86/0xa0 + ? die_addr+0x4b/0xd0 + ? exc_general_protection+0x163/0x260 + ? asm_exc_general_protection+0x27/0x30 + ? vhost_scsi_get_req+0x165/0x3a0 + vhost_scsi_ctl_handle_vq+0x2a4/0xca0 + ? __pfx_vhost_scsi_ctl_handle_vq+0x10/0x10 + ? __switch_to+0x721/0xeb0 + ? __schedule+0xda5/0x5710 + ? __kasan_check_write+0x14/0x30 + ? _raw_spin_lock+0x82/0xf0 + vhost_scsi_ctl_handle_kick+0x52/0x90 + vhost_run_work_list+0x134/0x1b0 + vhost_task_fn+0x121/0x350 +... + +---[ end trace 0000000000000000 ]--- + +Let's add a check in vhost_scsi_get_req. + +Fixes: 3f8ca2e115e5 ("vhost/scsi: Extract common handling code from control queue handler") +Signed-off-by: Haoran Zhang +[whitespace fixes] +Signed-off-by: Mike Christie +Message-Id: +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/vhost/scsi.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +--- a/drivers/vhost/scsi.c ++++ b/drivers/vhost/scsi.c +@@ -1029,20 +1029,23 @@ vhost_scsi_get_req(struct vhost_virtqueu + /* virtio-scsi spec requires byte 0 of the lun to be 1 */ + vq_err(vq, "Illegal virtio-scsi lun: %u\n", *vc->lunp); + } else { +- struct vhost_scsi_tpg **vs_tpg, *tpg; ++ struct vhost_scsi_tpg **vs_tpg, *tpg = NULL; + +- vs_tpg = vhost_vq_get_backend(vq); /* validated at handler entry */ +- +- tpg = READ_ONCE(vs_tpg[*vc->target]); +- if (unlikely(!tpg)) { +- vq_err(vq, "Target 0x%x does not exist\n", *vc->target); +- } else { +- if (tpgp) +- *tpgp = tpg; +- ret = 0; ++ if (vc->target) { ++ /* validated at handler entry */ ++ vs_tpg = vhost_vq_get_backend(vq); ++ tpg = READ_ONCE(vs_tpg[*vc->target]); ++ if (unlikely(!tpg)) { ++ vq_err(vq, "Target 0x%x does not exist\n", *vc->target); ++ goto out; ++ } + } +- } + ++ if (tpgp) ++ *tpgp = tpg; ++ ret = 0; ++ } ++out: + return ret; + } +