Re: [PATCH v6 02/11] driver core: Add dma_cleanup callback in bus_type

From: Jason Gunthorpe
Date: Wed Feb 23 2022 - 08:47:15 EST


On Wed, Feb 23, 2022 at 01:04:00PM +0000, Robin Murphy wrote:

> 1 - tmp->driver is non-NULL because tmp is already bound.
> 1.a - If tmp->driver->driver_managed_dma == 0, the group must currently be
> DMA-API-owned as a whole. Regardless of what driver dev has unbound from,
> its removal does not release someone else's DMA API (co-)ownership.

This is an uncommon locking pattern, but it does work. It relies on
the mutex being an effective synchronization barrier for an unlocked
store:

WRITE_ONCE(dev->driver, NULL)

mutex_lock(&group->lock)
READ_ONCE(dev->driver) != NULL and no UAF
mutex_unlock(&group->lock)

mutex_lock(&group->lock)
tmp = READ_ONCE(dev1->driver);
if (tmp && tmp->blah) [..]
mutex_unlock(&group->lock)
mutex_lock(&group->lock)
READ_ONCE(dev->driver) == NULL
mutex_unlock(&group->lock)

/* No other CPU can UAF dev->driver */
kfree(driver)

Ie the CPU setting driver cannot pass to the next step without all
other CPUs observing the new value because of the release/acquire built
into the mutex_lock.

It is tricky, and can work in this instance, but the pattern's unlocked
design relies on ordering between the WRITE_ONCE and the locks - and
that ordering in dd.c isn't like that today.

Jason