dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Pavel Begunkov" <asml.silence@gmail.com>
Cc: media-ci@linuxtv.org, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v6 01/13] dma-buf: introduce initial file I/O infrastructure
Date: Mon, 21 Sep 2026 13:53:43 +0000	[thread overview]
Message-ID: <20260921135344.035B81F000FF@smtp.kernel.org> (raw)
In-Reply-To: <5490ee42c4452fd4198b245ead20fcf7438c066e.1789997898.git.asml.silence@gmail.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] dma-buf: TOCTOU race allows a stale map to escape concurrent invalidation
- [High] dma-buf: Use-After-Free of ctx in waitqueue due to race condition
- [High] dma-buf: GFP_KERNEL allocation performed while holding dmabuf->resv ww_mutex
- [Medium] dma-buf: Hardcoded kfree(map) restricts driver structure embedding
- [Medium] dma-buf: Memory leak of ctx and dmabuf reference on incomplete dev_ops error path
- [Medium] dma-buf: Memory leak of map structure and DMA mappings on min_seg_shift validation error
--

commit b9251fd88ee105b166b558434c10ce6e3b106691
Author: Pavel Begunkov <asml.silence@gmail.com>
Subject: dma-buf: introduce initial file I/O infrastructure

This commit adds basic building blocks serving as a glue and API between
drivers and upper layer subsystems providing the uAPI. It introduces
struct dma_buf_io_ctx and struct dma_buf_io_map, allowing dma-buf to be
natively used in the read-write / IO path.

> diff --git a/drivers/dma-buf/dma-buf-io.c b/drivers/dma-buf/dma-buf-io.c
> new file mode 100644
> index 0000000000000..8312637a299f6
> --- /dev/null
> +++ b/drivers/dma-buf/dma-buf-io.c
[ ... ]
> @@ -22,17 +22,17 @@ static void dma_buf_io_map_release_work(struct work_struct *work)
>  {
>  	struct dma_buf_io_map *map = container_of(work, struct dma_buf_io_map,
>  						  release_work);
>  	struct dma_buf_io_ctx *ctx = map->ctx;
>  	struct dma_buf *dmabuf = ctx->dmabuf;
>  
>  	dma_resv_lock(dmabuf->resv, NULL);
>  	ctx->dev_ops->unmap(ctx, map);
>  	dma_resv_unlock(dmabuf->resv);
>  
>  	percpu_ref_exit(&map->refs);
>  	kfree(map);

[Severity: Medium]
Since drivers allocate this map object (often embedding it in a larger
structure), does this unconditional kfree(map) restrict where drivers can
embed the structure?

If a driver needs to use vmalloc or embed the map at a non-zero offset,
this will cause a panic. Could a .free callback be provided for safe
lifecycle management?

>  
>  	atomic_dec(&ctx->all_maps);
>  	wake_up(&ctx->maps_wq);

[Severity: High]
Can this sequence lead to a use-after-free on ctx?

If atomic_dec(&ctx->all_maps) drops the count to 0, a concurrent thread
blocked in dma_buf_io_wait_maps() can wake up, return, and free the ctx via
dma_buf_io_ctx_release():

Thread 1 (waiter):
dma_buf_io_ctx_release()
  dma_buf_io_wait_maps()
    wait_event() unblocks since atomic_read(&ctx->all_maps) == 0.
  dma_buf_io_put_ctx() is called and frees ctx.

Thread 2 (worker here):
Proceeds to call wake_up(&ctx->maps_wq) on the now-freed ctx memory.

>  }
[ ... ]
> +int dma_buf_io_init_map(struct dma_buf_io_ctx *ctx, struct dma_buf_io_map *map,
> +			struct sg_table *sgt)
> +{
> +	unsigned seg_shift = ~0U;
> +	struct scatterlist *sg;
> +	unsigned long tmp;
> +	int ret;
> +
> +	for_each_sgtable_dma_sg(sgt, sg, tmp)
> +		seg_shift = min(seg_shift, __ffs(sg_dma_len(sg)));
> +
> +	ret = percpu_ref_init(&map->refs, dma_buf_io_map_refs_release, 0,
> +			      GFP_KERNEL);

[Severity: High]
Does this GFP_KERNEL allocation violate DMA-buf locking rules?

dma_buf_io_create_map() calls ctx->dev_ops->map(ctx) while holding the
dmabuf->resv ww_mutex. If the driver then calls dma_buf_io_init_map() under
this lock, the GFP_KERNEL allocation could deadlock if memory reclaim
attempts to acquire dma_resv locks.

> +	if (ret)
> +		return ret;
> +	map->min_seg_shift = seg_shift;
> +	map->ctx = ctx;
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(dma_buf_io_init_map, "DMA_BUF");
> +
> +struct dma_buf_io_map *dma_buf_io_create_map(struct dma_buf_io_ctx *ctx)
> +{
> +	struct dma_buf *dmabuf = ctx->dmabuf;
> +	struct dma_buf_io_map *map;
> +	long ret;
> +
> +	guard(mutex)(&ctx->map_create_mutex);
> +
> +	scoped_guard(mutex, &ctx->map_mutex) {
> +		if (ctx->maps_killed)
> +			return ERR_PTR(-ENOENT);
> +		/* recheck under the lock in case it has already been re-created */
> +		map = __dma_buf_io_get_map(ctx);
> +		if (map)
> +			return map;
> +	}
> +
> +	dma_buf_io_wait_active_maps(ctx);
> +
> +	ret = dma_resv_lock_interruptible(dmabuf->resv, NULL);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	ret = dma_resv_wait_timeout(dmabuf->resv, DMA_RESV_USAGE_KERNEL,
> +				    true, MAX_SCHEDULE_TIMEOUT);
> +	if (ret <= 0) {
> +		if (!ret)
> +			ret = -EAGAIN;
> +		dma_resv_unlock(dmabuf->resv);
> +		return ERR_PTR(ret);
> +	}
> +
> +	map = ctx->dev_ops->map(ctx);
> +	dma_resv_unlock(dmabuf->resv);
> +
> +	if (IS_ERR(map))
> +		return map;
> +	if (WARN_ON_ONCE(!map->min_seg_shift))
> +		return ERR_PTR(-EFAULT);

[Severity: Medium]
If this validation fails and we return -EFAULT, do we leak the map structure
and the underlying device DMA mappings?

It looks like we are bypassing ctx->dev_ops->unmap() and the corresponding
map structure freeing here.

[Severity: Critical]
Does this sequence create a TOCTOU race with dma_buf_io_invalidate_mappings()?

The map is created under dmabuf->resv lock, but we unlock it before updating
ctx->map and ctx->active_maps. 

If an exporter triggers an invalidation:

1. dma_buf_io_create_map() calls ctx->dev_ops->map(ctx).
2. It then calls dma_resv_unlock(dmabuf->resv).
3. The exporter acquires the dmabuf->resv lock and calls
   dma_buf_io_invalidate_mappings().
4. dma_buf_io_kill_maps() and dma_buf_io_wait_active_maps() observe
   no active maps and finish the invalidation.
5. dma_buf_io_create_map() resumes, increments active_maps, and publishes
   the now-stale map to ctx->map.

This allows the stale physical memory mapping to escape to the caller.

> +
> +	atomic_inc(&ctx->active_maps);
> +	atomic_inc(&ctx->all_maps);
> +	/* get a reference for the caller */
> +	percpu_ref_get(&map->refs);
> +
> +	scoped_guard(mutex, &ctx->map_mutex)
> +		rcu_assign_pointer(ctx->map, map);
> +	return map;
> +}
[ ... ]
> +int dma_buf_io_ctx_create(struct file *file,
> +			   struct dma_buf *dmabuf,
> +			   enum dma_data_direction dir,
> +			   struct dma_buf_io_ctx **out_ctx)
> +{
> +	struct dma_buf_io_ctx *ctx;
> +	int ret;
> +
> +	if (!file->f_op->init_dma_buf_io_ctx)
> +		return -EOPNOTSUPP;
> +
> +	ctx = kmalloc_obj(*ctx);
> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	memset(ctx, 0, sizeof(*ctx));
> +	ctx->dir = dir;
> +	ctx->dmabuf = dmabuf;
> +	get_dma_buf(dmabuf);
> +	mutex_init(&ctx->map_mutex);
> +	mutex_init(&ctx->map_create_mutex);
> +	atomic_set(&ctx->active_maps, 0);
> +	atomic_set(&ctx->all_maps, 0);
> +	init_waitqueue_head(&ctx->maps_wq);
> +
> +	ret = file->f_op->init_dma_buf_io_ctx(file, ctx);
> +	if (ret) {
> +		kfree(ctx);
> +		dma_buf_put(dmabuf);
> +		return ret;
> +	}
> +
> +	if (WARN_ON_ONCE(!ctx->dev_ops ||
> +			 !ctx->dev_ops->map ||
> +			 !ctx->dev_ops->unmap ||
> +			 !ctx->dev_ops->release))
> +		return -EINVAL;

[Severity: Medium]
If this check fails, does it leak the allocated ctx and the dmabuf reference?

The previous error path handles cleanup via kfree(ctx) and dma_buf_put(dmabuf),
but this one bails out without cleaning up.

> +
> +	*out_ctx = ctx;
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1789997898.git.asml.silence@gmail.com?part=1

  reply	other threads:[~2026-09-21 13:53 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 13:38 [PATCH v6 00/13] Add dmabuf read/write via io_uring Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 01/13] dma-buf: introduce initial file I/O infrastructure Pavel Begunkov
2026-09-21 13:53   ` sashiko-bot [this message]
2026-09-22  9:08     ` Pavel Begunkov
2026-09-30  6:54       ` Matthew Brost
2026-09-30 10:03         ` Pavel Begunkov
2026-09-30  3:00   ` Matthew Brost
2026-09-30 10:08     ` Pavel Begunkov
2026-09-30 12:48       ` Pavel Begunkov
2026-09-30 19:43         ` Matthew Brost
2026-10-05 11:49           ` Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 02/13] iov_iter: add iterator type for dmabuf maps Pavel Begunkov
2026-09-21 13:53   ` sashiko-bot
2026-09-22  9:15     ` Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 03/13] block: always adjust bi_offset on bio_advance_iter Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 04/13] block: introduce dma map backed bio type Pavel Begunkov
     [not found]   ` <20260922131610.GA30468@lst.de>
2026-09-22 13:54     ` Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 05/13] block: add dma-buf support for raw bdev Pavel Begunkov
2026-09-21 13:50   ` sashiko-bot
2026-09-21 13:38 ` [PATCH v6 06/13] nvme-pci: implement dma-buf backed requests Pavel Begunkov
2026-09-21 13:58   ` sashiko-bot
     [not found]   ` <20260922132016.GA30684@lst.de>
2026-09-22 13:37     ` Pavel Begunkov
     [not found]       ` <20260923045505.GB26231@lst.de>
2026-09-24 15:53         ` Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 07/13] nvme-pci: rename nvme_pci_sgl_set_data to nvme_pci_dma_iter_set_sgl Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 08/13] nvme-pci: add SGL support for the dmabuf path Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 09/13] io_uring/rsrc: introduce buf registration structure Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 10/13] io_uring/rsrc: extend buffer update Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 11/13] io_uring/rsrc: add uncloneable regbuf flag Pavel Begunkov
2026-09-21 13:53   ` sashiko-bot
2026-09-21 13:38 ` [PATCH v6 12/13] io_uring/rsrc: add regbuf import flags Pavel Begunkov
2026-09-21 13:38 ` [PATCH v6 13/13] io_uring/rsrc: add dmabuf backed registered buffers Pavel Begunkov
2026-09-21 13:54   ` sashiko-bot

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=20260921135344.035B81F000FF@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=asml.silence@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=media-ci@linuxtv.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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