摘要:
In the Linux kernel, the following vulnerability has been resolved:
usb: xhci: Don't skip on Stopped - Length Invalid
Up until commit d56b0b2ab142 ("usb: xhci: ensure skipped isoc TDs are
returned when isoc ring is stopped") in v6.11, the driver didn't skip
missed isochronous TDs when handling Stoppend and Stopped - Length
Invalid events. Instead, it erroneously cleared the skip flag, which
would cause the ring to get stuck, as future events won't match the
missed TD which is never removed from the queue until it's cancelled.
This buggy logic seems to have been in place substantially unchanged
since the 3.x series over 10 years ago, which probably speaks first
and foremost about relative rarity of this case in normal usage, but
by the spec I see no reason why it shouldn't be possible.
After d56b0b2ab142, TDs are immediately skipped when handling those
Stopped events. This poses a potential problem in case of Stopped -
Length Invalid, which occurs either on completed TDs (likely already
given back) or Link and No-Op TRBs. Such event won't be recognized
as matching any TD (unless it's the rare Link TRB inside a TD) and
will result in skipping all pending TDs, giving them back possibly
before they are done, risking isoc data loss and maybe UAF by HW.
As a compromise, don't skip and don't clear the skip flag on this
kind of event. Then the next event will skip missed TDs. A downside
of not handling Stopped - Length Invalid on a Link inside a TD is
that if the TD is cancelled, its actual length will not be updated
to account for TRBs (silently) completed before the TD was stopped.
I had no luck producing this sequence of completion events so there
is no compelling demonstration of any resulting disaster. It may be
a very rare, obscure condition. The sole motivation for this patch
is that if such unlikely event does occur, I'd rather risk reporting
a cancelled partially done isoc frame as empty than gamble with UAF.
This will be fixed more properly by looking at Stopped event's TRB
pointer when making skipping decisions, but such rework is unlikely
to be backported to v6.12, which will stay around for a few years.
安全等级: Low
公告ID: KylinSec-SA-2025-2402
发布日期: 2025年4月28日
关联CVE: CVE-2025-22023
Linux内核中发现以下漏洞修复:
usb: xhci: 正确处理"Stopped - Length Invalid"事件
在v6.11版本提交d56b0b2ab142("usb: xhci: ensure skipped isoc TDs are returned when isoc ring is stopped")之前,驱动程序在处理"Stopped"和"Stopped - Length Invalid"事件时未能正确跳过错过的等时传输描述符(TD)。相反,它错误地清除了跳过标志,导致传输环卡死,因为后续事件将无法匹配这个永远不会从队列中移除的TD(直到被取消)。
这个有缺陷的逻辑似乎从10多年前的3.x系列内核开始就基本未变,这可能首先说明了正常使用中这种情况相对罕见。但根据规范,这种情况完全有可能发生。
在d56b0b2ab142提交后,驱动程序在处理这些"Stopped"事件时会立即跳过TD。这在"Stopped - Length Invalid"情况下可能存在问题,因为该事件可能发生在已完成的TD(可能已返回)、Link TRB或No-Op TRB上。这样的事件不会被识别为匹配任何TD(除非是TD内部的罕见Link TRB),将导致跳过所有待处理的TD,可能在它们完成前就返回,存在等时数据丢失风险,甚至可能导致硬件使用已释放内存(UAF)。
作为折中方案,对此类事件既不跳过也不清除跳过标志。这样下一个事件将跳过错过的TD。不在TD内部的Link TRB上处理"Stopped - Length Invalid"的缺点是,如果TD被取消,其实际长度将不会更新以计入TD停止前(静默)完成的TRB。
我未能成功复现这一系列完成事件,因此没有确凿证据表明会导致灾难性后果。这可能是一个非常罕见且晦涩的情况。本补丁的唯一动机是,如果这种不太可能的事件确实发生,我宁愿冒险将部分完成的等时帧报告为空,也不愿冒险出现UAF问题。
更彻底的修复方案是通过检查"Stopped"事件的TRB指针来做跳过决策,但这种重构不太可能被反向移植到v6.12版本,而该版本还将继续使用数年。
cve名称 | 产品 | 组件 | 是否受影响 |
---|---|---|---|
CVE-2025-22023 | KY3.4-5A | kernel | Unaffected |
CVE-2025-22023 | V6 | kernel | Unaffected |