All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frank Li <Frank.li@oss.nxp.com>
To: "Ziyou Wang (Lenovo)" <ziyou.dev@gmail.com>
Cc: Vinod Koul <vkoul@kernel.org>,
	Vinicius Costa Gomes <vinicius.gomes@intel.com>,
	Dave Jiang <dave.jiang@intel.com>, Frank Li <Frank.Li@kernel.org>,
	dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org,
	Adrian Huang <adrianhuang0701@gmail.com>
Subject: Re: [PATCH] dmaengine: idxd: Fix use-after-free in idxd_remove
Date: Fri, 30 Oct 2026 09:54:05 -0500	[thread overview]
Message-ID: <auSvjQ8JKZ1GKWVT@SMW015318> (raw)
In-Reply-To: <20260911065547.161522-1-ziyou.dev@gmail.com>

On Fri, Sep 11, 2026 at 02:55:47PM +0800, Ziyou Wang (Lenovo) wrote:
> [You don't often get email from ziyou.dev@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> When unbinding the idxd driver, the following call trace is observed:
>
>   general protection fault, probably for non-canonical address 0x18fc1d6937256657
>   CPU: 117 UID: 0 PID: 3396 Comm: python3 Tainted: G E 7.2.0-rc5-latest+ #11 PREEMPT(lazy)
>   Hardware name: Lenovo WenTian WR5220 G5, BIOS speb50m-2.54
>   RIP: 0010:__refill_objects_node+0x2da/0x5e0
>   Call Trace:
>    <TASK>
>    refill_objects+0x1ee/0x2e0
>    __pcs_replace_empty_main+0x1e1/0x330
>    __kmalloc_noprof+0x503/0x550
>    ext4_htree_store_dirent+0x34/0x110 [ext4]
>    htree_dirblock_to_tree+0x1a9/0x2c0 [ext4]
>    ext4_htree_fill_tree+0x246/0x3d0 [ext4]
>    ext4_readdir+0x863/0x9d0 [ext4]
>    iterate_dir+0xa6/0x260
>    __x64_sys_getdents64+0x76/0x130
>    do_syscall_64+0x98/0x620
>    entry_SYSCALL_64_after_hwframe+0x76/0x7e
>    </TASK>
>
> With the KASAN-enabled kernel, the kernel reports a use-after-free bug:
>
> idxd_unregister_devices() calls device_unregister(wq), which triggers
> the wq release callback and frees wq memory via kfree(). However,
> idxd->wqs[] array still holds the freed pointer. Later, when
> device_unregister(idxd) calls idxd_device_drv_remove(), it accesses
> wq->state through idxd->wqs[], resulting in use-after-free.
>
> The same issue exists for idxd->engines[] and idxd->groups[] arrays.
>
> KASAN report:
>
>   BUG: KASAN: slab-use-after-free in idxd_device_drv_remove+0xc1/0x100 [idxd]
>   Read of size 4 at addr ff1100038d296414 by task python3/3354
>   CPU: 20 UID: 0 PID: 3354 Comm: python3 Tainted: G E 7.2.0-rc5-debug+
>   Hardware name: Lenovo WenTian WR5220 G5, BIOS speb50m-2.54
>
>   Call Trace:
>     <TASK>
>     dump_stack_lvl+0x5b/0x80
>     print_report+0x153/0x4b5
>     kasan_report+0xbc/0xf0
>     idxd_device_drv_remove+0xc1/0x100 [idxd]
>     device_release_driver_internal+0x244/0x2e0
>     bus_remove_device+0x195/0x2b0
>     device_del+0x24b/0x540
>     device_unregister+0x17/0x80
>     idxd_remove+0x3f/0x120 [idxd]
>     pci_device_remove+0x6d/0xf0
>     device_release_driver_internal+0x244/0x2e0
>     unbind_store+0xae/0xb0
>     kernfs_fop_write_iter+0x205/0x2d0
>     vfs_write+0x3a9/0x6b0
>     ksys_write+0xc7/0x160
>     do_syscall_64+0x9c/0x620
>     entry_SYSCALL_64_after_hwframe+0x76/0x7e
>     </TASK>
>
>   Allocated by task 1219:
>     kasan_save_stack+0x20/0x40
>     kasan_save_track+0x14/0x30
>     __kasan_kmalloc+0x9a/0xb0
>     __kmalloc_cache_node_noprof+0x1c6/0x470
>     idxd_pci_probe_alloc+0x103f/0x2430 [idxd]
>     local_pci_probe+0x71/0xd0
>     local_pci_probe_callback+0x20/0x40
>     process_one_work+0x389/0x6a0
>     worker_thread+0x321+0x590
>     kthread+0x1b4/0x200
>     ret_from_fork+0x3bd/0x4d0
>     ret_from_fork_asm+0x1a/0x30
>
>   Freed by task 3354:
>     kasan_save_stack+0x20/0x40
>     kasan_save_track+0x14/0x30
>     kasan_save_free_info+0x3b/0x70
>     __kasan_slab_free+0x6b/0x90
>     kfree+0x1d4/0x520
>     device_release+0x77/0x120
>     kobject_put+0xdb/0x2a0
>     idxd_unregister_devices+0x5b/0x130 [idxd]
>     idxd_remove+0x2f/0x120 [idxd]
>     pci_device_remove+0x6d/0xf0
>     device_release_driver_internal+0x244/0x2e0
>     unbind_store+0xae/0xb0
>     kernfs_fop_write_iter+0x205/0x2d0
>     vfs_write+0x3a9/0x6b0
>     ksys_write+0xc7/0x160
>     do_syscall_64+0x9c/0x620
>     entry_SYSCALL_64_after_hwframe+0x76/0x7e

Can you trim dump to make commit message short.

>
> Fix by taking refs on wq/engine/group conf_dev in idxd_unregister_devices()
> before calling device_unregister(). This prevents their memory from being
> freed until after idxd_device_drv_remove() completes. Add idxd_put_devices()
> to release the refs after all cleanup activities are done.
>
> To reproduce:
>   cd dsa-perf-micros
>   ./scripts/setup_dsa.sh -d dsa0 -w 1 -m s -e 4
>   echo "0000:00:01.0" > /sys/bus/pci/drivers/idxd/unbind

This is typical unbind driver method. So needn't this paragraph.

Frank

>
> Fixes: 47c16ac27d4c ("dmaengine: idxd: fix idxd conf_dev 'struct device' lifetime")
> Suggested-by: Adrian Huang (Lenovo) <adrianhuang0701@gmail.com>
> Signed-off-by: Ziyou Wang (Lenovo) <ziyou.dev@gmail.com>
> ---
> Added a Suggested-by tag for Adrian, as he came up with the idea for this patch.
>
>  drivers/dma/idxd/init.c  | 15 +++++++++++++++
>  drivers/dma/idxd/sysfs.c |  8 ++++++++
>  2 files changed, 23 insertions(+)
>
> diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
> index 4b827a329756..212efbfebacc 100644
> --- a/drivers/dma/idxd/init.c
> +++ b/drivers/dma/idxd/init.c
> @@ -1263,6 +1263,20 @@ static void idxd_shutdown(struct pci_dev *pdev)
>         flush_workqueue(idxd->wq);
>  }
>
> +static void idxd_put_devices(struct idxd_device *idxd)
> +{
> +       int i;
> +
> +       for (i = 0; i < idxd->max_wqs; i++)
> +               put_device(wq_confdev(idxd->wqs[i]));
> +
> +       for (i = 0; i < idxd->max_engines; i++)
> +               put_device(engine_confdev(idxd->engines[i]));
> +
> +       for (i = 0; i < idxd->max_groups; i++)
> +               put_device(group_confdev(idxd->groups[i]));
> +}
> +
>  static void idxd_remove(struct pci_dev *pdev)
>  {
>         struct idxd_device *idxd = pci_get_drvdata(pdev);
> @@ -1284,6 +1298,7 @@ static void idxd_remove(struct pci_dev *pdev)
>         if (device_pasid_enabled(idxd))
>                 idxd_disable_system_pasid(idxd);
>         pci_iounmap(pdev, idxd->reg_base);
> +       idxd_put_devices(idxd);
>         put_device(idxd_confdev(idxd));
>         pci_disable_device(pdev);
>  }
> diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
> index 6d251095c350..eca96a4dcecd 100644
> --- a/drivers/dma/idxd/sysfs.c
> +++ b/drivers/dma/idxd/sysfs.c
> @@ -1988,21 +1988,29 @@ void idxd_unregister_devices(struct idxd_device *idxd)
>  {
>         int i;
>
> +       /*
> +        * Take a reference count to the idxd device to prevent the
> +        * corresponding idxd context from being freed, as the driver
> +        * still needs it for the remaining cleanup operations.
> +        */
>         for (i = 0; i < idxd->max_wqs; i++) {
>                 struct idxd_wq *wq = idxd->wqs[i];
>
> +               get_device(wq_confdev(wq));
>                 device_unregister(wq_confdev(wq));
>         }
>
>         for (i = 0; i < idxd->max_engines; i++) {
>                 struct idxd_engine *engine = idxd->engines[i];
>
> +               get_device(engine_confdev(engine));
>                 device_unregister(engine_confdev(engine));
>         }
>
>         for (i = 0; i < idxd->max_groups; i++) {
>                 struct idxd_group *group = idxd->groups[i];
>
> +               get_device(group_confdev(group));
>                 device_unregister(group_confdev(group));
>         }
>  }
> --
> 2.53.0
>

  parent reply	other threads:[~2026-10-30 14:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11  6:55 [PATCH] dmaengine: idxd: Fix use-after-free in idxd_remove Ziyou Wang (Lenovo)
2026-09-11  7:14 ` sashiko-bot
2026-10-30 14:54 ` Frank Li [this message]
     [not found] ` <CABBdrdLtTJL7-xgB4i=AvqBoBJfFzYvJe+gV+KyLz5=QjUWkCg@mail.gmail.com>
2026-10-31  0:13   ` Vinicius Costa Gomes

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=auSvjQ8JKZ1GKWVT@SMW015318 \
    --to=frank.li@oss.nxp.com \
    --cc=Frank.Li@kernel.org \
    --cc=adrianhuang0701@gmail.com \
    --cc=dave.jiang@intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=vinicius.gomes@intel.com \
    --cc=vkoul@kernel.org \
    --cc=ziyou.dev@gmail.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.