Commit 8aeb7b17 authored by Palmer Dabbelt's avatar Palmer Dabbelt

RISC-V: Make mmap() with PROT_WRITE imply PROT_READ

Commit 2139619b ("riscv: mmap with PROT_WRITE but no PROT_READ is
invalid") made mmap() reject mappings with only PROT_WRITE set in an
attempt to fix an observed inconsistency in behavior when attempting
to read from a PROT_WRITE-only mapping. The root cause of this behavior
was actually that while RISC-V's protection_map maps VM_WRITE to
readable PTE permissions (since write-only PTEs are considered reserved
by the privileged spec), the page fault handler considered loads from
VM_WRITE-only VMAs illegal accesses. Fix the underlying cause by
handling faults in VM_WRITE-only VMAs (patch 1) and then re-enable
use of mmap(PROT_WRITE) (patch 2), making RISC-V's behavior consistent
with all other architectures that don't support write-only PTEs.

* remotes/palmer/riscv-wonly:
  riscv: Allow PROT_WRITE-only mmap()
  riscv: Make VM_WRITE imply VM_READ

Link: https://lore.kernel.org/r/20220915193702.2201018-1-abrestic@rivosinc.com/Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents c45fc916 9e2e6042
...@@ -18,9 +18,6 @@ static long riscv_sys_mmap(unsigned long addr, unsigned long len, ...@@ -18,9 +18,6 @@ static long riscv_sys_mmap(unsigned long addr, unsigned long len,
if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) if (unlikely(offset & (~PAGE_MASK >> page_shift_offset)))
return -EINVAL; return -EINVAL;
if (unlikely((prot & PROT_WRITE) && !(prot & PROT_READ)))
return -EINVAL;
return ksys_mmap_pgoff(addr, len, prot, flags, fd, return ksys_mmap_pgoff(addr, len, prot, flags, fd,
offset >> (PAGE_SHIFT - page_shift_offset)); offset >> (PAGE_SHIFT - page_shift_offset));
} }
......
...@@ -184,7 +184,8 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma) ...@@ -184,7 +184,8 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma)
} }
break; break;
case EXC_LOAD_PAGE_FAULT: case EXC_LOAD_PAGE_FAULT:
if (!(vma->vm_flags & VM_READ)) { /* Write implies read */
if (!(vma->vm_flags & (VM_READ | VM_WRITE))) {
return true; return true;
} }
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment