]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Jun 2020 17:22:26 +0000 (19:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Jun 2020 17:22:26 +0000 (19:22 +0200)
added patches:
uprobes-ensure-that-uprobe-offset-and-ref_ctr_offset-are-properly-aligned.patch

queue-5.7/series
queue-5.7/uprobes-ensure-that-uprobe-offset-and-ref_ctr_offset-are-properly-aligned.patch [new file with mode: 0644]

index c9b08d477f9b95d486c3df235bbf93ef4c4fa960..0e7310b9a89f2f42f6ae7d22b72c2d576d74ca08 100644 (file)
@@ -21,3 +21,4 @@ x86-cpu-add-table-argument-to-cpu_matches.patch
 x86-speculation-add-special-register-buffer-data-sampling-srbds-mitigation.patch
 x86-speculation-add-srbds-vulnerability-and-mitigation-documentation.patch
 x86-speculation-add-ivy-bridge-to-affected-list.patch
+uprobes-ensure-that-uprobe-offset-and-ref_ctr_offset-are-properly-aligned.patch
diff --git a/queue-5.7/uprobes-ensure-that-uprobe-offset-and-ref_ctr_offset-are-properly-aligned.patch b/queue-5.7/uprobes-ensure-that-uprobe-offset-and-ref_ctr_offset-are-properly-aligned.patch
new file mode 100644 (file)
index 0000000..3e0f07c
--- /dev/null
@@ -0,0 +1,76 @@
+From 013b2deba9a6b80ca02f4fafd7dedf875e9b4450 Mon Sep 17 00:00:00 2001
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Mon, 4 May 2020 18:47:25 +0200
+Subject: uprobes: ensure that uprobe->offset and ->ref_ctr_offset are properly aligned
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit 013b2deba9a6b80ca02f4fafd7dedf875e9b4450 upstream.
+
+uprobe_write_opcode() must not cross page boundary; prepare_uprobe()
+relies on arch_uprobe_analyze_insn() which should validate "vaddr" but
+some architectures (csky, s390, and sparc) don't do this.
+
+We can remove the BUG_ON() check in prepare_uprobe() and validate the
+offset early in __uprobe_register(). The new IS_ALIGNED() check matches
+the alignment check in arch_prepare_kprobe() on supported architectures,
+so I think that all insns must be aligned to UPROBE_SWBP_INSN_SIZE.
+
+Another problem is __update_ref_ctr() which was wrong from the very
+beginning, it can read/write outside of kmap'ed page unless "vaddr" is
+aligned to sizeof(short), __uprobe_register() should check this too.
+
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Reviewed-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Tested-by: Sven Schnelle <svens@linux.ibm.com>
+Cc: Steven Rostedt <rostedt@goodmis.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/events/uprobes.c |   16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+--- a/kernel/events/uprobes.c
++++ b/kernel/events/uprobes.c
+@@ -867,10 +867,6 @@ static int prepare_uprobe(struct uprobe
+       if (ret)
+               goto out;
+-      /* uprobe_write_opcode() assumes we don't cross page boundary */
+-      BUG_ON((uprobe->offset & ~PAGE_MASK) +
+-                      UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
+-
+       smp_wmb(); /* pairs with the smp_rmb() in handle_swbp() */
+       set_bit(UPROBE_COPY_INSN, &uprobe->flags);
+@@ -1166,6 +1162,15 @@ static int __uprobe_register(struct inod
+       if (offset > i_size_read(inode))
+               return -EINVAL;
++      /*
++       * This ensures that copy_from_page(), copy_to_page() and
++       * __update_ref_ctr() can't cross page boundary.
++       */
++      if (!IS_ALIGNED(offset, UPROBE_SWBP_INSN_SIZE))
++              return -EINVAL;
++      if (!IS_ALIGNED(ref_ctr_offset, sizeof(short)))
++              return -EINVAL;
++
+  retry:
+       uprobe = alloc_uprobe(inode, offset, ref_ctr_offset);
+       if (!uprobe)
+@@ -2014,6 +2019,9 @@ static int is_trap_at_addr(struct mm_str
+       uprobe_opcode_t opcode;
+       int result;
++      if (WARN_ON_ONCE(!IS_ALIGNED(vaddr, UPROBE_SWBP_INSN_SIZE)))
++              return -EINVAL;
++
+       pagefault_disable();
+       result = __get_user(opcode, (uprobe_opcode_t __user *)vaddr);
+       pagefault_enable();