iio: buffer: Tie IIO dma fence lock lifetime to the fence

The `iio_dma_fence` implementation currently uses a lock embedded in the
`iio_dmabuf_priv`. But the `iio_dma_fence` can outlive the
`iio_dmabuf_priv`, which can cause a use-after-free.

Tie the lifetime of the lock to the lifetime of the fence by embedding them
in the same struct.

We can't just hold a reference to the `iio_dmabuf_priv` from the
`iio_dma_fence` since `iio_buffer_dmabuf_release()` might sleep and the
fence release callback is not allowed to sleep.

Note that the `dma_fence` framework now has an internal lock that gets used
when the passing `NULL` for `lock` in `dma_fence_init()`, but in order to
allow this patch to be backportable use an external lock.

Reported-by: codex:gpt-5.6
Fixes: 3e26d9f08f ("iio: core: Add new DMABUF interface infrastructure")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Cc: <Stable@vger.kernel.org>
Signed-off-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
This commit is contained in:
Lars-Peter Clausen 2026-07-15 08:42:44 -07:00 committed by Jonathan Cameron
parent 6288b593e7
commit f25ec4627d

View File

@ -47,9 +47,6 @@ struct iio_dmabuf_priv {
u64 context;
/* Spinlock used for locking the dma_fence */
spinlock_t lock;
struct dma_buf_attachment *attach;
struct sg_table *sgt;
enum dma_data_direction dir;
@ -58,6 +55,7 @@ struct iio_dmabuf_priv {
struct iio_dma_fence {
struct dma_fence base;
spinlock_t lock; /* protects base */
struct iio_dmabuf_priv *priv;
struct work_struct work;
};
@ -1706,7 +1704,6 @@ static int iio_buffer_attach_dmabuf(struct iio_dev_buffer_pair *ib,
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->lock);
priv->context = dma_fence_context_alloc(1);
dmabuf = dma_buf_get(fd);
@ -1896,6 +1893,8 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
goto err_attachment_put;
}
spin_lock_init(&fence->lock);
fence->priv = priv;
seqno = atomic_add_return(1, &priv->seqno);
@ -1906,7 +1905,7 @@ static int iio_buffer_enqueue_dmabuf(struct iio_dev_buffer_pair *ib,
* the dma_fence.
*/
dma_fence_init(&fence->base, &iio_buffer_dma_fence_ops,
&priv->lock, priv->context, seqno);
&fence->lock, priv->context, seqno);
ret = iio_dma_resv_lock(dmabuf, nonblock);
if (ret)