🇰🇷 한글 설명
Linux 커널의 amdgpu DRM 드라이버에서 IRQ 레지스터의 읽기-수정-쓰기(RMW) 작업이 원자적으로 처리되지 않아 발생하는 레이스 컨디션 취약점입니다. 이로 인해 인터럽트 설정과 확인 과정에서 데이터가 덮어씌워져 하드웨어 인터럽트가 비정상적으로 해제될 수 있습니다.
💡 쉬운 설명
하드웨어 신호를 처리하는 과정에서 두 작업이 동시에 일어나 데이터가 꼬이는 문제입니다. 이로 인해 화면 재생 빈도(Refresh rate) 관련 신호가 제대로 전달되지 않아 시스템 성능 저하나 타임아웃이 발생할 수 있습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
drm/amd/display: Atomize IRQ register read/modify/write ops
[Why]
The OTG_GLOBAL_SYNC_STATUS register controls various HW IRQ sources for
the output timing generator (OTG). VUPDATE_NO_LOCK is one of them.
To enable the IRQ, driver sets the VUPDATE_NO_LOCK_EN bit in the
GLOBAL_SYNC_STATUS register.
To ack the IRQ after it fires, the driver sets the VUPDATE_NO_LOCK_CLEAR
bit in the same GLOBAL_SYNC_STATUS register.
The bit sets are done through read/modify/write operations, which are
not atomic. Thus, the following race is possible:
Thread A: IRQ handler:
*HW IRQ fires*
# IRQ disable
val = read(GLOBAL_SYNC_STATUS)
unset(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# ACK reads VUPDATE_NO_LOCK_EN unset
val1 = read(GLOBAL_SYNC_STATUS)
set(val1, VUPDATE_NO_LOCK_CLEAR)
# IRQ enable
val = read(GLOBAL_SYNC_STATUS)
set(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# BAD! clears VUPDATE_NO_LOCK_EN
write(val1, GLOBAL_SYNC_STATUS)
Regarding the tagged Fixes: change, it appears the change made this race
more likely to occur. Since VUPDATE_NO_LOCK is now the sole IRQ source
for vblank handling, a single race on high refresh panels can lead to a
time out.
[How]
The GLOBAL_SYNC_STATUS register is only one example, other IRQ control
registers also share the same scheme. On top of GLOBAL_SYNC_STATUS,
let's clean up those as well.
To keep things simple, Let's atomize the IRQ rmw ops via a single
driver-wide spinlock. Due to the small scope of this lock, it is
unlikely to cause noticeable overhead on top of all the existing locking
within the IRQ set/handle paths.
Since DM is responsible for locking, wrap dc_interrupt_set/ack with the
spinlock in the new amdgpu_dm_irq_set/ack functions. Migrate/drop all
references in DM to dc_interrupt_set/ack to use amdgpu_dm_irq_set/ack
instead.
(cherry picked from commit 70de0a0216583a53c946155f8c8adedfdca6b4e7)
📍 영향받는 시스템
Linux kernel (amd/display 드라이버를 사용하는 AMD GPU 시스템)
⚔️ 공격 벡터
로컬 공격자가 특정 하드웨어 인터럽트 상황을 유도하여 시스템의 타이밍 문제를 일으키는 방식 (Race Condition)
🛡️ 대응 방법
커널 패치를 통해 IRQ 레지스터 조작 시 스핀락(Spinlock)을 사용하여 작업을 원자적으로 처리하도록 업데이트해야 합니다.
🔧 검증 코드
현재 사용 중인 커널 버전과 amdgpu 드라이버 로드 여부를 확인하여 패치 적용 대상인지 판단합니다.
uname -r && grep -i 'amdgpu' /lib/modules/$(uname -r)/kernel/drivers/gpu/drm/amd/amdgpu.ko 2>/dev/null