CVE-2024-56592 in Linux
요약
\~에 의해 VulDB • 2026. 05. 30.
리눅스 커널에서 다음 취약점이 해결되었습니다:
bpf: htab_unlock_bucket() 이후 free_htab_elem() 호출
맵의 htab의 경우, 맵이 htab에서 제거될 때 맵의 마지막 참조를 유지할 수 있습니다. bpf_map_fd_put_ptr()는 제거된 맵 요소의 ID를 해제하기 위해 bpf_map_free_id()를 호출합니다. 그러나 bpf_map_fd_put_ptr()는 bucket lock(raw_spin_lock_t)을 획득한 상태에서 호출되며, bpf_map_free_id()는 map_idr_lock(spinlock_t)을 획득하려고 시도하여 다음 lockdep 경고를 트리거합니다:
============================= [ BUG: Invalid wait context ]
6.11.0-rc4+ #49 Not tainted ----------------------------- test_maps/4881 is trying to lock: ffffffff84884578 (map_idr_lock){+...}-{3:3}, at: bpf_map_free_id.part.0+0x21/0x70
other info that might help us debug this: context-{5:5}
2 locks held by test_maps/4881: #0: ffffffff846caf60 (rcu_read_lock){....}-{1:3}, at: bpf_fd_htab_map_update_elem+0xf9/0x270
#1: ffff888149ced148 (&htab->lockdep_key#2){....}-{2:2}, at: htab_map_update_elem+0x178/0xa80
stack backtrace: CPU: 0 UID: 0 PID: 4881 Comm: test_maps Not tainted 6.11.0-rc4+ #49 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x59/0x80 dump_stack+0x10/0x18 __lock_acquire+0x1338/0x26f0 lock_acquire+0x119/0x3a0 _raw_spin_lock+0x45/0x60 x64_sys_bpf+0x45/0x60 x64_sys_call+0x1b2a/0x20d0 do_syscall_64+0x5d/0x100 entry_SYSCALL_64_after_hwframe+0x76/0x7e
map_idr_lock을 raw_spinlock_t로 변경하여 lockdep 경고를 해결할 수 있습니다. 그러나 bpf_map_alloc_id()는 map_idr_lock을 획득한 후 idr_alloc_cyclic()를 호출하며, 이는 슬랩의 잠금(s->cpu_slab->lock)이 여전히 spinlock이므로 유사한 lockdep 경고를 트리거합니다.
map_idr_lock의 타입을 변경하는 대신, htab_unlock_bucket() 이후 htab_put_fd_value()를 호출하여 문제를 해결합니다. 그러나 htab_put_fd_value() 호출만 지연시키는 것은 충분하지 않습니다. 배치 삭제 중 htab의 맵에서 이전 맵 포인터를 저장할 수 없기 때문입니다. 따라서 free_htab_elem() 호출도 지연시켜, 이러한 해제 대상 요소들을 LRU 맵과 유사하게 연결할 수 있습니다.
->map_fd_put_ptr()를 호출하는 호출자는 다음과 같습니다:
(1) alloc_htab_elem() (htab_put_fd_value()를 통해) raw_spinlock_t를 획득한 상태에서 ->map_fd_put_ptr()를 호출합니다. htab_put_fd_value() 호출을 htab_unlock_bucket() 이후로 단순히 이동할 수 없습니다. 이전 요소가 이미 htab->extra_elems에 저장되어 있기 때문입니다. htab_unlock_bucket() 이후에 즉시 재사용될 수 있으며, htab_unlock_bucket() 이후에 htab_put_fd_value()를 호출하면 새로 추가된 요소를 잘못 해제할 수 있습니다. 따라서 버킷을 잠금 해제하기 전에 htab의 맵에 대한 이전 요소의 맵 포인터를 저장하고, 잠금 해제 후 map_ptr을 해제합니다. 이전 요소의 맵 포인터 외에도 이전 요소의 특수 필드에 대해서도 동일한 작업을 수행해야 합니다.
(2) free_htab_elem() (htab_put_fd_value()를 통해) 호출자에는 __htab_map_lookup_and_delete_elem(), htab_map_delete_elem(), __htab_map_lookup_and_delete_batch()가 포함됩니다.
htab_map_delete_elem()의 경우, htab_unlock_bucket() 이후 free_htab_elem()을 단순히 호출합니다. __htab_map_lookup_and_delete_batch()의 경우, LRU 맵과 마찬가지로 해제 대상 요소를 node_to_free 목록에 연결하고 잠금 해제 후 이러한 요소에 대해 free_htab_elem()을 호출합니다. 이러한 요소들은 해시 llist에서 제거되었으므로 batch_flink를 node_to_free의 링크로 안전하게 재사용할 수 있습니다.
htab의 맵은 lookup_and_delete 연산을 지원하지 않으므로, __htab_map_lookup_and_delete_elem()에는 문제가 없습니다.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.