[PATCH] firmware: arm_scmi: Fix msg use-after-free in virtio_mark_txdone()
From: Wentao Liang
Date: Wed Sep 16 2026 - 05:37:01 EST
virtio_mark_txdone() can drop the last reference of a polled message
while msg->poll_lock is still held, returning the message to the
free-list where a concurrent sender can re-allocate it and race with
the unlock at the end of the critical section. Hold a spare reference
across the poll_lock critical section and drop it after the unlock.
Fixes: 5a3b7185c47c ("firmware: arm_scmi: Add atomic mode support to virtio transport")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wentao Liang <vulab@xxxxxxxxxxx>
---
drivers/firmware/arm_scmi/transports/virtio.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/firmware/arm_scmi/transports/virtio.c b/drivers/firmware/arm_scmi/transports/virtio.c
index 326c4a93e44b..4bbd9dd2de83 100644
--- a/drivers/firmware/arm_scmi/transports/virtio.c
+++ b/drivers/firmware/arm_scmi/transports/virtio.c
@@ -616,6 +616,14 @@ static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret,
return;
}
+ /*
+ * Hold a spare reference to msg so that it is not returned to the
+ * free-list while it is still accessed under poll_lock: a message
+ * sitting on the free-list can be re-allocated and re-initialized
+ * without taking poll_lock.
+ */
+ scmi_vio_msg_acquire(msg);
+
spin_lock_irqsave(&msg->poll_lock, flags);
/* Do not free timedout polled messages only if still inflight */
if (ret != -ETIMEDOUT || msg->poll_status == VIO_MSG_POLL_DONE)
@@ -624,6 +632,8 @@ static void virtio_mark_txdone(struct scmi_chan_info *cinfo, int ret,
msg->poll_status = VIO_MSG_POLL_TIMEOUT;
spin_unlock_irqrestore(&msg->poll_lock, flags);
+ scmi_vio_msg_release(vioch, msg);
+
scmi_vio_channel_release(vioch);
}
--
2.34.1