]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.19.31/mm-memory.c-do_fault-avoid-usage-of-stale-vm_area_struct.patch
Linux 4.19.31
[thirdparty/kernel/stable-queue.git] / releases / 4.19.31 / mm-memory.c-do_fault-avoid-usage-of-stale-vm_area_struct.patch
CommitLineData
ec71c73b
GKH
1From fc8efd2ddfed3f343c11b693e87140ff358d7ff5 Mon Sep 17 00:00:00 2001
2From: Jan Stancek <jstancek@redhat.com>
3Date: Tue, 5 Mar 2019 15:50:08 -0800
4Subject: mm/memory.c: do_fault: avoid usage of stale vm_area_struct
5
6From: Jan Stancek <jstancek@redhat.com>
7
8commit fc8efd2ddfed3f343c11b693e87140ff358d7ff5 upstream.
9
10LTP testcase mtest06 [1] can trigger a crash on s390x running 5.0.0-rc8.
11This is a stress test, where one thread mmaps/writes/munmaps memory area
12and other thread is trying to read from it:
13
14 CPU: 0 PID: 2611 Comm: mmap1 Not tainted 5.0.0-rc8+ #51
15 Hardware name: IBM 2964 N63 400 (z/VM 6.4.0)
16 Krnl PSW : 0404e00180000000 00000000001ac8d8 (__lock_acquire+0x7/0x7a8)
17 Call Trace:
18 ([<0000000000000000>] (null))
19 [<00000000001adae4>] lock_acquire+0xec/0x258
20 [<000000000080d1ac>] _raw_spin_lock_bh+0x5c/0x98
21 [<000000000012a780>] page_table_free+0x48/0x1a8
22 [<00000000002f6e54>] do_fault+0xdc/0x670
23 [<00000000002fadae>] __handle_mm_fault+0x416/0x5f0
24 [<00000000002fb138>] handle_mm_fault+0x1b0/0x320
25 [<00000000001248cc>] do_dat_exception+0x19c/0x2c8
26 [<000000000080e5ee>] pgm_check_handler+0x19e/0x200
27
28page_table_free() is called with NULL mm parameter, but because "0" is a
29valid address on s390 (see S390_lowcore), it keeps going until it
30eventually crashes in lockdep's lock_acquire. This crash is
31reproducible at least since 4.14.
32
33Problem is that "vmf->vma" used in do_fault() can become stale. Because
34mmap_sem may be released, other threads can come in, call munmap() and
35cause "vma" be returned to kmem cache, and get zeroed/re-initialized and
36re-used:
37
38handle_mm_fault |
39 __handle_mm_fault |
40 do_fault |
41 vma = vmf->vma |
42 do_read_fault |
43 __do_fault |
44 vma->vm_ops->fault(vmf); |
45 mmap_sem is released |
46 |
47 | do_munmap()
48 | remove_vma_list()
49 | remove_vma()
50 | vm_area_free()
51 | # vma is released
52 | ...
53 | # same vma is allocated
54 | # from kmem cache
55 | do_mmap()
56 | vm_area_alloc()
57 | memset(vma, 0, ...)
58 |
59 pte_free(vma->vm_mm, ...); |
60 page_table_free |
61 spin_lock_bh(&mm->context.lock);|
62 <crash> |
63
64Cache mm_struct to avoid using potentially stale "vma".
65
66[1] https://github.com/linux-test-project/ltp/blob/master/testcases/kernel/mem/mtest06/mmap1.c
67
68Link: http://lkml.kernel.org/r/5b3fdf19e2a5be460a384b936f5b56e13733f1b8.1551595137.git.jstancek@redhat.com
69Signed-off-by: Jan Stancek <jstancek@redhat.com>
70Reviewed-by: Andrea Arcangeli <aarcange@redhat.com>
71Reviewed-by: Matthew Wilcox <willy@infradead.org>
72Acked-by: Rafael Aquini <aquini@redhat.com>
73Reviewed-by: Minchan Kim <minchan@kernel.org>
74Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
75Cc: Rik van Riel <riel@surriel.com>
76Cc: Michal Hocko <mhocko@suse.com>
77Cc: Huang Ying <ying.huang@intel.com>
78Cc: Souptick Joarder <jrdr.linux@gmail.com>
79Cc: Jerome Glisse <jglisse@redhat.com>
80Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
81Cc: David Hildenbrand <david@redhat.com>
82Cc: Andrea Arcangeli <aarcange@redhat.com>
83Cc: David Rientjes <rientjes@google.com>
84Cc: Mel Gorman <mgorman@techsingularity.net>
85Cc: <stable@vger.kernel.org>
86Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
87Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
88Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
89
90---
91 mm/memory.c | 5 ++++-
92 1 file changed, 4 insertions(+), 1 deletion(-)
93
94--- a/mm/memory.c
95+++ b/mm/memory.c
96@@ -3762,10 +3762,13 @@ static vm_fault_t do_shared_fault(struct
97 * but allow concurrent faults).
98 * The mmap_sem may have been released depending on flags and our
99 * return value. See filemap_fault() and __lock_page_or_retry().
100+ * If mmap_sem is released, vma may become invalid (for example
101+ * by other thread calling munmap()).
102 */
103 static vm_fault_t do_fault(struct vm_fault *vmf)
104 {
105 struct vm_area_struct *vma = vmf->vma;
106+ struct mm_struct *vm_mm = vma->vm_mm;
107 vm_fault_t ret;
108
109 /*
110@@ -3806,7 +3809,7 @@ static vm_fault_t do_fault(struct vm_fau
111
112 /* preallocated pagetable is unused: free it */
113 if (vmf->prealloc_pte) {
114- pte_free(vma->vm_mm, vmf->prealloc_pte);
115+ pte_free(vm_mm, vmf->prealloc_pte);
116 vmf->prealloc_pte = NULL;
117 }
118 return ret;