The problem here is not the mmap(), it is that you are mapping it as only PROT_WRITE and not also PROT_READ. With the native kernel, syscalls which only write to a buffer and do not read from it (like read(2)) only require write permissions on that memory. QEMU's implementation requires both write and read permission.
This is a QEMU bug, but not a major one, because in practice no guest binaries set up memory that is only writable and can't be read (what would they do with the data that they wrote into that memory?). You can work around it in your test program by using mmap(..., PROT_READ | PROT_WRITE, ...), which will allow it to work in QEMU. (Technical QEMU internal notes for other developers: the issue here is that we do permissions checks in syscall.c using lock_user(VERIFY_WRITE, ...) etc, but in access_ok() we treat VERIFY_WRITE as "implies read access" when we're choosing the permissions flags to pass to page_check_range(). To fix this we would have to check all the places we use VERIFY_WRITE to identify which should be "only need write" and which are "need both read and write".) ** Summary changed: - qemu-arm-static read() doesn't accept mmap address as destination + qemu linux-user requires read permissions on memory passed to syscalls that should only need write access ** Changed in: qemu Status: New => Confirmed -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/1779955 Title: qemu linux-user requires read permissions on memory passed to syscalls that should only need write access Status in QEMU: Confirmed Bug description: When read() function takes an mmap'ed address as output buffer, it returns EFAULT. The expected behavior is it should just work. The following code works for qemu-system-arm, but not for qemu-arm- static. QEMU version affected: latest release 2.12.0. Steps to reproduce (please substitute /path/to/qemu-arm-static with the path of the binary, and /tmp/a.cpp with the example source code attached): # First register binfmt_misc [hidden]$ docker run --rm --privileged multiarch/qemu-user-static:register --reset # Compile the code and run [hidden]$ docker run --rm -it -v /tmp/a.cpp:/tmp/a.cpp -v /path/to/qemu-arm-static:/usr/bin/qemu-arm-static arm32v7/ubuntu:18.04 bash -c '{ apt update -y && apt install -y g++; } >& /dev/null && g++ -std=c++14 /tmp/a.cpp -o /tmp/a.out && echo hehe > /tmp/haha.txt && /tmp/a.out' ofd=3 ftruncate=0 mmap=0xff3f5000 fd=4 0xff3f5023 -1 14 The expected result in qemu-system-arm as well as natively on x86_64 host: hidden$ ./a.out ofd=3 ftruncate=0 mmap=0xb6fb7000 fd=4 0xb6fb7023 5 0 To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/1779955/+subscriptions