mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Matt Evans <matt@ozlabs.org>
To: Zack Rusin <zack.rusin@broadcom.com>
Cc: "Sumit Semwal" <sumit.semwal@linaro.org>,
	"Christian König" <christian.koenig@amd.com>,
	"Thomas Hellstrom" <thellstrom@vmware.com>,
	"Jani Nikula" <jani.nikula@linux.intel.com>,
	"Joonas Lahtinen" <joonas.lahtinen@linux.intel.com>,
	"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
	"Tvrtko Ursulin" <tursulin@ursulin.net>,
	linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linaro-mm-sig@lists.linaro.org, linux-kernel@vger.kernel.org,
	"Alex Mastro" <amastro@fb.com>,
	"Alex Williamson" <alex@shazbot.org>
Subject: Re: [PATCH] dma-buf: Annul dmabuf->file on file release
Date: Thu, 8 Oct 2026 14:41:53 +0100	[thread overview]
Message-ID: <fd564691-ca79-4fcb-80a7-8328c71ab322@ozlabs.org> (raw)
In-Reply-To: <CABQX2QOOaxkxzREaDHY3iXHs0106u+F9JvQSTXCnA7AEjPPxuQ@mail.gmail.com>

Hi Zack,

On 07/10/2026 16:24, Zack Rusin wrote:
> On Tue, Oct 6, 2026 at 3:15 PM Matt Evans <matt@ozlabs.org> wrote:
>>
>> The dmabuf release path is split between file and dentry release:
>> dma_buf_file_release() is called shortly before the file is freed, and
>> dma_buf_release() calls an exporter's dmabuf->ops->release when the
>> dentry is freed.  However, the dentry can outlive the file (for
>> example, if opened with O_PATH), meaning .release might be called some
>> time after the file is freed.
>>
>> This presents a window, when closing a DMABUF file, in which
>> dmabuf->file points to freed memory yet .release op has not yet been
>> called.
>>
>> For VFIO, if a buffer's .release has not been called it's considered
>> still active and subject to move/cleanup.  If so, it attempts to
>> get_file_active() on dmabuf->file: a file close with dentry held open
>> will call this function with a stale pointer, a UAF.
>>
>> To make this pattern safe, set dmabuf->file to NULL in
>> dma_buf_file_release() to reflect that the associated file is now dead
>> even if the DMABUF is not yet gone.  A get_file_active() ... fput()
>> sequence concurrent with a file close will only execute as one of:
>>
>>    - Gets the file before file_ref_put() (dmabuf->file valid)
>>    - Observes dmabuf->file pointing to a file, but it's DEAD (no file)
>>    - Observes dmabuf->file = NULL (no file)
>>
>> Originally, drivers could assume dmabuf->file was valid until .release
>> was called from fops->release.  This assumption was no longer valid
>> after 4ab59c3c638c6 ("dma-buf: Move dma_buf_release() from fops to
>> dentry_ops"), which moved the callback to the dentry release (by which
>> point the file might have been freed).  With this commit, drivers must
>> still consider that dmabuf->file could be NULL before .release.
>>
>> Fixes: 4ab59c3c638c6 ("dma-buf: Move dma_buf_release() from fops to dentry_ops")
>> Signed-off-by: Matt Evans <matt@ozlabs.org>
>> ---
>>
>> Hi,
>>
>> This issue was found (by Claude Opus 5.5) in the context of VFIO's
>> DMABUF export path.  VFIO iterates live DMABUFs with a
>> get_file_active()/fput() block, which now becomes safe if the file is
>> closed (and memory freed!) yet DMABUF .release hasn't yet occurred.
>>
>> However, there are a couple of other places that directly use
>> dmabuf->file and seem able to race a closing file (i.e. without holding
>> the file reference)?  If this is so, they'd be a UAF today; with this
>> patch that goes away, but instead of a stale pointer dmabuf->file could
>> be NULL:
>>
>> 1. drivers/gpu/drm/vmwgfx/ttm_object.c:get_dma_buf_unless_doomed()
>>
>>    file_ref_get(&dmabuf->file->f_ref); on a non-refcounted DMABUF
> 
> Yes, that's a real UAF today. vmwgfx relied on the exporter's
> dma_buf_ops.release running inside __fput() before file_free(), which
> stopped being true with 4ab59c3c638c and we missed it.
> 
> But this patch on its own makes vmwgfx worse. In the ordinary case,
> where closing the file drops the last dentry reference, a close racing
> PRIME_HANDLE_TO_FD is safe today: ttm_prime_dmabuf_release() runs from
> the same __fput() and blocks on prime->mutex, keeping the file
> allocated, so file_ref_get() just fails on the dead refcount. With
> this patch dmabuf->file is NULL in that window and we oops. So this
> shouldn't go to stable without a vmwgfx fix.
> 
> For vmwgfx we'd probably need this one line change in
> drivers/gpu/drm/vmwgfx/ttm_object.c to accompany this patch:
> @@ -471,7 +475,7 @@ void ttm_object_device_release(struct
> ttm_object_device **p_tdev)
>    */
>   static bool __must_check get_dma_buf_unless_doomed(struct dma_buf *dmabuf)
>   {
> -     return file_ref_get(&dmabuf->file->f_ref);
> +     return get_file_active(&dmabuf->file) != NULL;
>   }
> 
> under prime->mutex, which keeps the struct dma_buf alive. It needs the
> NULL store from this patch to fix the existing UAF, since otherwise
> the recheck can accept a recycled file through the unchanged stale
> pointer.

Thanks for confirming!  Ah, so get_file_active() is good here, cheers. 
I'll repost as a 2-part series to first include this in vmwgfx and 
second add the anNULL.

>> The commit message of 90ee6ed776c0 ("fs: port files to file_ref") hints
>> this might be more subtle than replacing it with a get_file() variant
>> (so as to accept a NULL file *).
>>
>> 2. drivers/gpu/drm/i915/gvt/dmabuf.c:intel_vgpu_get_dmabuf()
>>
>>    gvt_dbg_dpy(... file_count(dmabuf->file) ...);

FWIW aside, I re-read this, and there does appear to be a ref held 
(dma_buf_export() has just happened, and dma_buf_fd() generated) so 
dmabuf->file is stable at that point.

>> Respective vmwgfx & i915 maintainers, what is your view?
>> Or, indeed, if anyone sees any other questionable uses of dmabuf->file.
>>
>> Thanks,
>>
>>
>> Matt
>>
>>
>>    drivers/dma-buf/dma-buf.c | 6 +++++-
>>    1 file changed, 5 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
>> index 4c9add51f9ef..726639130477 100644
>> --- a/drivers/dma-buf/dma-buf.c
>> +++ b/drivers/dma-buf/dma-buf.c
>> @@ -193,11 +193,15 @@ static void dma_buf_release(struct dentry *dentry)
>>
>>    static int dma_buf_file_release(struct inode *inode, struct file *file)
>>    {
>> +       struct dma_buf *dmabuf = file->private_data;
>> +
>>          if (!is_dma_buf_file(file))
>>                  return -EINVAL;
>>
>> -       __dma_buf_list_del(file->private_data);
>> +       __dma_buf_list_del(dmabuf);
>>
>> +       /* Must be observed by __get_file_rcu() before file_free() */
>> +       smp_store_mb(dmabuf->file, NULL);
> 
> I think Alex is right and dmabuf can be NULL here. An early if
> (!dmabuf) return 0" will fix that.

Yep, on it.

Many thanks,


Matt


  reply	other threads:[~2026-10-08 13:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-06 19:15 Matt Evans
2026-10-07  7:51 ` Christian König
2026-10-07 14:29   ` Matt Evans
2026-10-07 14:46     ` Christian König
2026-10-07  9:19 ` Alex Mastro
2026-10-07 14:42   ` Matt Evans
2026-10-07 15:24 ` Zack Rusin
2026-10-08 13:41   ` Matt Evans [this message]
2026-10-12 16:03     ` Matt Evans

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=fd564691-ca79-4fcb-80a7-8328c71ab322@ozlabs.org \
    --to=matt@ozlabs.org \
    --cc=alex@shazbot.org \
    --cc=amastro@fb.com \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=rodrigo.vivi@intel.com \
    --cc=sumit.semwal@linaro.org \
    --cc=thellstrom@vmware.com \
    --cc=tursulin@ursulin.net \
    --cc=zack.rusin@broadcom.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 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®