[PATCH 2/2] media: pci: saa7164: fix slab-use-after-free in saa7164_dvb_register

From: xiaopeitux

Date: Tue Jun 02 2026 - 03:03:15 EST


From: Pei Xiao <xiaopei01@xxxxxxxxxx>

A use-after-free (UAF) issue similar to the one in au0828 was found in
the saa7164 DVB driver. When dvb_register_frontend() fails before the
frontend's kref is initialized (e.g., due to -ENOMEM in kzalloc of
fe->frontend_priv), the error path still calls dvb_frontend_detach(),
which eventually invokes dvb_frontend_put(), immediately frees the frontend
via dvb_frontend_free().

Later, the outer error path in saa7164_dvb_register() again calls
dvb->frontend->ops.release() on the already freed frontend, leading
to a double free and a KASAN slab-use-after-free report.

The call chain is:

saa7164_dvb_register()
-> dvb_register(port)
-> dvb_register_frontend()
(fails before kref_init, e.g., -ENOMEM)
-> fail_frontend:
-> dvb_frontend_detach()
-> dvb_frontend_put()
-> __dvb_frontend_free()
-> dvb_frontend_invoke_release(fe, fe->ops.release)
-> (frontend-specific release, frees the object)
(back to saa7164_dvb_register)
if (ret < 0) {
if (dvb->frontend->ops.release)
dvb->frontend->ops.release(dvb->frontend); // USE-AFTER-FREE
}

The second release is redundant and unsafe because the frontend has
already been freed by the first release via dvb_frontend_put.

Fix this by removing the redundant manual release call in the outer
error path. The frontend is already destroyed by dvb_frontend_put()
in the inner error path, so we only need to set dvb->frontend to NULL
to avoid any further misuse.

Modified by referring to au0828 UAF.

Fixes: ead666000a5f ("media: dvb_frontend: only use kref after initialized")
Reported-by: Shuangpeng Bai <shuangpeng.kernel@xxxxxxxxx>
Closes: https://lore.kernel.org/lkml/AAC17221-93BF-436F-92AC-906A18F882F0@xxxxxxxxx/
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Pei Xiao <xiaopei01@xxxxxxxxxx>
---
drivers/media/pci/saa7164/saa7164-dvb.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index 3eb749db1ca7..ba6e83b360ac 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -727,8 +727,10 @@ int saa7164_dvb_register(struct saa7164_port *port)
/* register everything */
ret = dvb_register(port);
if (ret < 0) {
- if (dvb->frontend->ops.release)
- dvb->frontend->ops.release(dvb->frontend);
+ /* dvb->frontend freed in dvb_frontend_put, now we can set
+ * frontend to NULL
+ */
+ dvb->frontend = NULL;
return ret;
}

--
2.25.1