From: Biren Pandya <birenpandya@gmail.com> mainline inclusion from mainline-v7.2-rc1 commit 0fbd5c2327020858c45b2d1c65775d64cdeca523 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19090 CVE: CVE-2026-89899 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- cec_transmit_msg_fh() drops adap->lock to wait for a blocking transmit in wait_for_completion_killable(). If that wait is interrupted by a signal, cancel_delayed_work_sync() can run before the CEC kthread arms the reply timeout via schedule_delayed_work(&data->work) in cec_transmit_done_ts(). The work is then armed after the cancel, and the data is freed with its delayed_work still pending: ODEBUG: free active (active state 0) object: ... hint: cec_wait_timeout Use disable_delayed_work_sync(): it cancels the work and disables it, so the later schedule_delayed_work() becomes a no-op and the work cannot be re-armed. The data is freed right after, so it need not be re-enabled. Fixes: 490d84f6d73c ("media: cec: forgot to cancel delayed work") Reported-by: syzbot+051024d603432b4ab395@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=051024d603432b4ab395 Suggested-by: Hillf Danton <hdanton@sina.com> Cc: stable@vger.kernel.org Signed-off-by: Biren Pandya <birenpandya@gmail.com> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org> Conflicts: drivers/media/cec/core/cec-adap.c [The 5.10 tree lacks the disable_delayed_work_sync() API (added in v6.9) and uses the older wait/!data->completed structure; keep the original cancel_delayed_work_sync() and, under adap->lock, cancel the reply-timeout work again before freeing, waiting for a running work without the lock (cec_wait_timeout() takes adap->lock) and re-cancelling after re-locking.] Signed-off-by: Chen Jinghuang <chenjinghuang2@huawei.com> --- drivers/media/cec/core/cec-adap.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index eed962a9ff01..05329c40a58e 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -918,8 +918,24 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, mutex_lock(&adap->lock); /* Cancel the transmit if it was interrupted */ - if (!data->completed) - cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + if (!data->completed) { + /* + * The reply-timeout delayed work may have been armed by the + * CEC kthread after the cancel above. Cancel it under the lock; + * if it is already running it is blocked on adap->lock (as + * cec_wait_timeout() takes the lock itself), so wait for it + * without the lock like cec_receive_notify() does, then cancel + * again in case the kthread armed it in the meantime. + */ + if (!cancel_delayed_work(&data->work)) { + mutex_unlock(&adap->lock); + cancel_delayed_work_sync(&data->work); + mutex_lock(&adap->lock); + cancel_delayed_work(&data->work); + } + if (!data->completed) + cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + } /* The transmit completed (possibly with an error) */ *msg = data->msg; -- 2.34.1