Re: [PATCH] hw/ide/core: Fix possible crash via NULL pointer in ide_cancel_dma_sync()
Philippe Mathieu-Daudé <[email protected]> Mon, 20 Jul 2026 22:36:48 +0200
| Newsgroups | org.nongnu.qemu-trivial,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On 20/7/26 21:42, Thomas Huth wrote: > From: Thomas Huth <[email protected]> > > ide_cancel_dma_sync() is called with a "IDEState *s" for one of the > two IDE drives on a bus (primary or secondary drive) to cancel all > pending DMA transfers on the drive. The code then checks > s->bus->dma->aiocb to see whether there is any IO in flight on the > *bus* and then calls blk_drain(s->blk) to wait for its completion. > However, s->bus->dma->aiocb might belong to the other drive on the > bus, and if there is no disk attached to the current drive, s->blk > is NULL. Since blk_drain() does not check its parameter for a NULL > pointer, QEMU can crash in such a case. > > Fix the problem by checking s->blk to be a valid pointer before > calling blk_drain() in this function. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/905 > Reported-by: Alexander Bulekov <[email protected]> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4052 > Reported-by: dong ling > Signed-off-by: Thomas Huth <[email protected]> > --- > hw/ide/core.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/hw/ide/core.c b/hw/ide/core.c > index f78b00220b8..49848c8e6bd 100644 > --- a/hw/ide/core.c > +++ b/hw/ide/core.c > @@ -741,8 +741,11 @@ void ide_cancel_dma_sync(IDEState *s) > * In the future we'll be able to safely cancel the I/O if the > * whole DMA operation will be submitted to disk with a single > * aio operation with preadv/pwritev. > + * > + * Note: s->bus->dma->aiocb might belong to the adjacent IDEState, > + * so we have to check s->blk for not being NULL, too. > */ > - if (s->bus->dma->aiocb) { > + if (s->bus->dma->aiocb && s->blk) { Reviewed-by: Philippe Mathieu-Daudé <[email protected]> If you don't object, I'll change to: if (s->blk && s->bus->dma->aiocb) { when queueing. > trace_ide_cancel_dma_sync_remaining(); > blk_drain(s->blk); > assert(s->bus->dma->aiocb == NULL);