From: Hans Verkuil <hverkuil+cisco@kernel.org>
To: YuanZhe Liu <25031212351@stu.xidian.edu.cn>,
Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Cc: Shuah Khan <shuah@kernel.org>, Bin Yu <byu@xidian.edu.cn>,
Cheng Wen <wencheng@xidian.edu.cn>,
linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: Re: [PATCH v3] media: dvb-core: skip disable_source handler for a released entity
Date: Thu, 12 Nov 2026 09:44:33 +0100 [thread overview]
Message-ID: <a19fa548-32a2-49a1-86ce-c93fcab7f729@kernel.org> (raw)
In-Reply-To: <20261102143415.26942-1-25031212351@stu.xidian.edu.cn>
On 02/11/2026 15:34, YuanZhe Liu wrote:
> dvb_remove_device() frees the media entity of a dvb_device through
> dvb_media_device_free() and sets dvbdev->entity to NULL. The media
> device of the adapter can still be registered at that point: au0828,
> for example, only clears mdev->disable_source in au0828_usb_release(),
> which runs after au0828_dvb_unregister() has unregistered the frontend
> device.
>
> A file descriptor that survives the disconnect then reaches
> dvb_frontend_release() with dvbdev->entity already NULL and calls
>
> fe->dvb->mdev->disable_source(dvbdev->entity);
>
> au0828_disable_source() dereferences that argument unconditionally:
>
> struct media_device *mdev = entity->graph_obj.mdev;
>
> which faults:
>
> general protection fault: 0000 [#1] SMP KASAN
> KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
> RIP: au0828_disable_source+0x27/0xb70 au0828-core.c:445
> Call Trace:
> dvb_frontend_release+0x2eb/0x500 dvb_frontend.c:2946
>
> The error path of __dvb_frontend_open() has the same call.
>
> Skip the handler when dvbdev->entity is gone. For that check to be
> sufficient, clear dvbdev->entity in dvb_media_device_free() before the
> entity is unregistered and freed: both frontend paths read the pointer
> while holding mdev->graph_mutex, and media_device_unregister_entity()
> takes the same lock, so a reader either still sees a registered entity,
> for which unregister waits, or sees NULL. Clearing the pointer after
> the unregister would leave a window in which the entity is read after
> it was already freed.
>
> Read the pointer only once, into a local variable, while the lock is
> held. dvb_media_device_free() stores NULL before taking graph_mutex,
> so re-reading the field to pass it as the argument could still observe
> NULL and hand it to the handler. That store is not serialised with the
> locked readers either, so publish the pointer with WRITE_ONCE() and
> read it with READ_ONCE().
>
> Stopping the pipeline the handler started is not done here. Only the
> driver knows how to release the link it owns, and dvb_media_device_free()
> runs for every dvb_device, including the demux, dvr and ca entities that
> never own a media link; calling the handler for those would deactivate a
> link owned by another entity. The au0828 driver stops the pipeline and
> clears its saved link in au0828_usb_disconnect(), before the frontend
> entity is unregistered, in a separate patch.
>
> Fixes: 68ff5767ddc4 ("[media] media: dvb-frontend invoke enable/disable_source handlers")
> Cc: stable@vger.kernel.org
> Co-developed-by: Bin Yu <byu@xidian.edu.cn>
> Signed-off-by: Bin Yu <byu@xidian.edu.cn>
> Co-developed-by: Cheng Wen <wencheng@xidian.edu.cn>
> Signed-off-by: Cheng Wen <wencheng@xidian.edu.cn>
> Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn>
> ---
> Changes in v3:
> - Publish dvbdev->entity with WRITE_ONCE() and read it with READ_ONCE()
> at both frontend call sites, so the clear in dvb_media_device_free()
> is not a plain data race with the readers that hold graph_mutex.
> - State why the active pipeline is torn down by the driver rather than
> in dvb-core. The matching au0828 change is attached to this mail.
>
> Link: https://lore.kernel.org/r/20261102142508.24277-1-25031212351@stu.xidian.edu.cn
>
> Changes in v2:
> - Read dvbdev->entity once into a local variable under graph_mutex at both
> call sites. dvb_media_device_free() clears the pointer without holding
> that lock, so re-reading the field for the call argument could still pass
> NULL to the handler.
> ---
> drivers/media/dvb-core/dvb_frontend.c | 14 ++++++++++----
> drivers/media/dvb-core/dvbdev.c | 16 +++++++++++++---
> 2 files changed, 23 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
> index 0286da57f382..bcee88e16576 100644
> --- a/drivers/media/dvb-core/dvb_frontend.c
> +++ b/drivers/media/dvb-core/dvb_frontend.c
> @@ -2826,9 +2826,12 @@ static int __dvb_frontend_open(struct inode *inode, struct file *file)
> #ifdef CONFIG_MEDIA_CONTROLLER_DVB
> mutex_lock(&fe->dvb->mdev_lock);
> if (fe->dvb->mdev) {
> + struct media_entity *entity;
> +
> mutex_lock(&fe->dvb->mdev->graph_mutex);
> - if (fe->dvb->mdev->disable_source)
> - fe->dvb->mdev->disable_source(dvbdev->entity);
> + entity = READ_ONCE(dvbdev->entity);
> + if (entity && fe->dvb->mdev->disable_source)
> + fe->dvb->mdev->disable_source(entity);
> mutex_unlock(&fe->dvb->mdev->graph_mutex);
> }
> mutex_unlock(&fe->dvb->mdev_lock);
> @@ -2941,9 +2944,12 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
> #ifdef CONFIG_MEDIA_CONTROLLER_DVB
> mutex_lock(&fe->dvb->mdev_lock);
> if (fe->dvb->mdev) {
> + struct media_entity *entity;
> +
> mutex_lock(&fe->dvb->mdev->graph_mutex);
> - if (fe->dvb->mdev->disable_source)
> - fe->dvb->mdev->disable_source(dvbdev->entity);
> + entity = READ_ONCE(dvbdev->entity);
> + if (entity && fe->dvb->mdev->disable_source)
> + fe->dvb->mdev->disable_source(entity);
> mutex_unlock(&fe->dvb->mdev->graph_mutex);
> }
> mutex_unlock(&fe->dvb->mdev_lock);
> diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
> index d753d329502a..bb6369c3abde 100644
> --- a/drivers/media/dvb-core/dvbdev.c
> +++ b/drivers/media/dvb-core/dvbdev.c
> @@ -208,10 +208,20 @@ static void dvb_media_device_free(struct dvb_device *dvbdev)
> {
> #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
> if (dvbdev->entity) {
> - media_device_unregister_entity(dvbdev->entity);
> - kfree(dvbdev->entity);
> + struct media_entity *entity = dvbdev->entity;
> +
> + /*
> + * Clear the pointer before the entity is unregistered and
> + * freed. The frontend release and open paths read it under
> + * mdev->graph_mutex and pass it to the disable_source
> + * handler, so a stale entity must not stay reachable. Publish
> + * it with WRITE_ONCE() because the store is not serialised by
> + * that lock.
> + */
> + WRITE_ONCE(dvbdev->entity, NULL);
I think this can be simplified: just take call mutex_lock(&fe->dvb->mdev->graph_mutex),
then set dvbdev->entity to NULL and unlock.
In __dvb_frontend_open and dvb_frontend_release you can just check if dvbdev->entity is
non-NULL before calling disable_source.
You basically say that in the comment you added: the store is not serialized by
the lock, so just add that lock here.
Regards,
Hans
> + media_device_unregister_entity(entity);
> + kfree(entity);
> kfree(dvbdev->pads);
> - dvbdev->entity = NULL;
> dvbdev->pads = NULL;
> }
>
prev parent reply other threads:[~2026-11-12 8:44 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 13:19 [PATCH] " YuanZhe Liu
2026-11-02 13:58 ` [PATCH v2] " YuanZhe Liu
2026-11-02 14:34 ` [PATCH v3] " YuanZhe Liu
2026-11-12 8:44 ` Hans Verkuil [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a19fa548-32a2-49a1-86ce-c93fcab7f729@kernel.org \
--to=hverkuil+cisco@kernel.org \
--cc=25031212351@stu.xidian.edu.cn \
--cc=byu@xidian.edu.cn \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab+huawei@kernel.org \
--cc=shuah@kernel.org \
--cc=stable@vger.kernel.org \
--cc=wencheng@xidian.edu.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®