mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Laurence Oberman <loberman@redhat.com>
To: Dingisoul <dingiso.kernel@gmail.com>
Cc: James.Bottomley@HansenPartnership.com,
	linux-kernel@vger.kernel.org,  linux-scsi@vger.kernel.org,
	mkp@kernel.org
Subject: Re: [BUG] scsi: st: use-after-free race between st_remove() and st_open()/scsi_tape_get()
Date: Tue, 13 Oct 2026 08:52:03 -0400	[thread overview]
Message-ID: <e5312492c3d90322f362b1b148f7dce4290c2ba1.camel@redhat.com> (raw)
In-Reply-To: <20261012201730.1853897-1-dingiso.kernel@gmail.com>

On Mon, 2026-10-12 at 16:17 -0400, Dingisoul wrote:
> Hi Laurence,
> 
> Adding you to Cc as requested. Quoting the original report below for
> reference; let me know if you'd like anything else re-tested.
> 
> Best,
> Dingisoul
> 
> > Hi Kernel Maintainers,
> > 
> > I hit the following report while testing current upstream kernel:
> > 
> > KASAN: slab-use-after-free in st_open
> > 
> > on commit: a90ee4305c4a (2026-10-06)
> > 
> > Root cause: st_remove() drops the device's last reference, and only
> > afterwards removes it from st_index_idr:
> > 
> >     static void st_remove(struct scsi_device *SDp)
> >     {
> >         struct device *dev = &SDp->sdev_gendev;
> >         struct scsi_tape *tpnt = dev_get_drvdata(dev);
> >         int index = tpnt->index;
> >         ...
> >         mutex_lock(&st_ref_mutex);
> >         kref_put(&tpnt->kref, scsi_tape_release);  /* may
> > kfree(tpnt) right here */
> >         mutex_unlock(&st_ref_mutex);
> >         spin_lock(&st_index_lock);
> >         idr_remove(&st_index_idr, index);          /* too late:
> > tpnt may already be freed */
> >         spin_unlock(&st_index_lock);
> >     }
> > 
> > Meanwhile scsi_tape_get() -- called from st_open() on every open of
> > a
> > tape device node -- looks the device up by the same index and takes
> > its
> > own reference:
> > 
> >     static struct scsi_tape *scsi_tape_get(int dev)
> >     {
> >         struct scsi_tape *STp = NULL;
> > 
> >         mutex_lock(&st_ref_mutex);
> >         spin_lock(&st_index_lock);
> > 
> >         STp = idr_find(&st_index_idr, dev);  /* can still find the
> > freed tpnt */
> >         if (!STp) goto out;
> > 
> >         kref_get(&STp->kref);                /* UAF write */
> >         ...
> >     }
> > 
> >     static int st_open(struct inode *inode, struct file *filp)
> >     {
> >         ...
> >         if (!(STp = scsi_tape_get(dev))) {
> >         ...
> > 
> > Between st_remove()'s mutex_unlock(&st_ref_mutex) and its own
> > spin_lock(&st_index_lock), tpnt is already freed but still
> > reachable
> > through st_index_idr. A concurrent st_open() racing in that window
> > takes
> > both locks in scsi_tape_get(), finds the stale idr entry, and calls
> > kref_get() on the freed tpnt.
> > 
> > We used scsi_debug (ptype=1, emulating a tape LUN) to avoid needing
> > real
> > tape hardware.
> > 
> > The reproducer and .config files are here.
> > https://gist.github.com/dingiso/b33f8c01a47bfcbb902d3f21a4877feb
> > 
> > I'm happy to test debug patches or provide additional information.
> > 
> > [   23.212502]
> > ==================================================================
> > [   23.212506] BUG: KASAN: slab-use-after-free in st_open
> > (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-
> > instrumented.h:252 ./include/linux/refcount.h:283
> > ./include/linux/refcount.h:366 ./include/linux/refcount.h:383
> > ./include/linux/kref.h:45 drivers/scsi/st.c:254
> > drivers/scsi/st.c:1291)
> > [   23.212537] Write of size 4 at addr ffff888009854a1c by task
> > repro/315
> > [   23.212541] 
> > [   23.212551] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX +
> > PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
> > [   23.212554] Call Trace:
> > [   23.212556]  <TASK>
> > [   23.212558]  dump_stack_lvl (lib/dump_stack.c:94
> > lib/dump_stack.c:120)
> > [   23.212566]  print_report (mm/kasan/report.c:378
> > mm/kasan/report.c:482)
> > [   23.212591]  kasan_report (mm/kasan/report.c:595)
> > [   23.212602]  kasan_check_range (mm/kasan/generic.c:186
> > mm/kasan/generic.c:200)
> > [   23.212607]  st_open (./include/linux/instrumented.h:112
> > ./include/linux/atomic/atomic-instrumented.h:252
> > ./include/linux/refcount.h:283 ./include/linux/refcount.h:366
> > ./include/linux/refcount.h:383 ./include/linux/kref.h:45
> > drivers/scsi/st.c:254 drivers/scsi/st.c:1291)
> > [   23.212623]  chrdev_open (fs/char_dev.c:411)
> > [   23.212645]  do_dentry_open (fs/open.c:996)
> > [   23.212651]  vfs_open (fs/open.c:1101)
> > [   23.212656]  path_openat (fs/namei.c:4837 fs/namei.c:5000)
> > [   23.212669]  do_file_open (fs/namei.c:5029)
> > [   23.212693]  do_sys_openat2 (fs/open.c:1417 (discriminator 1))
> > [   23.212702]  __x64_sys_openat (fs/open.c:1423 fs/open.c:1439
> > fs/open.c:1434 fs/open.c:1434)
> > [   23.212712]  do_syscall_64 (arch/x86/entry/syscall_64.c:61
> > arch/x86/entry/syscall_64.c:84)
> > [   23.212719]  entry_SYSCALL_64_after_hwframe
> > (arch/x86/entry/entry_64.S:121)
> > [   23.212755] 
> > [   23.212756] Allocated by task 325:
> > [   23.212758]  kasan_save_stack (mm/kasan/common.c:57)
> > [   23.212764]  kasan_save_track (mm/kasan/common.c:78)
> > [   23.212768]  __kasan_kmalloc (mm/kasan/common.c:409
> > mm/kasan/common.c:426)
> > [   23.212773]  __kmalloc_cache_noprof (./include/linux/kasan.h:263
> > mm/slub.c:5563)
> > [   23.212778]  st_probe (./include/linux/slab.h:991
> > ./include/linux/slab.h:1312 drivers/scsi/st.c:4376)
> > [   23.212783]  really_probe (drivers/base/dd.c:628
> > drivers/base/dd.c:706)
> > [   23.212788]  __driver_probe_device (drivers/base/dd.c:868)
> > [   23.212793]  driver_probe_device (drivers/base/dd.c:898)
> > [   23.212798]  __device_attach_driver (drivers/base/dd.c:1026)
> > [   23.212803]  bus_for_each_drv (drivers/base/bus.c:500)
> > [   23.212807]  __device_attach (drivers/base/dd.c:1098)
> > [   23.212811]  device_initial_probe (drivers/base/dd.c:1153)
> > [   23.212816]  bus_probe_device (drivers/base/bus.c:620)
> > [   23.212821]  device_add (drivers/base/core.c:3776)
> > [   23.212826]  scsi_sysfs_add_sdev
> > (drivers/scsi/scsi_sysfs.c:1427)
> > [   23.212830]  scsi_add_lun (drivers/scsi/scsi_scan.c:1138
> > (discriminator 1))
> > [   23.212834]  scsi_probe_and_add_lun
> > (drivers/scsi/scsi_scan.c:1311)
> > [   23.212838]  __scsi_scan_target (drivers/scsi/scsi_scan.c:1805)
> > [   23.212841]  scsi_scan_channel (drivers/scsi/scsi_scan.c:1895
> > drivers/scsi/scsi_scan.c:1870)
> > [   23.212845]  scsi_scan_host_selected
> > (drivers/scsi/scsi_scan.c:1924)
> > [   23.212849]  scsi_scan_host (drivers/scsi/scsi_scan.c:2089
> > drivers/scsi/scsi_scan.c:2077)
> > [   23.212852] sdebug_driver_probe (drivers/scsi/scsi_debug.c:9618)
> > scsi_debug
> > [   23.212875]  really_probe (drivers/base/dd.c:628
> > drivers/base/dd.c:706)
> > [   23.212879]  __driver_probe_device (drivers/base/dd.c:868)
> > [   23.212883]  driver_probe_device (drivers/base/dd.c:898)
> > [   23.212887]  __device_attach_driver (drivers/base/dd.c:1026)
> > [   23.212891]  bus_for_each_drv (drivers/base/bus.c:500)
> > [   23.212895]  __device_attach (drivers/base/dd.c:1098)
> > [   23.212900]  device_initial_probe (drivers/base/dd.c:1153)
> > [   23.212905]  bus_probe_device (drivers/base/bus.c:620)
> > [   23.212909]  device_add (drivers/base/core.c:3776)
> > [   23.212914] sdebug_add_host_helper
> > (drivers/scsi/scsi_debug.c:8843) scsi_debug
> > [   23.212937] add_host_store (drivers/scsi/scsi_debug.c:8878
> > drivers/scsi/scsi_debug.c:8105) scsi_debug
> > [   23.212954]  kernfs_fop_write_iter (fs/kernfs/file.c:345)
> > [   23.212960]  vfs_write (fs/read_write.c:595 fs/read_write.c:687)
> > [   23.212964]  ksys_write (fs/read_write.c:739)
> > [   23.212968]  do_syscall_64 (arch/x86/entry/syscall_64.c:61
> > arch/x86/entry/syscall_64.c:84)
> > [   23.212973]  entry_SYSCALL_64_after_hwframe
> > (arch/x86/entry/entry_64.S:121)
> > [   23.212977] 
> > [   23.212978] Freed by task 325:
> > [   23.212980]  kasan_save_stack (mm/kasan/common.c:57)
> > [   23.212984]  kasan_save_track (mm/kasan/common.c:78)
> > [   23.212989]  kasan_save_free_info (mm/kasan/generic.c:584)
> > [   23.212993]  __kasan_slab_free (mm/kasan/common.c:264
> > mm/kasan/common.c:296)
> > [   23.212997]  kfree (./include/linux/kasan.h:235 mm/slub.c:2748
> > mm/slub.c:6509 mm/slub.c:6802)
> > [   23.213000]  st_remove (./include/linux/kref.h:65
> > drivers/scsi/st.c:4512)
> > [   23.213004]  device_release_driver_internal
> > (drivers/base/dd.c:1349 drivers/base/dd.c:1372)
> > [   23.213009]  bus_remove_device (drivers/base/bus.c:664)
> > [   23.213014]  device_del (drivers/base/core.c:3965)
> > [   23.213018]  __scsi_remove_device
> > (drivers/scsi/scsi_sysfs.c:1499)
> > [   23.213021]  scsi_forget_host (drivers/scsi/scsi_scan.c:2115)
> > [   23.213025]  scsi_remove_host (drivers/scsi/hosts.c:182)
> > [   23.213031] sdebug_driver_remove
> > (drivers/scsi/scsi_debug.c:9631) scsi_debug
> > [   23.213052]  device_release_driver_internal
> > (drivers/base/dd.c:1349 drivers/base/dd.c:1372)
> > [   23.213057]  bus_remove_device (drivers/base/bus.c:664)
> > [   23.213061]  device_del (drivers/base/core.c:3965)
> > [   23.213065]  device_unregister (drivers/base/core.c:4006)
> > [   23.213070] sdebug_do_remove_host
> > (drivers/scsi/scsi_debug.c:8917) scsi_debug
> > [   23.213089] add_host_store (drivers/scsi/scsi_debug.c:8110)
> > scsi_debug
> > [   23.213109]  kernfs_fop_write_iter (fs/kernfs/file.c:345)
> > [   23.213113]  vfs_write (fs/read_write.c:595 fs/read_write.c:687)
> > [   23.213117]  ksys_write (fs/read_write.c:739)
> > [   23.213121]  do_syscall_64 (arch/x86/entry/syscall_64.c:61
> > arch/x86/entry/syscall_64.c:84)
> > [   23.213126]  entry_SYSCALL_64_after_hwframe
> > (arch/x86/entry/entry_64.S:121)
> > Best,
> > Dingisoul

Hello

Please try this patch, let me know if it fixes this and I will send a
follow up to finalize this fix.


diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index f1c3c49466..d5b90bd1c6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4509,11 +4509,11 @@ static void st_remove(struct scsi_device *SDp)
 	remove_cdevs(tpnt);
 
 	mutex_lock(&st_ref_mutex);
-	kref_put(&tpnt->kref, scsi_tape_release);
-	mutex_unlock(&st_ref_mutex);
 	spin_lock(&st_index_lock);
 	idr_remove(&st_index_idr, index);
 	spin_unlock(&st_index_lock);
+	kref_put(&tpnt->kref, scsi_tape_release);
+	mutex_unlock(&st_ref_mutex);
 }
 



  reply	other threads:[~2026-10-13 12:52 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-07 21:15 Dingisoul
2026-10-12 20:17 ` Dingisoul
2026-10-13 12:52   ` Laurence Oberman [this message]
2026-10-13 20:01     ` Dingisoul

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e5312492c3d90322f362b1b148f7dce4290c2ba1.camel@redhat.com \
    --to=loberman@redhat.com \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=dingiso.kernel@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=mkp@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®