From: Greg Kroah-Hartman Date: Thu, 21 Nov 2019 20:44:07 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v5.3.13~18 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=62956f2e539fa85c53e60b2df0d33f4d0a402433;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch mm-memory_hotplug-fix-updating-the-node-span.patch --- diff --git a/queue-4.14/arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch b/queue-4.14/arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch new file mode 100644 index 00000000000..c5b0c506c0d --- /dev/null +++ b/queue-4.14/arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch @@ -0,0 +1,116 @@ +From 94bb804e1e6f0a9a77acf20d7c70ea141c6c821e Mon Sep 17 00:00:00 2001 +From: Pavel Tatashin +Date: Tue, 19 Nov 2019 17:10:06 -0500 +Subject: arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault + +From: Pavel Tatashin + +commit 94bb804e1e6f0a9a77acf20d7c70ea141c6c821e upstream. + +A number of our uaccess routines ('__arch_clear_user()' and +'__arch_copy_{in,from,to}_user()') fail to re-enable PAN if they +encounter an unhandled fault whilst accessing userspace. + +For CPUs implementing both hardware PAN and UAO, this bug has no effect +when both extensions are in use by the kernel. + +For CPUs implementing hardware PAN but not UAO, this means that a kernel +using hardware PAN may execute portions of code with PAN inadvertently +disabled, opening us up to potential security vulnerabilities that rely +on userspace access from within the kernel which would usually be +prevented by this mechanism. In other words, parts of the kernel run the +same way as they would on a CPU without PAN implemented/emulated at all. + +For CPUs not implementing hardware PAN and instead relying on software +emulation via 'CONFIG_ARM64_SW_TTBR0_PAN=y', the impact is unfortunately +much worse. Calling 'schedule()' with software PAN disabled means that +the next task will execute in the kernel using the page-table and ASID +of the previous process even after 'switch_mm()', since the actual +hardware switch is deferred until return to userspace. At this point, or +if there is a intermediate call to 'uaccess_enable()', the page-table +and ASID of the new process are installed. Sadly, due to the changes +introduced by KPTI, this is not an atomic operation and there is a very +small window (two instructions) where the CPU is configured with the +page-table of the old task and the ASID of the new task; a speculative +access in this state is disastrous because it would corrupt the TLB +entries for the new task with mappings from the previous address space. + +As Pavel explains: + + | I was able to reproduce memory corruption problem on Broadcom's SoC + | ARMv8-A like this: + | + | Enable software perf-events with PERF_SAMPLE_CALLCHAIN so userland's + | stack is accessed and copied. + | + | The test program performed the following on every CPU and forking + | many processes: + | + | unsigned long *map = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, + | MAP_SHARED | MAP_ANONYMOUS, -1, 0); + | map[0] = getpid(); + | sched_yield(); + | if (map[0] != getpid()) { + | fprintf(stderr, "Corruption detected!"); + | } + | munmap(map, PAGE_SIZE); + | + | From time to time I was getting map[0] to contain pid for a + | different process. + +Ensure that PAN is re-enabled when returning after an unhandled user +fault from our uaccess routines. + +Cc: Catalin Marinas +Reviewed-by: Mark Rutland +Tested-by: Mark Rutland +Cc: +Fixes: 338d4f49d6f7 ("arm64: kernel: Add support for Privileged Access Never") +Signed-off-by: Pavel Tatashin +[will: rewrote commit message] +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/lib/clear_user.S | 1 + + arch/arm64/lib/copy_from_user.S | 1 + + arch/arm64/lib/copy_in_user.S | 1 + + arch/arm64/lib/copy_to_user.S | 1 + + 4 files changed, 4 insertions(+) + +--- a/arch/arm64/lib/clear_user.S ++++ b/arch/arm64/lib/clear_user.S +@@ -57,5 +57,6 @@ ENDPROC(__arch_clear_user) + .section .fixup,"ax" + .align 2 + 9: mov x0, x2 // return the original size ++ uaccess_disable_not_uao x2, x3 + ret + .previous +--- a/arch/arm64/lib/copy_from_user.S ++++ b/arch/arm64/lib/copy_from_user.S +@@ -75,5 +75,6 @@ ENDPROC(__arch_copy_from_user) + .section .fixup,"ax" + .align 2 + 9998: sub x0, end, dst // bytes not copied ++ uaccess_disable_not_uao x3, x4 + ret + .previous +--- a/arch/arm64/lib/copy_in_user.S ++++ b/arch/arm64/lib/copy_in_user.S +@@ -77,5 +77,6 @@ ENDPROC(__arch_copy_in_user) + .section .fixup,"ax" + .align 2 + 9998: sub x0, end, dst // bytes not copied ++ uaccess_disable_not_uao x3, x4 + ret + .previous +--- a/arch/arm64/lib/copy_to_user.S ++++ b/arch/arm64/lib/copy_to_user.S +@@ -74,5 +74,6 @@ ENDPROC(__arch_copy_to_user) + .section .fixup,"ax" + .align 2 + 9998: sub x0, end, dst // bytes not copied ++ uaccess_disable_not_uao x3, x4 + ret + .previous diff --git a/queue-4.14/mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch b/queue-4.14/mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch new file mode 100644 index 00000000000..abdbe1997af --- /dev/null +++ b/queue-4.14/mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch @@ -0,0 +1,182 @@ +From 00d6c019b5bc175cee3770e0e659f2b5f4804ea5 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Fri, 18 Oct 2019 20:19:33 -0700 +Subject: mm/memory_hotplug: don't access uninitialized memmaps in shrink_pgdat_span() + +From: David Hildenbrand + +commit 00d6c019b5bc175cee3770e0e659f2b5f4804ea5 upstream. + +We might use the nid of memmaps that were never initialized. For +example, if the memmap was poisoned, we will crash the kernel in +pfn_to_nid() right now. Let's use the calculated boundaries of the +separate zones instead. This now also avoids having to iterate over a +whole bunch of subsections again, after shrinking one zone. + +Before commit d0dc12e86b31 ("mm/memory_hotplug: optimize memory +hotplug"), the memmap was initialized to 0 and the node was set to the +right value. After that commit, the node might be garbage. + +We'll have to fix shrink_zone_span() next. + +Link: http://lkml.kernel.org/r/20191006085646.5768-4-david@redhat.com +Fixes: f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded memory to zones until online") [d0dc12e86b319] +Signed-off-by: David Hildenbrand +Reported-by: Aneesh Kumar K.V +Cc: Oscar Salvador +Cc: David Hildenbrand +Cc: Michal Hocko +Cc: Pavel Tatashin +Cc: Dan Williams +Cc: Wei Yang +Cc: Alexander Duyck +Cc: Alexander Potapenko +Cc: Andy Lutomirski +Cc: Anshuman Khandual +Cc: Benjamin Herrenschmidt +Cc: Borislav Petkov +Cc: Catalin Marinas +Cc: Christian Borntraeger +Cc: Christophe Leroy +Cc: Damian Tometzki +Cc: Dave Hansen +Cc: Fenghua Yu +Cc: Gerald Schaefer +Cc: Greg Kroah-Hartman +Cc: Halil Pasic +Cc: Heiko Carstens +Cc: "H. Peter Anvin" +Cc: Ingo Molnar +Cc: Ira Weiny +Cc: Jason Gunthorpe +Cc: Jun Yao +Cc: Logan Gunthorpe +Cc: Mark Rutland +Cc: Masahiro Yamada +Cc: "Matthew Wilcox (Oracle)" +Cc: Mel Gorman +Cc: Michael Ellerman +Cc: Mike Rapoport +Cc: Pankaj Gupta +Cc: Paul Mackerras +Cc: Pavel Tatashin +Cc: Peter Zijlstra +Cc: Qian Cai +Cc: Rich Felker +Cc: Robin Murphy +Cc: Steve Capper +Cc: Thomas Gleixner +Cc: Tom Lendacky +Cc: Tony Luck +Cc: Vasily Gorbik +Cc: Vlastimil Babka +Cc: Wei Yang +Cc: Will Deacon +Cc: Yoshinori Sato +Cc: Yu Zhao +Cc: [4.13+] +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memory_hotplug.c | 77 ++++++++++------------------------------------------ + 1 file changed, 16 insertions(+), 61 deletions(-) + +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -459,70 +459,25 @@ static void shrink_zone_span(struct zone + zone_span_writeunlock(zone); + } + +-static void shrink_pgdat_span(struct pglist_data *pgdat, +- unsigned long start_pfn, unsigned long end_pfn) ++static void update_pgdat_span(struct pglist_data *pgdat) + { +- unsigned long pgdat_start_pfn = pgdat->node_start_pfn; +- unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */ +- unsigned long pgdat_end_pfn = p; +- unsigned long pfn; +- struct mem_section *ms; +- int nid = pgdat->node_id; +- +- if (pgdat_start_pfn == start_pfn) { +- /* +- * If the section is smallest section in the pgdat, it need +- * shrink pgdat->node_start_pfn and pgdat->node_spanned_pages. +- * In this case, we find second smallest valid mem_section +- * for shrinking zone. +- */ +- pfn = find_smallest_section_pfn(nid, NULL, end_pfn, +- pgdat_end_pfn); +- if (pfn) { +- pgdat->node_start_pfn = pfn; +- pgdat->node_spanned_pages = pgdat_end_pfn - pfn; +- } +- } else if (pgdat_end_pfn == end_pfn) { +- /* +- * If the section is biggest section in the pgdat, it need +- * shrink pgdat->node_spanned_pages. +- * In this case, we find second biggest valid mem_section for +- * shrinking zone. +- */ +- pfn = find_biggest_section_pfn(nid, NULL, pgdat_start_pfn, +- start_pfn); +- if (pfn) +- pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1; +- } +- +- /* +- * If the section is not biggest or smallest mem_section in the pgdat, +- * it only creates a hole in the pgdat. So in this case, we need not +- * change the pgdat. +- * But perhaps, the pgdat has only hole data. Thus it check the pgdat +- * has only hole or not. +- */ +- pfn = pgdat_start_pfn; +- for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SECTION) { +- ms = __pfn_to_section(pfn); +- +- if (unlikely(!valid_section(ms))) +- continue; +- +- if (pfn_to_nid(pfn) != nid) +- continue; +- +- /* If the section is current section, it continues the loop */ +- if (start_pfn == pfn) +- continue; ++ unsigned long node_start_pfn = 0, node_end_pfn = 0; ++ struct zone *zone; + +- /* If we find valid section, we have nothing to do */ +- return; ++ for (zone = pgdat->node_zones; ++ zone < pgdat->node_zones + MAX_NR_ZONES; zone++) { ++ unsigned long zone_end_pfn = zone->zone_start_pfn + ++ zone->spanned_pages; ++ ++ /* No need to lock the zones, they can't change. */ ++ if (zone_end_pfn > node_end_pfn) ++ node_end_pfn = zone_end_pfn; ++ if (zone->zone_start_pfn < node_start_pfn) ++ node_start_pfn = zone->zone_start_pfn; + } + +- /* The pgdat has no valid section */ +- pgdat->node_start_pfn = 0; +- pgdat->node_spanned_pages = 0; ++ pgdat->node_start_pfn = node_start_pfn; ++ pgdat->node_spanned_pages = node_end_pfn - node_start_pfn; + } + + static void __remove_zone(struct zone *zone, unsigned long start_pfn) +@@ -533,7 +488,7 @@ static void __remove_zone(struct zone *z + + pgdat_resize_lock(zone->zone_pgdat, &flags); + shrink_zone_span(zone, start_pfn, start_pfn + nr_pages); +- shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages); ++ update_pgdat_span(pgdat); + pgdat_resize_unlock(zone->zone_pgdat, &flags); + } + diff --git a/queue-4.14/mm-memory_hotplug-fix-updating-the-node-span.patch b/queue-4.14/mm-memory_hotplug-fix-updating-the-node-span.patch new file mode 100644 index 00000000000..5b96f45ee27 --- /dev/null +++ b/queue-4.14/mm-memory_hotplug-fix-updating-the-node-span.patch @@ -0,0 +1,63 @@ +From 656d571193262a11c2daa4012e53e4d645bbce56 Mon Sep 17 00:00:00 2001 +From: David Hildenbrand +Date: Tue, 5 Nov 2019 21:17:10 -0800 +Subject: mm/memory_hotplug: fix updating the node span + +From: David Hildenbrand + +commit 656d571193262a11c2daa4012e53e4d645bbce56 upstream. + +We recently started updating the node span based on the zone span to +avoid touching uninitialized memmaps. + +Currently, we will always detect the node span to start at 0, meaning a +node can easily span too many pages. pgdat_is_empty() will still work +correctly if all zones span no pages. We should skip over all zones +without spanned pages and properly handle the first detected zone that +spans pages. + +Unfortunately, in contrast to the zone span (/proc/zoneinfo), the node +span cannot easily be inspected and tested. The node span gives no real +guarantees when an architecture supports memory hotplug, meaning it can +easily contain holes or span pages of different nodes. + +The node span is not really used after init on architectures that +support memory hotplug. + +E.g., we use it in mm/memory_hotplug.c:try_offline_node() and in +mm/kmemleak.c:kmemleak_scan(). These users seem to be fine. + +Link: http://lkml.kernel.org/r/20191027222714.5313-1-david@redhat.com +Fixes: 00d6c019b5bc ("mm/memory_hotplug: don't access uninitialized memmaps in shrink_pgdat_span()") +Signed-off-by: David Hildenbrand +Cc: Michal Hocko +Cc: Oscar Salvador +Cc: Stephen Rothwell +Cc: Dan Williams +Cc: Pavel Tatashin +Cc: Greg Kroah-Hartman +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/memory_hotplug.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -470,6 +470,14 @@ static void update_pgdat_span(struct pgl + zone->spanned_pages; + + /* No need to lock the zones, they can't change. */ ++ if (!zone->spanned_pages) ++ continue; ++ if (!node_end_pfn) { ++ node_start_pfn = zone->zone_start_pfn; ++ node_end_pfn = zone_end_pfn; ++ continue; ++ } ++ + if (zone_end_pfn > node_end_pfn) + node_end_pfn = zone_end_pfn; + if (zone->zone_start_pfn < node_start_pfn) diff --git a/queue-4.14/series b/queue-4.14/series index 3514ebdbc0c..9fcbc2e5cc9 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -3,3 +3,6 @@ tee-optee-add-missing-of_node_put-after-of_device_is_available.patch revert-opp-protect-dev_list-with-opp_table-lock.patch net-cdc_ncm-signedness-bug-in-cdc_ncm_set_dgram_size.patch idr-fix-idr_get_next-race-with-idr_remove.patch +mm-memory_hotplug-don-t-access-uninitialized-memmaps-in-shrink_pgdat_span.patch +mm-memory_hotplug-fix-updating-the-node-span.patch +arm64-uaccess-ensure-pan-is-re-enabled-after-unhandled-uaccess-fault.patch