Helge Deller <[email protected]> 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 <[email protected]>
>> ---
>> 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

Reply via email to