@@ -557,6 +587,11 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,Ah, this revert to the non-write flags doesn't look great as we
/* It was write fault */
vm_flags = VM_WRITE;
mm_flags |= FAULT_FLAG_WRITE;
+ } else if (is_el0_atomic_instr(regs)) {
+ /* Force write fault */
+ vm_flags = VM_WRITE;
+ mm_flags |= FAULT_FLAG_WRITE;
+ force_write = true;
} else {
/* It was read fault */
vm_flags = VM_READ;
@@ -586,6 +621,14 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
if (!vma)
goto lock_mmap;
+ /* vma flags don't allow write, undo force write */
+ if (force_write && !(vma->vm_flags & VM_WRITE)) {
+ vm_flags |= VM_READ;
+ if (!alternative_has_cap_unlikely(ARM64_HAS_EPAN))
+ vm_flags |= VM_EXEC;
+ mm_flags &= ~FAULT_FLAG_WRITE;
+ }
basically duplicate the 'else' block in the original check. So, it
probably look better as per your earlier patch to just do the
instruction read just before the !(vma->vm_flags & flags) check,
something like:
if ((vma->vm_flags & VM_WRITE) && is_el0_atomic_instr(regs)) {
vm_flags = VM_WRITE;
mm_flags |= FAULT_FLAG_WRITE;
}
This way we also only read the instruction if the vma is writeable. I
think it's fine to do this under the vma lock since we have
pagefault_disable() for the insn read.