CVE-2022-49783 Information
Description
In the Linux kernel the following vulnerability has been resolved:
x86/fpu: Drop fpregs lock before inheriting FPU permissions
Mike Galbraith reported the following against an old fork of preempt-rt but the same issue also applies to the current preempt-rt tree.
BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:46
in_atomic(): 1 irqs_disabled(): 0 non_block: 0 pid: 1 name: systemd
preempt_count: 1 expected: 0
RCU nest depth: 0 expected: 0
Preemption disabled at:
fpu_clone
CPU: 6 PID: 1 Comm: systemd Tainted: G E (unreleased)
Call Trace:
Mike says:
The splat comes from fpu_inherit_perms() being called under fpregs_lock() and us reaching the spin_lock_irq() therein due to fpu_state_size_dynamic() returning true despite static key __fpu_state_size_dynamic having never been enabled.
Mike’s assessment looks correct. fpregs_lock on a PREEMPT_RT kernel disables preemption so calling spin_lock_irq() in fpu_inherit_perms() is unsafe. This problem exists since commit
9e798e9aa14c (�/fpu: Prepare fpu_clone() for dynamically enabled features).
Even though the original bug report should not have enabled the paths at all the bug still exists.
fpregs_lock is necessary when editing the FPU registers or a task’s FP state but it is not necessary for fpu_inherit_perms(). The only write of any FP state in fpu_inherit_perms() is for the new child which is not running yet and cannot context switch or be borrowed by a kernel thread yet. Hence fpregs_lock is not protecting anything in the new child until clone() completes and can be dropped earlier. The siglock still needs to be acquired by fpu_inherit_perms() as the read of the parent’s permissions has to be serialised.
[ bp: Cleanup splat. ]
Reference
https://git.kernel.org/stable/c/36b038791e1e2baea892e9276588815fd14894b4 https://git.kernel.org/stable/c/c6e8a7a1780af3da65e78a615f7d0874da6aabb0
Share on: