A critical vulnerability in the Linux kernel has been resolved, which previously led to incorrect handling of faulty array blocks in the 'dm array' and resulted in unstable behavior. The issue specifically lies in the dm_array_cursor_end function, where a faulty array block was released twice due to an implicit release by dm_bm_read_lock() function when it encounters locking or checksum errors. This caused the dm_array_cursor to cache the invalid pointer and led to a double release in dm_array_cursor_end(), eventually triggering the BUG_ON in dm-bufio cache_put().
This blog post will provide a brief overview of the vulnerability, steps to reproduce it on the affected Linux kernel, and information about the fix that has been implemented.
Initialize a cache device with the following commands
dmsetup create cmeta --table " 8192 linear /dev/sdc "
dmsetup create cdata --table " 65536 linear /dev/sdc 8192"
dmsetup create corig --table " 524288 linear /dev/sdc $262144"
dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1
dmsetup create cache --table " 524288 cache /dev/mapper/cmeta \
/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq "
Wipe the second array block offline with these commands
dmsteup remove cache cmeta cdata corig
mapping_root=$(dd if=/dev/sdc bs=1c count=8 skip=192 \
2>/dev/null | hexdump -e '1/8 "%u\n"')
ablock=$(dd if=/dev/sdc bs=1c count=8 skip=$((4096*mapping_root+2056)) \
2>/dev/null | hexdump -e '1/8 "%u\n"')
dd if=/dev/zero of=/dev/sdc bs=4k count=1 seek=$ablock
Try reopening the cache device with the following commands
dmsetup create cmeta --table " 8192 linear /dev/sdc "
dmsetup create cdata --table " 65536 linear /dev/sdc 8192"
dmsetup create corig --table " 524288 linear /dev/sdc $262144"
dmsetup create cache --table " 524288 cache /dev/mapper/cmeta \
/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq "
If the vulnerability is present, you should see the following kernel logs
(snip)
device-mapper: array: array_block_check failed: blocknr != wanted 10
device-mapper: block manager: array validator check failed for block 10
device-mapper: array: get_ablock failed
device-mapper: cache metadata: dm_array_cursor_next for mapping failed
------------[ cut here ]------------
kernel BUG at drivers/md/dm-bufio.c:638!
Fix Details
The vulnerability was fixed by setting the cached block pointer to NULL on errors to prevent caching the invalid pointer. As a result, the double release in dm_array_cursor_end() should no longer occur.
Verification
To verify that the fix is applied correctly, you can run the "array_cursor/damaged" test in dm-unit with the following command:
dm-unit run /pdata/array_cursor/damaged --kernel-dir <KERNEL_DIR>
Conclusion
With the resolution of CVE-2024-57929, Linux kernel users can now avoid encountering this severe vulnerability in the 'dm array'. By properly handling faulty array blocks and preventing double releases, system stability is improved, and dm_array_cursor_end() functions correctly.
We would like to thank the developers and maintainers of the Linux kernel for their diligence in identifying and fixing this vulnerability.
Original References
- Linux Kernel Mailing List
- Github Commit Fix
Timeline
Published on: 01/19/2025 12:15:27 UTC
Last modified on: 02/02/2025 11:15:14 UTC