casaroli opened a new pull request, #20834:
URL: https://github.com/apache/nuttx/pull/20834

   ## Summary
   
   `mprotect()` returned 0 and changed nothing, also in kernel builds where the 
MMU can change the page permissions. A page made read-only stayed writable, a 
page could not become executable, and bad arguments were not reported.
   
   In all builds, `mprotect()` now returns `EINVAL` when `addr` is not a 
multiple of `sysconf(_SC_PAGESIZE)` or `prot` has an unknown bit. Without 
`CONFIG_ARCH_ADDRENV` a valid request still returns 0 and changes nothing: 
without an MMU the permissions cannot be enforced.
   
   With `CONFIG_ARCH_ADDRENV`, `mprotect()` calls `up_addrenv_mprot()` for the 
address environment of the caller. It returns `ENOMEM` when a page of the range 
is not mapped user memory, and then nothing changes. With `PROT_EXEC` the 
kernel also makes the instruction cache coherent for the range, so code written 
to the pages runs without a cache maintenance call in the program. `PROT_READ | 
PROT_WRITE | PROT_EXEC` is allowed; a W^X policy can come later as an option.
   
   `up_addrenv_mprot()` on arm64 and RISC-V now checks the whole range before 
it changes an entry: a user address with a valid page entry. Before, it 
accepted any address, changed invalid entries and stopped half way on an error. 
On arm64, `PROT_NONE` now removes the user access (it gave a readable page). On 
RISC-V, `PROT_WRITE` now also sets R (W without R is a reserved encoding), and 
with `CONFIG_SMP` every hart runs `sfence.vma` and `fence.i` through 
`nxsched_smp_call()` (before, only the local hart did).
   
   On arm64, `fork()` now copies the page attributes of the parent. Before, the 
child got the default permissions, so a read-only page of the parent was 
writable in the child.
   
   The commits:
   
   - arch/arm64: Check the range in up_addrenv_mprot() and support PROT_NONE.
   - arch/risc-v: Check the range in up_addrenv_mprot().
   - arch/risc-v: Flush all harts in up_addrenv_mprot().
   - fs/mmap: Implement mprotect().
   - arch/arm64: Keep the page permissions in fork().
   - Documentation: Update the mprotect() support.
   
   ## Impact
   
   Kernel builds (`CONFIG_ARCH_ADDRENV`) on arm64 and RISC-V: `mprotect()` 
changes the page permissions. A program that wrote to a page after it made the 
page read-only now gets a fault.
   
   All builds: `mprotect()` with an unaligned `addr` or an unknown `prot` bit 
now fails with `EINVAL` instead of returning 0.
   
   Other targets with `CONFIG_ARCH_ADDRENV` (x86_64, armv7-a, the arm64 MPU and 
ESP32-S3) have a `up_addrenv_mprot()` that does nothing: there a valid request 
returns 0 as before.
   
   The ELF loader calls `up_addrenv_mprot()` for `.text`. That range passes the 
new check.
   
   ## Testing
   
   Test program `mprotect.c`. Each fault case runs in a child process that the 
program spawns: mmap an anonymous page, make it read-only and write it; 
PROT_NONE and read; write code to a page and call it before and after 
`PROT_READ | PROT_EXEC`; write new code after RW, back to RX, call it; 
`PROT_READ | PROT_WRITE | PROT_EXEC`; a read-only `.bss` page, also in a fork() 
child; EINVAL and ENOMEM cases. In a flat build only the argument checks run.
   
   - qemu-armv8a:knsh (HVF): master 16 of 22 checks fail; this branch all pass. 
Without the fork() commit only the read-only `.bss` page in the fork() child 
fails.
   - rv-virt:knsh64, rv-virt:ksmp64 (4 harts) and rv-virt:knsh64_paging (QEMU 
TCG, `CONFIG_FS_SHMFS` added so that anonymous mmap() gives pages): this branch 
all pass (the fork() case is skipped: no fork() on RISC-V). rv-virt:knsh64 on 
master: 15 of 21 fail.
   - qemu-armv8a:nsh (flat, HVF): `sysconf(_SC_PAGESIZE)` is 8192 there. Master 
returns 0 for an unaligned `addr` and an unknown `prot` bit; this branch 
returns EINVAL, and valid requests return 0.
   
   ostest: exit status 0 on qemu-armv8a:knsh, qemu-armv8a:nsh, rv-virt:knsh64, 
rv-virt:ksmp64 and rv-virt:knsh64_paging.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to