* [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM @ 2026-09-03 14:27 Alex Bennée 2026-09-09 21:17 ` Helge Deller 0 siblings, 1 reply; 5+ messages in thread From: Alex Bennée @ 2026-09-03 14:27 UTC (permalink / raw) To: qemu-devel Cc: Alex Bennée, Laurent Vivier, Helge Deller, Pierrick Bouvier Per madvise(2) and the Linux kernel implementation (madvise_walk_vmas), madvise() must validate that the requested range is currently mapped and return -ENOMEM if any page in the range is unmapped. Add a page_check_range(start, len, PAGE_VALID) check for valid advice values before proceeding with the advice actions. In addition, extend the tcg multiarch test linux-madvise.c to test this behaviour. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4382 AI-used-for: importing and validating test case Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- NOTE - again testing the minimal agents which did stop and say: *(Note: Per user policy, git commits are never executed automatically by the agent. Please review the diff with `git diff` and commit the changes if you are satisfied.)* but non-the-less imported the test and wrote a crap patch which I have re-done dropping a load of unneeded verbosity. --- linux-user/mmap.c | 12 ++++++++++++ tests/tcg/multiarch/linux/linux-madvise.c | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/linux-user/mmap.c b/linux-user/mmap.c index cc0c2ee6c27..4066072ff45 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -1307,6 +1307,16 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) * though. */ mmap_lock(); + + /* + * Whatever advice if the pages are not currently mapped, or are + * outside the address space of the process. + */ + if (!page_check_range(start, len, PAGE_VALID)) { + ret = -TARGET_ENOMEM; + goto unlock; + } + switch (advice) { case MADV_NORMAL: case MADV_RANDOM: @@ -1358,6 +1368,8 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) ret = -EINVAL; /* not yet known advise */ break; } + + unlock: mmap_unlock(); return ret; diff --git a/tests/tcg/multiarch/linux/linux-madvise.c b/tests/tcg/multiarch/linux/linux-madvise.c index 539fb3b7726..ebb9666c919 100644 --- a/tests/tcg/multiarch/linux/linux-madvise.c +++ b/tests/tcg/multiarch/linux/linux-madvise.c @@ -1,4 +1,5 @@ #include <assert.h> +#include <errno.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> @@ -63,10 +64,29 @@ static void test_file(void) assert(ret == 0); } +static void test_unmapped(void) +{ + int pagesize = getpagesize(); + void *page; + int ret; + + page = mmap(NULL, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(page != MAP_FAILED); + + ret = munmap(page, pagesize); + assert(ret == 0); + + errno = 0; + ret = madvise(page, pagesize, MADV_NORMAL); + assert(ret == -1); + assert(errno == ENOMEM); +} + int main(void) { test_anonymous(); test_file(); + test_unmapped(); return EXIT_SUCCESS; } -- 2.47.3 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM 2026-09-03 14:27 [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM Alex Bennée @ 2026-09-09 21:17 ` Helge Deller 2026-09-10 10:09 ` Helge Deller 2026-09-10 10:16 ` Alex Bennée 0 siblings, 2 replies; 5+ messages in thread From: Helge Deller @ 2026-09-09 21:17 UTC (permalink / raw) To: Alex Bennée, qemu-devel; +Cc: Laurent Vivier, Pierrick Bouvier Hi Alex, On 9/3/26 16:27, Alex Bennée wrote: > Per madvise(2) and the Linux kernel implementation (madvise_walk_vmas), > madvise() must validate that the requested range is currently mapped > and return -ENOMEM if any page in the range is unmapped. > > Add a page_check_range(start, len, PAGE_VALID) check for valid advice > values before proceeding with the advice actions. In addition, extend the > tcg multiarch test linux-madvise.c to test this behaviour. > > Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4382 > AI-used-for: importing and validating test case > Signed-off-by: Alex Bennée <alex.bennee@linaro.org> > > --- > NOTE > - again testing the minimal agents which did stop and say: > > *(Note: Per user policy, git commits are never executed automatically by the agent. Please review the diff with `git diff` and commit the changes if you are satisfied.)* > > but non-the-less imported the test and wrote a crap patch which I > have re-done dropping a load of unneeded verbosity. Did you test this patch? If yes, did it work for you? I'm asking, because I tried the testcase from the bug report, and in qemu I still get 0 (success). Helge > --- > linux-user/mmap.c | 12 ++++++++++++ > tests/tcg/multiarch/linux/linux-madvise.c | 20 ++++++++++++++++++++ > 2 files changed, 32 insertions(+) > > diff --git a/linux-user/mmap.c b/linux-user/mmap.c > index cc0c2ee6c27..4066072ff45 100644 > --- a/linux-user/mmap.c > +++ b/linux-user/mmap.c > @@ -1307,6 +1307,16 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) > * though. > */ > mmap_lock(); > + > + /* > + * Whatever advice if the pages are not currently mapped, or are > + * outside the address space of the process. > + */ > + if (!page_check_range(start, len, PAGE_VALID)) { > + ret = -TARGET_ENOMEM; > + goto unlock; > + } > + > switch (advice) { > case MADV_NORMAL: > case MADV_RANDOM: > @@ -1358,6 +1368,8 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) > ret = -EINVAL; /* not yet known advise */ > break; > } > + > + unlock: > mmap_unlock(); > > return ret; > diff --git a/tests/tcg/multiarch/linux/linux-madvise.c b/tests/tcg/multiarch/linux/linux-madvise.c > index 539fb3b7726..ebb9666c919 100644 > --- a/tests/tcg/multiarch/linux/linux-madvise.c > +++ b/tests/tcg/multiarch/linux/linux-madvise.c > @@ -1,4 +1,5 @@ > #include <assert.h> > +#include <errno.h> > #include <stdlib.h> > #include <sys/mman.h> > #include <unistd.h> > @@ -63,10 +64,29 @@ static void test_file(void) > assert(ret == 0); > } > > +static void test_unmapped(void) > +{ > + int pagesize = getpagesize(); > + void *page; > + int ret; > + > + page = mmap(NULL, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); > + assert(page != MAP_FAILED); > + > + ret = munmap(page, pagesize); > + assert(ret == 0); > + > + errno = 0; > + ret = madvise(page, pagesize, MADV_NORMAL); > + assert(ret == -1); > + assert(errno == ENOMEM); > +} > + > int main(void) > { > test_anonymous(); > test_file(); > + test_unmapped(); > > return EXIT_SUCCESS; > } ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM 2026-09-09 21:17 ` Helge Deller @ 2026-09-10 10:09 ` Helge Deller 2026-09-10 10:16 ` Alex Bennée 1 sibling, 0 replies; 5+ messages in thread From: Helge Deller @ 2026-09-10 10:09 UTC (permalink / raw) To: Alex Bennée, qemu-devel; +Cc: Laurent Vivier, Pierrick Bouvier On 9/9/26 23:17, Helge Deller wrote: > Hi Alex, > > On 9/3/26 16:27, Alex Bennée wrote: >> Per madvise(2) and the Linux kernel implementation (madvise_walk_vmas), >> madvise() must validate that the requested range is currently mapped >> and return -ENOMEM if any page in the range is unmapped. >> >> Add a page_check_range(start, len, PAGE_VALID) check for valid advice >> values before proceeding with the advice actions. In addition, extend the >> tcg multiarch test linux-madvise.c to test this behaviour. >> >> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4382 >> AI-used-for: importing and validating test case >> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> >> >> --- >> NOTE >> - again testing the minimal agents which did stop and say: >> >> *(Note: Per user policy, git commits are never executed automatically by the agent. Please review the diff with `git diff` and commit the changes if you are satisfied.)* >> >> but non-the-less imported the test and wrote a crap patch which I >> have re-done dropping a load of unneeded verbosity. > > > Did you test this patch? > If yes, did it work for you? > I'm asking, because I tried the testcase from the bug report, and > in qemu I still get 0 (success). Oh, this was a misconfiguration on my side. The patch works ok! Reviewed-by: Helge Deller <deller@gmx.de> Tested-by: Helge Deller <deller@gmx.de> Thanks! Helge ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM 2026-09-09 21:17 ` Helge Deller 2026-09-10 10:09 ` Helge Deller @ 2026-09-10 10:16 ` Alex Bennée 2026-09-10 10:22 ` Helge Deller 1 sibling, 1 reply; 5+ messages in thread From: Alex Bennée @ 2026-09-10 10:16 UTC (permalink / raw) To: Helge Deller; +Cc: qemu-devel, Laurent Vivier, Pierrick Bouvier Helge Deller <deller@gmx.de> writes: > Hi Alex, > > On 9/3/26 16:27, Alex Bennée wrote: >> Per madvise(2) and the Linux kernel implementation (madvise_walk_vmas), >> madvise() must validate that the requested range is currently mapped >> and return -ENOMEM if any page in the range is unmapped. >> Add a page_check_range(start, len, PAGE_VALID) check for valid >> advice >> values before proceeding with the advice actions. In addition, extend the >> tcg multiarch test linux-madvise.c to test this behaviour. >> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4382 >> AI-used-for: importing and validating test case >> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> >> --- >> NOTE >> - again testing the minimal agents which did stop and say: >> *(Note: Per user policy, git commits are never executed >> automatically by the agent. Please review the diff with `git diff` >> and commit the changes if you are satisfied.)* >> but non-the-less imported the test and wrote a crap patch which I >> have re-done dropping a load of unneeded verbosity. > > > Did you test this patch? > If yes, did it work for you? Yes - ran the test case before and after the changes and it asserts before. ./qemu-aarch64 -strace -d guest_errors,unimp aarch64-linux-user-linux-madvise.test 681364 uname(0x7f403e54d3c8) = 0 681364 brk(NULL) = 0x00000000004a7000 681364 brk(0x00000000004a7b00) = 0x00000000004a7b00 681364 set_tid_address(0x4a70f0) = 681364 681364 set_robust_list(0x4a7100,24) = -1 errno=38 (Function not implemented) 681364 rseq(0x4a77c0,32,0,0xd428bc00)Unsupported syscall: 293 = -1 errno=38 (Function not implemented) 681364 prlimit64(0,RLIMIT_STACK,NULL,0x00007f403e54d518) = 0 ({rlim_cur=8388608,rlim_max=-1}) 681364 readlinkat(AT_FDCWD,"/proc/self/exe",0x00007f403e54c4a0,4096) = 73 681364 getrandom(0x4a6808,8,1) = 8 681364 brk(NULL) = 0x00000000004a7b00 681364 brk(0x00000000004c8b00) = 0x00000000004c8b00 681364 brk(0x00000000004c9000) = 0x00000000004c9000 681364 mprotect(0x000000000049b000,20480,PROT_READ) = 0 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 681364 mprotect(0x00007f40405f2000,4096,PROT_READ|PROT_WRITE) = 0 681364 madvise(0x00007f40405f2000,4096,MADV_DONTNEED) = 0 681364 munmap(0x00007f40405f2000,4096) = 0 681364 getrandom(0x7f403e54d360,8,1) = 8 681364 openat(AT_FDCWD,"/tmp/.cmadvisebhAABn",O_RDWR|O_CREAT|O_EXCL,0600) = 3 681364 unlinkat(AT_FDCWD,"/tmp/.cmadvisebhAABn",0) = 0 681364 write(3,0x7f403e54d3f7,1) = 1 681364 ftruncate(3,4096) = 0 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE,3,0) = 0x00007f40405f2000 681364 mprotect(0x00007f40405f2000,4096,PROT_READ|PROT_WRITE) = 0 681364 madvise(0x00007f40405f2000,4096,MADV_DONTNEED) = 0 681364 munmap(0x00007f40405f2000,4096) = 0 681364 close(3) = 0 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 681364 munmap(0x00007f40405f2000,4096) = 0 681364 madvise(0x00007f40405f2000,4096,MADV_NORMAL) = 0 681364 write(2,0x7f403e54cbc8,128)aarch64-linux-user-linux-madvise.test: /home/alex/lsrc/qemu.git/tests/tcg/multiarch/linux/linux-madvise.c:81: test_unmapped: Ass = 128 681364 write(2,0x7f403e54cbc8,27)ertion `ret == -1' failed. = 27 681364 mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 681364 gettid() = 681364 681364 getpid() = 681364 681364 tgkill(681364,681364,SIGIOT) = 0 --- SIGIOT {si_signo=SIGIOT, si_code=SI_TKILL, si_pid=681364, si_uid=1000} --- qemu: uncaught target signal 6 (Aborted) - core dumped fish: Job 1, './qemu-aarch64 -strace -d guest…' terminated by signal SIGABRT (Abort) > I'm asking, because I tried the testcase from the bug report, and > in qemu I still get 0 (success). I suspect you've been tripped up by the conversion of tests to meson as they now have the .test suffix. So with the patch applied and tests passing: cp tests/tcg/aarch64-linux-user-linux-madvise.test . and then drop back one patch and rebuild and test against the copy of the test with the test_unmapped support. > > Helge > >> --- >> linux-user/mmap.c | 12 ++++++++++++ >> tests/tcg/multiarch/linux/linux-madvise.c | 20 ++++++++++++++++++++ >> 2 files changed, 32 insertions(+) >> diff --git a/linux-user/mmap.c b/linux-user/mmap.c >> index cc0c2ee6c27..4066072ff45 100644 >> --- a/linux-user/mmap.c >> +++ b/linux-user/mmap.c >> @@ -1307,6 +1307,16 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) >> * though. >> */ >> mmap_lock(); >> + >> + /* >> + * Whatever advice if the pages are not currently mapped, or are >> + * outside the address space of the process. >> + */ >> + if (!page_check_range(start, len, PAGE_VALID)) { >> + ret = -TARGET_ENOMEM; >> + goto unlock; >> + } >> + >> switch (advice) { >> case MADV_NORMAL: >> case MADV_RANDOM: >> @@ -1358,6 +1368,8 @@ abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice) >> ret = -EINVAL; /* not yet known advise */ >> break; >> } >> + >> + unlock: >> mmap_unlock(); >> return ret; >> diff --git a/tests/tcg/multiarch/linux/linux-madvise.c b/tests/tcg/multiarch/linux/linux-madvise.c >> index 539fb3b7726..ebb9666c919 100644 >> --- a/tests/tcg/multiarch/linux/linux-madvise.c >> +++ b/tests/tcg/multiarch/linux/linux-madvise.c >> @@ -1,4 +1,5 @@ >> #include <assert.h> >> +#include <errno.h> >> #include <stdlib.h> >> #include <sys/mman.h> >> #include <unistd.h> >> @@ -63,10 +64,29 @@ static void test_file(void) >> assert(ret == 0); >> } >> +static void test_unmapped(void) >> +{ >> + int pagesize = getpagesize(); >> + void *page; >> + int ret; >> + >> + page = mmap(NULL, pagesize, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); >> + assert(page != MAP_FAILED); >> + >> + ret = munmap(page, pagesize); >> + assert(ret == 0); >> + >> + errno = 0; >> + ret = madvise(page, pagesize, MADV_NORMAL); >> + assert(ret == -1); >> + assert(errno == ENOMEM); >> +} >> + >> int main(void) >> { >> test_anonymous(); >> test_file(); >> + test_unmapped(); >> return EXIT_SUCCESS; >> } -- Alex Bennée Virtualisation Tech Lead @ Linaro ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM 2026-09-10 10:16 ` Alex Bennée @ 2026-09-10 10:22 ` Helge Deller 0 siblings, 0 replies; 5+ messages in thread From: Helge Deller @ 2026-09-10 10:22 UTC (permalink / raw) To: Alex Bennée; +Cc: qemu-devel, Laurent Vivier, Pierrick Bouvier On 9/10/26 12:16, Alex Bennée wrote: > Helge Deller <deller@gmx.de> writes: > >> Hi Alex, >> >> On 9/3/26 16:27, Alex Bennée wrote: >>> Per madvise(2) and the Linux kernel implementation (madvise_walk_vmas), >>> madvise() must validate that the requested range is currently mapped >>> and return -ENOMEM if any page in the range is unmapped. >>> Add a page_check_range(start, len, PAGE_VALID) check for valid >>> advice >>> values before proceeding with the advice actions. In addition, extend the >>> tcg multiarch test linux-madvise.c to test this behaviour. >>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4382 >>> AI-used-for: importing and validating test case >>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> >>> --- >>> NOTE >>> - again testing the minimal agents which did stop and say: >>> *(Note: Per user policy, git commits are never executed >>> automatically by the agent. Please review the diff with `git diff` >>> and commit the changes if you are satisfied.)* >>> but non-the-less imported the test and wrote a crap patch which I >>> have re-done dropping a load of unneeded verbosity. >> >> >> Did you test this patch? >> If yes, did it work for you? > > Yes - ran the test case before and after the changes and it asserts > before. Yes, sorry, as mentioned in earlier mail, it was a misconfiguration on my side. > ./qemu-aarch64 -strace -d guest_errors,unimp aarch64-linux-user-linux-madvise.test > 681364 uname(0x7f403e54d3c8) = 0 > 681364 brk(NULL) = 0x00000000004a7000 > 681364 brk(0x00000000004a7b00) = 0x00000000004a7b00 > 681364 set_tid_address(0x4a70f0) = 681364 > 681364 set_robust_list(0x4a7100,24) = -1 errno=38 (Function not implemented) > 681364 rseq(0x4a77c0,32,0,0xd428bc00)Unsupported syscall: 293 > = -1 errno=38 (Function not implemented) > 681364 prlimit64(0,RLIMIT_STACK,NULL,0x00007f403e54d518) = 0 ({rlim_cur=8388608,rlim_max=-1}) > 681364 readlinkat(AT_FDCWD,"/proc/self/exe",0x00007f403e54c4a0,4096) = 73 > 681364 getrandom(0x4a6808,8,1) = 8 > 681364 brk(NULL) = 0x00000000004a7b00 > 681364 brk(0x00000000004c8b00) = 0x00000000004c8b00 > 681364 brk(0x00000000004c9000) = 0x00000000004c9000 > 681364 mprotect(0x000000000049b000,20480,PROT_READ) = 0 > 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 > 681364 mprotect(0x00007f40405f2000,4096,PROT_READ|PROT_WRITE) = 0 > 681364 madvise(0x00007f40405f2000,4096,MADV_DONTNEED) = 0 > 681364 munmap(0x00007f40405f2000,4096) = 0 > 681364 getrandom(0x7f403e54d360,8,1) = 8 > 681364 openat(AT_FDCWD,"/tmp/.cmadvisebhAABn",O_RDWR|O_CREAT|O_EXCL,0600) = 3 > 681364 unlinkat(AT_FDCWD,"/tmp/.cmadvisebhAABn",0) = 0 > 681364 write(3,0x7f403e54d3f7,1) = 1 > 681364 ftruncate(3,4096) = 0 > 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE,3,0) = 0x00007f40405f2000 > 681364 mprotect(0x00007f40405f2000,4096,PROT_READ|PROT_WRITE) = 0 > 681364 madvise(0x00007f40405f2000,4096,MADV_DONTNEED) = 0 > 681364 munmap(0x00007f40405f2000,4096) = 0 > 681364 close(3) = 0 > 681364 mmap(NULL,4096,PROT_READ,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 > 681364 munmap(0x00007f40405f2000,4096) = 0 > 681364 madvise(0x00007f40405f2000,4096,MADV_NORMAL) = 0 > 681364 write(2,0x7f403e54cbc8,128)aarch64-linux-user-linux-madvise.test: /home/alex/lsrc/qemu.git/tests/tcg/multiarch/linux/linux-madvise.c:81: test_unmapped: Ass = 128 > 681364 write(2,0x7f403e54cbc8,27)ertion `ret == -1' failed. > = 27 > 681364 mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x00007f40405f2000 > 681364 gettid() = 681364 > 681364 getpid() = 681364 > 681364 tgkill(681364,681364,SIGIOT) = 0 > --- SIGIOT {si_signo=SIGIOT, si_code=SI_TKILL, si_pid=681364, si_uid=1000} --- > qemu: uncaught target signal 6 (Aborted) - core dumped > fish: Job 1, './qemu-aarch64 -strace -d guest…' terminated by signal SIGABRT (Abort) > >> I'm asking, because I tried the testcase from the bug report, and >> in qemu I still get 0 (success). > > I suspect you've been tripped up by the conversion of tests to meson as > they now have the .test suffix. No, actually I ran the test in a chroot which I set up with binfmt_misc, and it was configured to use an outdated (v5.something) qemu version :-( Helge ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-10 10:23 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-03 14:27 [RFC PATCH] linux-user: madvise() on unmapped ranges should return ENOMEM Alex Bennée 2026-09-09 21:17 ` Helge Deller 2026-09-10 10:09 ` Helge Deller 2026-09-10 10:16 ` Alex Bennée 2026-09-10 10:22 ` 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.