| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2024-41009: bpf: Fix overrunning reservations in ringbuf |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| bpf: Fix overrunning reservations in ringbuf |
| |
| The BPF ring buffer internally is implemented as a power-of-2 sized circular |
| buffer, with two logical and ever-increasing counters: consumer_pos is the |
| consumer counter to show which logical position the consumer consumed the |
| data, and producer_pos which is the producer counter denoting the amount of |
| data reserved by all producers. |
| |
| Each time a record is reserved, the producer that "owns" the record will |
| successfully advance producer counter. In user space each time a record is |
| read, the consumer of the data advanced the consumer counter once it finished |
| processing. Both counters are stored in separate pages so that from user |
| space, the producer counter is read-only and the consumer counter is read-write. |
| |
| One aspect that simplifies and thus speeds up the implementation of both |
| producers and consumers is how the data area is mapped twice contiguously |
| back-to-back in the virtual memory, allowing to not take any special measures |
| for samples that have to wrap around at the end of the circular buffer data |
| area, because the next page after the last data page would be first data page |
| again, and thus the sample will still appear completely contiguous in virtual |
| memory. |
| |
| Each record has a struct bpf_ringbuf_hdr { u32 len; u32 pg_off; } header for |
| book-keeping the length and offset, and is inaccessible to the BPF program. |
| Helpers like bpf_ringbuf_reserve() return `(void *)hdr + BPF_RINGBUF_HDR_SZ` |
| for the BPF program to use. Bing-Jhong and Muhammad reported that it is however |
| possible to make a second allocated memory chunk overlapping with the first |
| chunk and as a result, the BPF program is now able to edit first chunk's |
| header. |
| |
| For example, consider the creation of a BPF_MAP_TYPE_RINGBUF map with size |
| of 0x4000. Next, the consumer_pos is modified to 0x3000 /before/ a call to |
| bpf_ringbuf_reserve() is made. This will allocate a chunk A, which is in |
| [0x0,0x3008], and the BPF program is able to edit [0x8,0x3008]. Now, lets |
| allocate a chunk B with size 0x3000. This will succeed because consumer_pos |
| was edited ahead of time to pass the `new_prod_pos - cons_pos > rb->mask` |
| check. Chunk B will be in range [0x3008,0x6010], and the BPF program is able |
| to edit [0x3010,0x6010]. Due to the ring buffer memory layout mentioned |
| earlier, the ranges [0x0,0x4000] and [0x4000,0x8000] point to the same data |
| pages. This means that chunk B at [0x4000,0x4008] is chunk A's header. |
| bpf_ringbuf_submit() / bpf_ringbuf_discard() use the header's pg_off to then |
| locate the bpf_ringbuf itself via bpf_ringbuf_restore_from_rec(). Once chunk |
| B modified chunk A's header, then bpf_ringbuf_commit() refers to the wrong |
| page and could cause a crash. |
| |
| Fix it by calculating the oldest pending_pos and check whether the range |
| from the oldest outstanding record to the newest would span beyond the ring |
| buffer size. If that is the case, then reject the request. We've tested with |
| the ring buffer benchmark in BPF selftests (./benchs/run_bench_ringbufs.sh) |
| before/after the fix and while it seems a bit slower on some benchmarks, it |
| is still not significantly enough to matter. |
| |
| The Linux kernel CVE team has assigned CVE-2024-41009 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 5.10.223 with commit be35504b959f2749bab280f4671e8df96dcf836f |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 5.15.164 with commit 0f98f40eb1ed52af8b81f61901b6c0289ff59de4 |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 6.1.97 with commit d1b9df0435bc61e0b44f578846516df8ef476686 |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 6.6.37 with commit 511804ab701c0503b72eac08217eabfd366ba069 |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 6.9.8 with commit 47416c852f2a04d348ea66ee451cbdcf8119f225 |
| Issue introduced in 5.8 with commit 457f44363a8894135c85b7a9afd2bd8196db24ab and fixed in 6.10 with commit cfa1a2329a691ffd991fcf7248a57d752e712881 |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2024-41009 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| kernel/bpf/ringbuf.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/be35504b959f2749bab280f4671e8df96dcf836f |
| https://git.kernel.org/stable/c/0f98f40eb1ed52af8b81f61901b6c0289ff59de4 |
| https://git.kernel.org/stable/c/d1b9df0435bc61e0b44f578846516df8ef476686 |
| https://git.kernel.org/stable/c/511804ab701c0503b72eac08217eabfd366ba069 |
| https://git.kernel.org/stable/c/47416c852f2a04d348ea66ee451cbdcf8119f225 |
| https://git.kernel.org/stable/c/cfa1a2329a691ffd991fcf7248a57d752e712881 |