[PATCH] firmware: arm_scmi: Fix msg use-after-free in virtio_mark_txdone()

Wentao Liang vulab at iscas.ac.cn
Wed Sep 16 02:35:27 PDT 2026


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 at vger.kernel.org
Signed-off-by: Wentao Liang <vulab at iscas.ac.cn>
---
 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




More information about the linux-arm-kernel mailing list