This issue was discovered using a custom multi-threaded C fuzzer
designed to stress-test HECI client lifecycles over /dev/mei0. By
running one thread that streams asynchronous MKHI requests while a
second thread concurrently drives rapid open/close/reconnect cycles,
a race condition is triggered during client teardown.
In mei_release(), a host client is torn down upon close(). During this
sequence, mei_cl_disconnect() is invoked, which temporarily releases
dev->device_lock while waiting for the firmware response.
If an in-flight read request was previously submitted, an incoming
completion interrupt processed concurrently by the MEI interrupt
handler can add a completed callback into cl->rd_completed via
mei_cl_add_rd_completed().
Because mei_cl_flush_queues(cl, NULL) was invoked before
mei_cl_unlink(cl), an incoming completion callback can slip into
cl->rd_completed after the flush has completed but before the client
is unlinked from dev->file_list. When mei_cl_unlink() is subsequently
called, the invariant check at drivers/misc/mei/client.c:698 triggers:
WARN_ON(!list_empty(&cl->rd_completed) ||
!list_empty(&cl->rd_pending) ||
!list_empty(&cl->link));
Call trace:
WARNING: CPU: 2 PID: 5056 at drivers/misc/mei/client.c:698 mei_cl_unlink+0xaa/0x140 [mei]
RIP: 0010:mei_cl_unlink+0xaa/0x140 [mei]
Call Trace:
<TASK>
mei_release+0x202/0x270 [mei]
__fput+0x105/0x2e0
__x64_sys_close+0x90/0x140
do_syscall_64+0xaa/0x660
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
Immediately following mei_cl_unlink(), mei_release() calls kfree(cl).
If any remaining or deferred callback references the freed client, a
use-after-free occurs.
Fix this by flushing queues after unlinking the client from
dev->file_list inside mei_cl_unlink(), preventing concurrent IRQ
completions from populating the completed queue during teardown.
Note: An LLM was used solely to assist with the proper phrasing and
formatting of this commit message. The vulnerability discovery,
fuzzer development, and code fix are entirely original author's work.
Fixes: f35fe5f47ed0 ("mei: add a vtag map for each client")
Signed-off-by: Nirbhay Kumar <[email protected]>
Cc: [email protected]
---
v4:
- Added the fuzzer methodology to the commit message per maintainer request.
- Documented LLM usage for Changelog formatting in the commit message.
- Manually wrapped commit message lines to 72 characters.
v3:
- Removed non-standard Helped-by tags.
v2:
- Removed redundant Reported-by tag.
- Added Fixes tag pointing to commit f35fe5f47ed0.
drivers/misc/mei/client.c | 2 ++
drivers/misc/mei/main.c | 1 -
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 643b003..38b5792 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -695,6 +695,8 @@ int mei_cl_unlink(struct mei_cl *cl)
cl->state = MEI_FILE_UNINITIALIZED;
cl->writing_state = MEI_IDLE;
+ mei_cl_flush_queues(cl, NULL);
+
WARN_ON(!list_empty(&cl->rd_completed) ||
!list_empty(&cl->rd_pending) ||
!list_empty(&cl->link));
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 4fbf0b3..9e14ab4 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -148,7 +148,6 @@ static int mei_release(struct inode *inode, struct file *file)
goto out;
}
- mei_cl_flush_queues(cl, NULL);
cl_dbg(dev, cl, "removing\n");
mei_cl_unlink(cl);
--
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.