cve/2024/CVE-2024-45025.md
2025-09-29 21:09:30 +02:00

2.9 KiB

CVE-2024-45025

Description

In the Linux kernel, the following vulnerability has been resolved:fix bitmap corruption on close_range() with CLOSE_RANGE_UNSHAREcopy_fd_bitmaps(new, old, count) is expected to copy the firstcount/BITS_PER_LONG bits from old->full_fds_bits[] and fillthe rest with zeroes. What it does is copying enough words(BITS_TO_LONGS(count/BITS_PER_LONG)), then memsets the rest.That works fine, if all bits past the cutoff point areclear. Otherwise we are risking garbage from the last wordwe'd copied.For most of the callers that is true - expand_fdtable() hascount equal to old->max_fds, so there's no open descriptorspast count, let alone fully occupied words in ->open_fds[],which is what bits in ->full_fds_bits[] correspond to.The other caller (dup_fd()) passes sane_fdtable_size(old_fdt, max_fds),which is the smallest multiple of BITS_PER_LONG that covers allopened descriptors below max_fds. In the common case (copying onfork()) max_fds is ~0U, so all opened descriptors will be belowit and we are fine, by the same reasons why the call in expand_fdtable()is safe.Unfortunately, there is a case where max_fds is less than thatand where we might, indeed, end up with junk in ->full_fds_bits[] -close_range(from, to, CLOSE_RANGE_UNSHARE) with * descriptor table being currently shared * 'to' being above the current capacity of descriptor table * 'from' being just under some chunk of opened descriptors.In that case we end up with observably wrong behaviour - e.g. spawna child with CLONE_FILES, get all descriptors in range 0..127 open,then close_range(64, ~0U, CLOSE_RANGE_UNSHARE) and watch dup(0) endingup with descriptor #128, despite #64 being observably not open.The minimally invasive fix would be to deal with that in dup_fd().If this proves to add measurable overhead, we can go that way, butlet's try to fix copy_fd_bitmaps() first.* new helper: bitmap_copy_and_expand(to, from, bits_to_copy, size).* make copy_fd_bitmaps() take the bitmap size in words, rather thanbits; it's 'count' argument is always a multiple of BITS_PER_LONG,so we are not losing any information, and that way we can use thesame helper for all three bitmaps - compiler will see that countis a multiple of BITS_PER_LONG for the large ones, so it'll generateplain memcpy()+memset().Reproducer added to tools/testing/selftests/core/close_range_test.c

POC

Reference

No PoCs from references.

Github