🇰🇷 한글 설명
Linux 커널의 hinic 네트워크 드라이버에서 hinic_get_stats64() 함수가 통계 수집 시 down()/up() 세마포어를 사용해 스케줄링이 발생할 수 있었다. 이 드라이버를 bond 슬레이브로 사용하고 bond 장치 통계를 읽으면 스핀락을 잡은 상태에서 슬립이 일어나 소프트 락업과 커널 행(hang)이 발생할 수 있다. 이번 수정은 잠금이 필요 없도록 통계 변수를 지역 변수로 바꾸고 해당 down()/up() 호출을 제거했다.
💡 쉬운 설명
네트워크 카드를 묶음(bond)으로 쓰는 서버에서 통계를 확인하면 시스템이 멈출 수 있는 문제입니다. 불필요한 잠금 대기를 제거해 이 멈춤을 막았습니다.
🇺🇸 원문 (English)
In the Linux kernel, the following vulnerability has been resolved:
net: hinic: avoid kernel hung in hinic_get_stats64()
When using hinic device as a bond slave device, and reading device stats
of master bond device, the kernel may hung.
The kernel panic calltrace as follows:
Kernel panic - not syncing: softlockup: hung tasks
Call trace:
native_queued_spin_lock_slowpath+0x1ec/0x31c
dev_get_stats+0x60/0xcc
dev_seq_printf_stats+0x40/0x120
dev_seq_show+0x1c/0x40
seq_read_iter+0x3c8/0x4dc
seq_read+0xe0/0x130
proc_reg_read+0xa8/0xe0
vfs_read+0xb0/0x1d4
ksys_read+0x70/0xfc
__arm64_sys_read+0x20/0x30
el0_svc_common+0x88/0x234
do_el0_svc+0x2c/0x90
el0_svc+0x1c/0x30
el0_sync_handler+0xa8/0xb0
el0_sync+0x148/0x180
And the calltrace of task that actually caused kernel hungs as follows:
__switch_to+124
__schedule+548
schedule+72
schedule_timeout+348
__down_common+188
__down+24
down+104
hinic_get_stats64+44 [hinic]
dev_get_stats+92
bond_get_stats+172 [bonding]
dev_get_stats+92
dev_seq_printf_stats+60
dev_seq_show+24
seq_read_iter+964
seq_read+220
proc_reg_read+164
vfs_read+172
ksys_read+108
__arm64_sys_read+28
el0_svc_common+132
do_el0_svc+40
el0_svc+24
el0_sync_handler+164
el0_sync+324
When getting device stats from bond, kernel will call bond_get_stats().
It first holds the spinlock bond->stats_lock, and then call
hinic_get_stats64() to collect hinic device's stats.
However, hinic_get_stats64() calls `down(&nic_dev->mgmt_lock)` to
protect its critical section, which may schedule current task out.
And if system is under high pressure, the task cannot be woken up
immediately, which eventually triggers kernel hung panic.
Since previous patch has replaced hinic_dev.tx_stats/rx_stats with local
variable in hinic_get_stats64(), there is nothing need to be protected
by lock, so just removing down()/up() is ok.
📍 영향받는 시스템
Linux 커널 hinic 네트워크 드라이버를 사용하고 bonding 슬레이브로 구성한 시스템 (수정 커밋 이전 커널 버전)
⚔️ 공격 벡터
로컬 사용자가 /proc 등에서 bond 장치 통계를 반복 조회하여 커널 락업(서비스 거부)을 유발할 수 있음
🛡️ 대응 방법
Linux 커널을 해당 취약점 수정이 포함된 최신 안정 버전으로 업데이트하거나 배포판 보안 패치를 적용
🔧 검증 코드
커널 버전이 수정 패치가 배포된 배포판 업데이트 버전 이상인지 확인하고, hinic 모듈이 없으면 해당 드라이버를 사용하지 않는 것이므로 영향이 없음
uname -r && (modinfo hinic 2>/dev/null | grep -E '^(version|srcversion|filename)')