Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virtio-mmio: don't break lifecycle of vm_dev

vm_dev has a separate lifecycle because it has a 'struct device'
embedded. Thus, having a release callback for it is correct.

Allocating the vm_dev struct with devres totally breaks this protection,
though. Instead of waiting for the vm_dev release callback, the memory
is freed when the platform_device is removed. Resulting in a
use-after-free when finally the callback is to be called.

To easily see the problem, compile the kernel with
CONFIG_DEBUG_KOBJECT_RELEASE and unbind with sysfs.

The fix is easy, don't use devres in this case.

Found during my research about object lifetime problems.

Fixes: 7eb781b1bbb7 ("virtio_mmio: add cleanup for virtio_mmio_probe")
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Message-Id: <20230629120526.7184-1-wsa+renesas@sang-engineering.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Wolfram Sang and committed by
Michael S. Tsirkin
55c91fed 52a93d39

+2 -3
+2 -3
drivers/virtio/virtio_mmio.c
··· 607 607 struct virtio_device *vdev = 608 608 container_of(_d, struct virtio_device, dev); 609 609 struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); 610 - struct platform_device *pdev = vm_dev->pdev; 611 610 612 - devm_kfree(&pdev->dev, vm_dev); 611 + kfree(vm_dev); 613 612 } 614 613 615 614 /* Platform device */ ··· 619 620 unsigned long magic; 620 621 int rc; 621 622 622 - vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL); 623 + vm_dev = kzalloc(sizeof(*vm_dev), GFP_KERNEL); 623 624 if (!vm_dev) 624 625 return -ENOMEM; 625 626