bpf: Call free_htab_elem() after htab_unlock_bucket()
The issue arises when a map is removed from the htab, which may hold the last reference of the map. The bpf_map_fd_put_ptr() function is invoked while holding a bucket lock (raw_spin_lock_t), and an attempt to acquire map_idr_lock (spinlock_t) is made, triggering a lockdep warning.
The warning can be resolved by invoking htab_put_fd_value() after htab_unlock_bucket(). However, merely deferring the invocation of htab_put_fd_value() isn't enough, as the old map pointers in the htab of maps cannot be saved during batched deletion. Instead, we also need to defer the invocation of free_htab_elem().
alloc_htab_elem() (through htab_put_fd_value())
The invocation of htab_put_fd_value() can be moved after htab_unlock_bucket(). To do this, save the map pointer of the old element for htabs of maps before unlocking the bucket, and release the map_ptr after the unlock.
free_htab_elem() (through htab_put_fd_value())
It's called by __htab_map_lookup_and_delete_elem(), htab_map_delete_elem(), and __htab_map_lookup_and_delete_batch().
For htab_map_delete_elem(), invoke free_htab_elem() after htab_unlock_bucket(). For __htab_map_lookup_and_delete_batch(), link the to-be-freed element into the node_to_free list and invoke free_htab_elem() for these elements after unlocking. The elements that have been removed from the hash list can be reused safely.
To fix the lockdep warning, use the following patch
...
+ htab_elem_set_map_ptr(elem, new_map_ptr);
+ htab_unlock_bucket(htab, h);
+ /* link to-be-freed htab_elem */
+ htab_elem->batch_flink = node_to_free;
+ node_to_free = htab_elem;
...
Conclusion
By applying the above mentioned changes in the Linux kernel, the vulnerability CVE-2024-56592 involving bpf_map_fd_put_ptr() and htab_unlock_bucket() is resolved. This prevents any further lockdep warnings being triggered when dealing with htabs of maps.
The original patch for this vulnerability can be found at the following link
Additional references
- Linux Kernel Mailing List (LKML)
- Red Hat Bugzilla
Timeline
Published on: 12/27/2024 15:15:18 UTC
Last modified on: 01/20/2025 06:23:43 UTC