For THPs page_check_address() always fails. It leads to endless loop in
uprobe_write_opcode().

Testcase with huge-tmpfs (not sure if it's possible to trigger this
uprobe codepath for anon memory):

        mount -t debugfs none /sys/kernel/debug
        mount -t tmpfs -o huge=always none /mnt
        gcc -Wall -O2 -o /mnt/test -x c - <<EOF
        int main(void)
        {
                return 0;
        }
        /* Padding to map the code segment with huge pmd */
        asm (".zero 2097152");
        EOF
        echo 'p /mnt/test:0' > /sys/kernel/debug/tracing/uprobe_events
        echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
        /mnt/test

Let's split THPs before trying to replace.

Signed-off-by: Kirill A. Shutemov <kirill.shute...@linux.intel.com>
Acked-by: Rik van Riel <r...@redhat.com>
Acked-by: Johannes Weiner <han...@cmpxchg.org>
Cc: Oleg Nesterov <o...@redhat.com>
Cc: Peter Zijlstra <pet...@infradead.org>
---
 kernel/events/uprobes.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index d416f3baf392..1e65c79e52a6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -300,8 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long 
vaddr,
 
 retry:
        /* Read the page with vaddr into memory */
-       ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
-                       &vma, NULL);
+       ret = get_user_pages_remote(NULL, mm, vaddr, 1,
+                       FOLL_FORCE | FOLL_SPLIT, &old_page, &vma, NULL);
        if (ret <= 0)
                return ret;
 
-- 
2.11.0

Reply via email to