--- /dev/null
+From 94bb804e1e6f0a9a77acf20d7c70ea141c6c821e Mon Sep 17 00:00:00 2001
+From: Pavel Tatashin <pasha.tatashin@soleen.com>
+Date: Tue, 19 Nov 2019 17:10:06 -0500
+Subject: arm64: uaccess: Ensure PAN is re-enabled after unhandled uaccess fault
+
+From: Pavel Tatashin <pasha.tatashin@soleen.com>
+
+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 <catalin.marinas@arm.com>
+Reviewed-by: Mark Rutland <mark.rutland@arm.com>
+Tested-by: Mark Rutland <mark.rutland@arm.com>
+Cc: <stable@vger.kernel.org>
+Fixes: 338d4f49d6f7 ("arm64: kernel: Add support for Privileged Access Never")
+Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com>
+[will: rewrote commit message]
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
--- /dev/null
+From 00d6c019b5bc175cee3770e0e659f2b5f4804ea5 Mon Sep 17 00:00:00 2001
+From: David Hildenbrand <david@redhat.com>
+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 <david@redhat.com>
+
+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 <david@redhat.com>
+Reported-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: David Hildenbrand <david@redhat.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Pavel Tatashin <pasha.tatashin@soleen.com>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: Wei Yang <richardw.yang@linux.intel.com>
+Cc: Alexander Duyck <alexander.h.duyck@linux.intel.com>
+Cc: Alexander Potapenko <glider@google.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Anshuman Khandual <anshuman.khandual@arm.com>
+Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Christian Borntraeger <borntraeger@de.ibm.com>
+Cc: Christophe Leroy <christophe.leroy@c-s.fr>
+Cc: Damian Tometzki <damian.tometzki@gmail.com>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: Fenghua Yu <fenghua.yu@intel.com>
+Cc: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Halil Pasic <pasic@linux.ibm.com>
+Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Ira Weiny <ira.weiny@intel.com>
+Cc: Jason Gunthorpe <jgg@ziepe.ca>
+Cc: Jun Yao <yaojun8558363@gmail.com>
+Cc: Logan Gunthorpe <logang@deltatee.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
+Cc: Mel Gorman <mgorman@techsingularity.net>
+Cc: Michael Ellerman <mpe@ellerman.id.au>
+Cc: Mike Rapoport <rppt@linux.ibm.com>
+Cc: Pankaj Gupta <pagupta@redhat.com>
+Cc: Paul Mackerras <paulus@samba.org>
+Cc: Pavel Tatashin <pavel.tatashin@microsoft.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Qian Cai <cai@lca.pw>
+Cc: Rich Felker <dalias@libc.org>
+Cc: Robin Murphy <robin.murphy@arm.com>
+Cc: Steve Capper <steve.capper@arm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Tom Lendacky <thomas.lendacky@amd.com>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: Wei Yang <richard.weiyang@gmail.com>
+Cc: Will Deacon <will@kernel.org>
+Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
+Cc: Yu Zhao <yuzhao@google.com>
+Cc: <stable@vger.kernel.org> [4.13+]
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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);
+ }
+
--- /dev/null
+From 656d571193262a11c2daa4012e53e4d645bbce56 Mon Sep 17 00:00:00 2001
+From: David Hildenbrand <david@redhat.com>
+Date: Tue, 5 Nov 2019 21:17:10 -0800
+Subject: mm/memory_hotplug: fix updating the node span
+
+From: David Hildenbrand <david@redhat.com>
+
+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 <david@redhat.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Stephen Rothwell <sfr@canb.auug.org.au>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: Pavel Tatashin <pasha.tatashin@soleen.com>
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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)