summaryrefslogtreecommitdiff
path: root/scripts/basic
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2026-11-02 06:42:30 +0000
committerAlexei Starovoitov <ast@kernel.org>2026-11-02 16:22:43 +0000
commit92b5ce3ca5b7c641e2678f92419aa7833951bc9d (patch)
treeaf80726e240fcc1bf05b3433d6872540c574097f /scripts/basic
parent5e96760b25fdedbbf9312827f1f237d6b18b03e8 (diff)
downloadlinux-92b5ce3ca5b7c641e2678f92419aa7833951bc9d.tar.gz
linux-92b5ce3ca5b7c641e2678f92419aa7833951bc9d.zip
bpf: Don't move a MAP_FIXED address in arena_get_unmapped_area()
The user range of an arena must not cross a 4 GiB boundary. Thus arena_get_unmapped_area() asks the mm for 2 * len bytes and rounds the result up if necessary. This is correct only if the mm finds a free range. With MAP_FIXED the mm does no search and returns addr. For MAP_FIXED_NOREPLACE, do_mmap() also sets MAP_FIXED. With MAP_FIXED the arena is not at addr after round_up(). Thus mmap() removes mappings outside the range from addr to addr + len. It keeps a part of those in this range. Also, round_up() can wrap to address 0, and the test for address 0 is before it. The arch code gets twice the length of the mapping. Thus it can refuse a valid MAP_FIXED range. On s390 the arch code also grows the page table for the range. With the double length it can omit this step for a valid range. The test for a crossing is not exact. Because ret is a long, ret >> 32 extends the sign, but the other side is unsigned. The sides are never equal for an address with bit 63 set, and round_up() always runs. Such user addresses exist on s390. arena_map_alloc() does the same test with a u64. With MAP_FIXED, pass len to the mm. Return -EINVAL if the range crosses a boundary, as for address 0. Make ret unsigned, so that only these ranges get the error. On x86-64, if round_up() gives address 0 today, mmap() now fails with -EINVAL or with -ENOMEM from the mm. Today mmap() can also fail for the address after round_up(), for example with -ENOMEM, -EEXIST, -EPERM or -EBUSY. Without MAP_FIXED the mm must still find a free range of 2 * len bytes inside the address space of the task. The range after round_up() is inside it, and round_up() cannot wrap. An address with bit 63 set now moves only if its range crosses a boundary. For an arena, libbpf uses MAP_FIXED only with map_extra, and arena_map_alloc() refuses a map_extra range that crosses a boundary. A subsequent mmap() must use the range of the first mmap(). For mmap() of the map fd, this range comes from arena_get_unmapped_area(), thus it crosses no boundary. arena_map_alloc() still accepts a map_extra above TASK_SIZE, and mmap() of such an arena fails. Fixes: 317460317a02 ("bpf: Introduce bpf_arena.") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20261102064231.2153879-2-alexei.starovoitov@gmail.com
Diffstat (limited to 'scripts/basic')
0 files changed, 0 insertions, 0 deletions