* [PATCH v2] linux-user: Fix mremap() with old_size == 0
@ 2026-02-01 1:03 Razvan Ghiorghe
2026-02-04 3:34 ` Richard Henderson
2026-03-03 19:01 ` razvan ghiorghe
0 siblings, 2 replies; 6+ messages in thread
From: Razvan Ghiorghe @ 2026-02-01 1:03 UTC (permalink / raw)
To: qemu-devel, laurent, razvanghiorghe16
When old_size is zero and old_address refers to a shareable mapping,
mremap() should create a new mapping of the same pages according to the
mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
Previously, QEMU's target_mremap() rejected this valid case with EFAULT during
the initial validation, before checking for the special old_size == 0 behaviour.
This patch adds proper handling for old_size == 0:
- Validates that MREMAP_MAYMOVE flag is set (required by man spec)
- Passes the call through to the host mremap()
- Creates a new mapping without invalidating the original, with both
beeing valid and sharing the same physical memory frames.
Tested with the reproducer from the issue on qemu-riscv64.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105
Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
---
linux-user/mmap.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 4bcfaf7894..b1a84eb60a 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -1117,6 +1117,38 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
errno = EINVAL;
return -1;
}
+
+ if (!old_size) {
+ if (!(flags & MREMAP_MAYMOVE)) {
+ errno = EINVAL;
+ return -1;
+ }
+ mmap_lock();
+ if (flags & MREMAP_FIXED) {
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags, g2h_untagged(new_addr));
+ } else {
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags);
+ }
+
+ if (host_addr == MAP_FAILED) {
+ mmap_unlock();
+ return -1;
+ }
+ new_addr = h2g(host_addr);
+ prot = page_get_flags(old_addr);
+ /*
+ * For old_size zero, there is nothing to clear at old_addr.
+ * Only set the flags for the new mapping. They both are valid.
+ */
+ page_set_flags(new_addr, new_addr + new_size - 1,
+ prot | PAGE_VALID, PAGE_VALID);
+ shm_region_rm_complete(new_addr, new_addr + new_size - 1);
+ mmap_unlock();
+ return new_addr;
+ }
+
if (!guest_range_valid_untagged(old_addr, old_size)) {
errno = EFAULT;
return -1;
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] linux-user: Fix mremap() with old_size == 0
2026-02-01 1:03 [PATCH v2] linux-user: Fix mremap() with old_size == 0 Razvan Ghiorghe
@ 2026-02-04 3:34 ` Richard Henderson
2026-03-03 19:01 ` razvan ghiorghe
1 sibling, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2026-02-04 3:34 UTC (permalink / raw)
To: qemu-devel
On 2/1/26 11:03, Razvan Ghiorghe wrote:
> When old_size is zero and old_address refers to a shareable mapping,
> mremap() should create a new mapping of the same pages according to the
> mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
> Previously, QEMU's target_mremap() rejected this valid case with EFAULT during
> the initial validation, before checking for the special old_size == 0 behaviour.
>
> This patch adds proper handling for old_size == 0:
> - Validates that MREMAP_MAYMOVE flag is set (required by man spec)
> - Passes the call through to the host mremap()
> - Creates a new mapping without invalidating the original, with both
> beeing valid and sharing the same physical memory frames.
>
> Tested with the reproducer from the issue on qemu-riscv64.
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105
> Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
> ---
> linux-user/mmap.c | 32 ++++++++++++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
>
> diff --git a/linux-user/mmap.c b/linux-user/mmap.c
> index 4bcfaf7894..b1a84eb60a 100644
> --- a/linux-user/mmap.c
> +++ b/linux-user/mmap.c
> @@ -1117,6 +1117,38 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
> errno = EINVAL;
> return -1;
> }
> +
> + if (!old_size) {
> + if (!(flags & MREMAP_MAYMOVE)) {
> + errno = EINVAL;
> + return -1;
> + }
> + mmap_lock();
> + if (flags & MREMAP_FIXED) {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags, g2h_untagged(new_addr));
> + } else {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags);
> + }
This probably doesn't work with host page size != target page size.
The non-FIXED path doesn't work with reserved_va, as qemu needs to handle the address
space itself for that case. See the top of target_mmap__locked.
> +
> + if (host_addr == MAP_FAILED) {
> + mmap_unlock();
> + return -1;
> + }
> + new_addr = h2g(host_addr);
> + prot = page_get_flags(old_addr);
> + /*
> + * For old_size zero, there is nothing to clear at old_addr.
> + * Only set the flags for the new mapping. They both are valid.
> + */
> + page_set_flags(new_addr, new_addr + new_size - 1,
> + prot | PAGE_VALID, PAGE_VALID);
> + shm_region_rm_complete(new_addr, new_addr + new_size - 1);
Don't you need to copy the shm data?
Tracing all this through linux/mm/mremap.c is non-trivial...
r~
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] linux-user: Fix mremap() with old_size == 0
2026-02-01 1:03 [PATCH v2] linux-user: Fix mremap() with old_size == 0 Razvan Ghiorghe
2026-02-04 3:34 ` Richard Henderson
@ 2026-03-03 19:01 ` razvan ghiorghe
2026-03-07 19:13 ` Helge Deller
1 sibling, 1 reply; 6+ messages in thread
From: razvan ghiorghe @ 2026-03-03 19:01 UTC (permalink / raw)
To: qemu-devel, laurent, razvanghiorghe16
[-- Attachment #1: Type: text/plain, Size: 2980 bytes --]
Hi,
I'd like to kindly ping this patch. It has been a few weeks since
submission and I haven't received any feedback yet.
I'm working on getting familiar with the contribution flux. Any review,
even brief comments on the approach would be very helpful!
Thanks in advance,
Razvan
În dum., 1 feb. 2026 la 03:08, Razvan Ghiorghe <razvanghiorghe16@gmail.com>
a scris:
> When old_size is zero and old_address refers to a shareable mapping,
> mremap() should create a new mapping of the same pages according to the
> mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
> Previously, QEMU's target_mremap() rejected this valid case with EFAULT
> during
> the initial validation, before checking for the special old_size == 0
> behaviour.
>
> This patch adds proper handling for old_size == 0:
> - Validates that MREMAP_MAYMOVE flag is set (required by man spec)
> - Passes the call through to the host mremap()
> - Creates a new mapping without invalidating the original, with both
> beeing valid and sharing the same physical memory frames.
>
> Tested with the reproducer from the issue on qemu-riscv64.
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105
> Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
> ---
> linux-user/mmap.c | 32 ++++++++++++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
>
> diff --git a/linux-user/mmap.c b/linux-user/mmap.c
> index 4bcfaf7894..b1a84eb60a 100644
> --- a/linux-user/mmap.c
> +++ b/linux-user/mmap.c
> @@ -1117,6 +1117,38 @@ abi_long target_mremap(abi_ulong old_addr,
> abi_ulong old_size,
> errno = EINVAL;
> return -1;
> }
> +
> + if (!old_size) {
> + if (!(flags & MREMAP_MAYMOVE)) {
> + errno = EINVAL;
> + return -1;
> + }
> + mmap_lock();
> + if (flags & MREMAP_FIXED) {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags, g2h_untagged(new_addr));
> + } else {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags);
> + }
> +
> + if (host_addr == MAP_FAILED) {
> + mmap_unlock();
> + return -1;
> + }
> + new_addr = h2g(host_addr);
> + prot = page_get_flags(old_addr);
> + /*
> + * For old_size zero, there is nothing to clear at old_addr.
> + * Only set the flags for the new mapping. They both are valid.
> + */
> + page_set_flags(new_addr, new_addr + new_size - 1,
> + prot | PAGE_VALID, PAGE_VALID);
> + shm_region_rm_complete(new_addr, new_addr + new_size - 1);
> + mmap_unlock();
> + return new_addr;
> + }
> +
> if (!guest_range_valid_untagged(old_addr, old_size)) {
> errno = EFAULT;
> return -1;
> --
> 2.43.0
>
>
[-- Attachment #2: Type: text/html, Size: 3816 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] linux-user: Fix mremap() with old_size == 0
2026-03-03 19:01 ` razvan ghiorghe
@ 2026-03-07 19:13 ` Helge Deller
2026-03-09 23:30 ` [PATCH v3] linux-user: fix mremap with old_size=0 for shared mappings Razvan Ghiorghe
0 siblings, 1 reply; 6+ messages in thread
From: Helge Deller @ 2026-03-07 19:13 UTC (permalink / raw)
To: razvan ghiorghe, qemu-devel, laurent
Hello Razvan,
On 3/3/26 20:01, razvan ghiorghe wrote:
> Hi,
> I'd like to kindly ping this patch. It has been a few weeks since submission and I haven't received any feedback yet.
> I'm working on getting familiar with the contribution flux. Any review, even brief comments on the approach would be very helpful!
First of all, I could not find the "v2" version of your patch.
It's not in the qemu mail archives, only in your mail below.
Did you sent a v2 version at all?
More importantly, I can confirm with the testcase from https://gitlab.com/qemu-project/qemu/-/issues/3105,
that the problem exists.
Testcase works on a physical hppa box, but fails in qemu-linux-user.
The patch seems ok, but it did not work for me.
Without your patch:
(hppa-chroot)root@p100:/# ./a.out
mremap with old_size=0 failed: Bad address
-> problem exists as you described.
With your patch:
(hppa-chroot)root@p100:/# ./a.out
qemu-hppa-static: ../../qemu/linux-user/mmap.c:1142: target_mremap: Assertion `h2g_valid(host_addr)' failed.
Aborted (core dumped) ./a.out
More info:
(hppa-chroot)root@p100:/# QEMU_LOG=strace ./a.out
...
7087 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0) = 0x45214000
7087 mremap(1159806976,0,8192,1,0,1159087572)
qemu-hppa-static: ../../qemu/linux-user/mmap.c:1142: target_mremap: Assertion `h2g_valid(host_addr)' failed.
Aborted (core dumped) QEMU_LOG=strace ./a.out
Helge
> Thanks in advance,
> Razvan
>
> În dum., 1 feb. 2026 la 03:08, Razvan Ghiorghe <razvanghiorghe16@gmail.com <mailto:razvanghiorghe16@gmail.com>> a scris:
>
> When old_size is zero and old_address refers to a shareable mapping,
> mremap() should create a new mapping of the same pages according to the
> mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
> Previously, QEMU's target_mremap() rejected this valid case with EFAULT during
> the initial validation, before checking for the special old_size == 0 behaviour.
>
> This patch adds proper handling for old_size == 0:
> - Validates that MREMAP_MAYMOVE flag is set (required by man spec)
> - Passes the call through to the host mremap()
> - Creates a new mapping without invalidating the original, with both
> beeing valid and sharing the same physical memory frames.
>
> Tested with the reproducer from the issue on qemu-riscv64.
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105 <https://gitlab.com/qemu-project/qemu/-/issues/3105>
> Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com <mailto:razvanghiorghe16@gmail.com>>
> ---
> linux-user/mmap.c | 32 ++++++++++++++++++++++++++++++++
> 1 file changed, 32 insertions(+)
>
> diff --git a/linux-user/mmap.c b/linux-user/mmap.c
> index 4bcfaf7894..b1a84eb60a 100644
> --- a/linux-user/mmap.c
> +++ b/linux-user/mmap.c
> @@ -1117,6 +1117,38 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
> errno = EINVAL;
> return -1;
> }
> +
> + if (!old_size) {
> + if (!(flags & MREMAP_MAYMOVE)) {
> + errno = EINVAL;
> + return -1;
> + }
> + mmap_lock();
> + if (flags & MREMAP_FIXED) {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags, g2h_untagged(new_addr));
> + } else {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags);
> + }
> +
> + if (host_addr == MAP_FAILED) {
> + mmap_unlock();
> + return -1;
> + }
> + new_addr = h2g(host_addr);
> + prot = page_get_flags(old_addr);
> + /*
> + * For old_size zero, there is nothing to clear at old_addr.
> + * Only set the flags for the new mapping. They both are valid.
> + */
> + page_set_flags(new_addr, new_addr + new_size - 1,
> + prot | PAGE_VALID, PAGE_VALID);
> + shm_region_rm_complete(new_addr, new_addr + new_size - 1);
> + mmap_unlock();
> + return new_addr;
> + }
> +
> if (!guest_range_valid_untagged(old_addr, old_size)) {
> errno = EFAULT;
> return -1;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3] linux-user: fix mremap with old_size=0 for shared mappings
2026-03-07 19:13 ` Helge Deller
@ 2026-03-09 23:30 ` Razvan Ghiorghe
2026-03-12 20:01 ` Helge Deller
0 siblings, 1 reply; 6+ messages in thread
From: Razvan Ghiorghe @ 2026-03-09 23:30 UTC (permalink / raw)
To: qemu-devel; +Cc: helge.deller, laurent, Razvan Ghiorghe
When old_size is zero and old_address refers to a shareable mapping,
mremap() should create a new mapping of the same pages according to the
mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
Previously, QEMU's target_mremap() rejected this valid case with EFAULT
during the initial validation, before checking for the special
old_size == 0 behaviour.
This patch adds proper handling for old_size == 0:
- Validates that MREMAP_MAYMOVE flag is set (required by man spec)
- Passes the call through to the host mremap()
- Creates a new mapping without invalidating the original, with both
being valid and sharing the same physical memory frames.
- Ensures the new mapping address falls within the valid guest address
region before returning it to the guest.
Tested with the reproducer from the issue on qemu-riscv64, qemu-hppa,
and qemu-aarch64.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105
Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
Hi Heldge,
Thank you for testing and detailed feedback!
V3 fixes h2g_valid assertion failure on hppa by using mmap_find_vma()
to ensure the new mapping stays within the valid guest adress region
Tested on qemu-riscv64, qemu-hppa and qemu-aarch64.
---
linux-user/mmap.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 07175e11d5..b41308840a 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -1117,6 +1117,58 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
errno = EINVAL;
return -1;
}
+
+ if (!old_size) {
+ if (!(flags & MREMAP_MAYMOVE)) {
+ errno = EINVAL;
+ return -1;
+ }
+ mmap_lock();
+ if (flags & MREMAP_FIXED) {
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags, g2h_untagged(new_addr));
+ } else {
+ /*
+ * We ensure that the new mapping stands in the
+ * region of guest mappable addresses.
+ */
+ abi_ulong mmap_start;
+
+ mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);
+
+ if (mmap_start == -1) {
+ errno = ENOMEM;
+ mmap_unlock();
+ return -1;
+ }
+
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
+ flags | MREMAP_FIXED, g2h_untagged(mmap_start));
+
+ new_addr = mmap_start;
+ }
+
+ if (host_addr == MAP_FAILED) {
+ mmap_unlock();
+ return -1;
+ }
+
+ if (flags & MREMAP_FIXED) {
+ new_addr = h2g(host_addr);
+ }
+
+ prot = page_get_flags(old_addr);
+ /*
+ * For old_size zero, there is nothing to clear at old_addr.
+ * Only set the flags for the new mapping. They both are valid.
+ */
+ page_set_flags(new_addr, new_addr + new_size - 1,
+ prot | PAGE_VALID, PAGE_VALID);
+ shm_region_rm_complete(new_addr, new_addr + new_size - 1);
+ mmap_unlock();
+ return new_addr;
+ }
+
if (!guest_range_valid_untagged(old_addr, old_size)) {
errno = EFAULT;
return -1;
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3] linux-user: fix mremap with old_size=0 for shared mappings
2026-03-09 23:30 ` [PATCH v3] linux-user: fix mremap with old_size=0 for shared mappings Razvan Ghiorghe
@ 2026-03-12 20:01 ` Helge Deller
0 siblings, 0 replies; 6+ messages in thread
From: Helge Deller @ 2026-03-12 20:01 UTC (permalink / raw)
To: Razvan Ghiorghe, qemu-devel; +Cc: helge.deller, laurent
On 3/10/26 00:30, Razvan Ghiorghe wrote:
> When old_size is zero and old_address refers to a shareable mapping,
> mremap() should create a new mapping of the same pages according to the
> mremap(2) man page. The MREMAP_MAYMOVE flag must be specified in this case.
>
> Previously, QEMU's target_mremap() rejected this valid case with EFAULT
> during the initial validation, before checking for the special
> old_size == 0 behaviour.
>
> This patch adds proper handling for old_size == 0:
> - Validates that MREMAP_MAYMOVE flag is set (required by man spec)
> - Passes the call through to the host mremap()
> - Creates a new mapping without invalidating the original, with both
> being valid and sharing the same physical memory frames.
> - Ensures the new mapping address falls within the valid guest address
> region before returning it to the guest.
>
> Tested with the reproducer from the issue on qemu-riscv64, qemu-hppa,
> and qemu-aarch64.
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3105
> Signed-off-by: Razvan Ghiorghe <razvanghiorghe16@gmail.com>
>
> Hi Heldge,
> Thank you for testing and detailed feedback!
> V3 fixes h2g_valid assertion failure on hppa by using mmap_find_vma()
> to ensure the new mapping stays within the valid guest adress region
>
> Tested on qemu-riscv64, qemu-hppa and qemu-aarch64.
Seems correct.
Tested-by: Helge Deller <deller@gmx.de>
Reviewed-by: Helge Deller <deller@gmx.de>
Helge
> ---
> linux-user/mmap.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 52 insertions(+)
>
> diff --git a/linux-user/mmap.c b/linux-user/mmap.c
> index 07175e11d5..b41308840a 100644
> --- a/linux-user/mmap.c
> +++ b/linux-user/mmap.c
> @@ -1117,6 +1117,58 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
> errno = EINVAL;
> return -1;
> }
> +
> + if (!old_size) {
> + if (!(flags & MREMAP_MAYMOVE)) {
> + errno = EINVAL;
> + return -1;
> + }
> + mmap_lock();
> + if (flags & MREMAP_FIXED) {
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags, g2h_untagged(new_addr));
> + } else {
> + /*
> + * We ensure that the new mapping stands in the
> + * region of guest mappable addresses.
> + */
> + abi_ulong mmap_start;
> +
> + mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);
> +
> + if (mmap_start == -1) {
> + errno = ENOMEM;
> + mmap_unlock();
> + return -1;
> + }
> +
> + host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
> + flags | MREMAP_FIXED, g2h_untagged(mmap_start));
> +
> + new_addr = mmap_start;
> + }
> +
> + if (host_addr == MAP_FAILED) {
> + mmap_unlock();
> + return -1;
> + }
> +
> + if (flags & MREMAP_FIXED) {
> + new_addr = h2g(host_addr);
> + }
> +
> + prot = page_get_flags(old_addr);
> + /*
> + * For old_size zero, there is nothing to clear at old_addr.
> + * Only set the flags for the new mapping. They both are valid.
> + */
> + page_set_flags(new_addr, new_addr + new_size - 1,
> + prot | PAGE_VALID, PAGE_VALID);
> + shm_region_rm_complete(new_addr, new_addr + new_size - 1);
> + mmap_unlock();
> + return new_addr;
> + }
> +
> if (!guest_range_valid_untagged(old_addr, old_size)) {
> errno = EFAULT;
> return -1;
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-03-12 20:02 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-01 1:03 [PATCH v2] linux-user: Fix mremap() with old_size == 0 Razvan Ghiorghe
2026-02-04 3:34 ` Richard Henderson
2026-03-03 19:01 ` razvan ghiorghe
2026-03-07 19:13 ` Helge Deller
2026-03-09 23:30 ` [PATCH v3] linux-user: fix mremap with old_size=0 for shared mappings Razvan Ghiorghe
2026-03-12 20:01 ` Helge Deller
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.