diff options
author | Akihiko Odaki <akihiko.odaki@daynix.com> | 2023-08-02 16:17:48 +0900 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-08-06 10:10:11 -0700 |
commit | ddcdd8c48fc48b2d528756fc98f1ce0ec3d7b617 (patch) | |
tree | c1680ace1ec56ab7c0c2c97596907b6e3fccbb84 /linux-user/mmap.c | |
parent | c3dd50da0f4d00fffe8ea5e211c2c189fe6ad4fb (diff) |
linux-user: Fix MAP_FIXED_NOREPLACE on old kernels
The man page states:
> Note that older kernels which do not recognize the MAP_FIXED_NOREPLACE
> flag will typically (upon detecting a collision with a preexisting
> mapping) fall back to a “non-MAP_FIXED” type of behavior: they will
> return an address that is different from the requested address.
> Therefore, backward-compatible software should check the returned
> address against the requested address.
https://man7.org/linux/man-pages/man2/mmap.2.html
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Message-Id: <20230802071754.14876-3-akihiko.odaki@daynix.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'linux-user/mmap.c')
-rw-r--r-- | linux-user/mmap.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/linux-user/mmap.c b/linux-user/mmap.c index a11c630a7b..90b3ef2140 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -263,7 +263,11 @@ static bool mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong last, void *p = mmap(host_start, qemu_host_page_size, target_to_host_prot(prot), flags | MAP_ANONYMOUS, -1, 0); - if (p == MAP_FAILED) { + if (p != host_start) { + if (p != MAP_FAILED) { + munmap(p, qemu_host_page_size); + errno = EEXIST; + } return false; } prot_old = prot; @@ -687,17 +691,25 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, /* map the middle (easier) */ if (real_start < real_last) { - void *p; + void *p, *want_p; off_t offset1; + size_t len1; if (flags & MAP_ANONYMOUS) { offset1 = 0; } else { offset1 = offset + real_start - start; } - p = mmap(g2h_untagged(real_start), real_last - real_start + 1, - target_to_host_prot(target_prot), flags, fd, offset1); - if (p == MAP_FAILED) { + len1 = real_last - real_start + 1; + want_p = g2h_untagged(real_start); + + p = mmap(want_p, len1, target_to_host_prot(target_prot), + flags, fd, offset1); + if (p != want_p) { + if (p != MAP_FAILED) { + munmap(p, len1); + errno = EEXIST; + } goto fail; } passthrough_start = real_start; |