CVE-2022-50494CVE-2022-50494是Linux内核中intel_powerclamp热管理驱动的一个本地拒绝服务漏洞。该漏洞源于驱动在处理CPU空闲注入(idle injection)时使用了smp_processor_id()函数获取当前CPU编号,但该函数要求在不可抢占的上下文中调用。当系统CPU 0处于离线状态时,intel_powerclamp驱动会尝试将控制CPU从默认的CPU 0切换到当前在线的CPU,这一操作需要在cpus_read_lock()保护下进行。然而,smp_processor_id()在可抢占上下文中被调用时,内核会触发BUG检查(debug_smp_processor_id),导致内核崩溃(BUG: using smp_processor_id() in preemptible code)。攻击者需要具有本地低权限访问权限即可触发该漏洞,无需用户交互。该漏洞影响系统的可用性(高影响),但不涉及机密性或完整性泄露。漏洞的CVSS 3.1评分为5.5分,属于中危级别。该问题已在Linux内核5.19版本的提交中得到修复,主要通过将smp_processor_id()替换为get_cpu()来正确处理CPU亲和性并避免在可抢占上下文中调用引发的内核BUG。
从技术层面分析,该漏洞的核心问题在于Linux内核intel_powerclamp驱动的powerclamp_set_cur_state()函数中使用了smp_processor_id()函数。smp_processor_id()是一个用于获取当前执行代码的CPU编号的函数,但它有一个严格的前提条件:调用时必须处于不可抢占(preempt-disabled)的上下文中。当CPU 0处于离线状态时,intel_powerclamp驱动需要将控制CPU(control CPU)从默认的CPU 0切换到当前在线的CPU。这一CPU切换操作需要在cpus_read_lock()读写信号量的保护下完成,而cpus_read_lock()是可以在可抢占上下文中获取的锁。当powerclamp_set_cur_state()在持有cpus_read_lock()的情况下调用smp_processor_id()时,内核的调试检查机制(debug_smp_processor_id)会检测到这一违规操作,并触发内核BUG,输出类似'BUG: using smp_processor_id() in preemptible [00000000] code'的错误信息,导致系统崩溃。修复方案是使用get_cpu()函数替代smp_processor_id(),因为get_cpu()内部会正确禁用抢占并增加引用计数,从而满足smp_processor_id()的调用前提条件。攻击者可以通过本地执行特定操作(如使用intel_powerclamp工具触发空闲注入)来利用该漏洞,但需要CPU 0处于离线状态这一前提条件。