diff options
author | Paul Gortmaker <paul.gortmaker@windriver.com> | 2018-03-06 15:36:52 -0500 |
---|---|---|
committer | Paul Gortmaker <paul.gortmaker@windriver.com> | 2018-03-06 15:36:52 -0500 |
commit | 0431dbb9f8ae2db584787fc83af5bc59439b3c3e (patch) | |
tree | fce109ea2e1d5eb765de60f05dbadb1e025650d9 | |
parent | 970f842fde372eba690f7a154635a67531cda804 (diff) | |
download | longterm-queue-4.8-0431dbb9f8ae2db584787fc83af5bc59439b3c3e.tar.gz |
add stack patches
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
9 files changed, 856 insertions, 0 deletions
diff --git a/queue/dma-api-Teach-the-DMA-from-stack-check-about-vmapped.patch b/queue/dma-api-Teach-the-DMA-from-stack-check-about-vmapped.patch new file mode 100644 index 0000000..b308073 --- /dev/null +++ b/queue/dma-api-Teach-the-DMA-from-stack-check-about-vmapped.patch @@ -0,0 +1,108 @@ +From b4a0f533e5976cb1a79f31d6152e1d322d79b7f1 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski <luto@kernel.org> +Date: Thu, 11 Aug 2016 02:35:22 -0700 +Subject: [PATCH] dma-api: Teach the "DMA-from-stack" check about vmapped + stacks + +commit b4a0f533e5976cb1a79f31d6152e1d322d79b7f1 upstream. + +If we're using CONFIG_VMAP_STACK=y and we manage to point an sg entry +at the stack, then either the sg page will be in highmem or sg_virt() +will return the direct-map alias. In neither case will the existing +check_for_stack() implementation realize that it's a stack page. + +Fix it by explicitly checking for stack pages. + +This has no effect by itself. It's broken out for ease of review. + +Signed-off-by: Andy Lutomirski <luto@kernel.org> +Cc: Andrew Morton <akpm@linux-foundation.org> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/448460622731312298bf19dcbacb1606e75de7a9.1470907718.git.luto@kernel.org +[ Minor edits. ] +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/lib/dma-debug.c b/lib/dma-debug.c +index fcfa1939ac41..06f02f6aecd2 100644 +--- a/lib/dma-debug.c ++++ b/lib/dma-debug.c +@@ -22,6 +22,7 @@ + #include <linux/stacktrace.h> + #include <linux/dma-debug.h> + #include <linux/spinlock.h> ++#include <linux/vmalloc.h> + #include <linux/debugfs.h> + #include <linux/uaccess.h> + #include <linux/export.h> +@@ -1164,11 +1165,32 @@ static void check_unmap(struct dma_debug_entry *ref) + put_hash_bucket(bucket, &flags); + } + +-static void check_for_stack(struct device *dev, void *addr) ++static void check_for_stack(struct device *dev, ++ struct page *page, size_t offset) + { +- if (object_is_on_stack(addr)) +- err_printk(dev, NULL, "DMA-API: device driver maps memory from " +- "stack [addr=%p]\n", addr); ++ void *addr; ++ struct vm_struct *stack_vm_area = task_stack_vm_area(current); ++ ++ if (!stack_vm_area) { ++ /* Stack is direct-mapped. */ ++ if (PageHighMem(page)) ++ return; ++ addr = page_address(page) + offset; ++ if (object_is_on_stack(addr)) ++ err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [addr=%p]\n", addr); ++ } else { ++ /* Stack is vmalloced. */ ++ int i; ++ ++ for (i = 0; i < stack_vm_area->nr_pages; i++) { ++ if (page != stack_vm_area->pages[i]) ++ continue; ++ ++ addr = (u8 *)current->stack + i * PAGE_SIZE + offset; ++ err_printk(dev, NULL, "DMA-API: device driver maps memory from stack [probable addr=%p]\n", addr); ++ break; ++ } ++ } + } + + static inline bool overlap(void *addr, unsigned long len, void *start, void *end) +@@ -1291,10 +1313,11 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, + if (map_single) + entry->type = dma_debug_single; + ++ check_for_stack(dev, page, offset); ++ + if (!PageHighMem(page)) { + void *addr = page_address(page) + offset; + +- check_for_stack(dev, addr); + check_for_illegal_area(dev, addr, size); + } + +@@ -1386,8 +1409,9 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, + entry->sg_call_ents = nents; + entry->sg_mapped_ents = mapped_ents; + ++ check_for_stack(dev, sg_page(s), s->offset); ++ + if (!PageHighMem(sg_page(s))) { +- check_for_stack(dev, sg_virt(s)); + check_for_illegal_area(dev, sg_virt(s), sg_dma_len(s)); + } + +-- +2.15.0 + diff --git a/queue/iommu-amd-Don-t-put-completion-wait-semaphore-on-sta.patch b/queue/iommu-amd-Don-t-put-completion-wait-semaphore-on-sta.patch new file mode 100644 index 0000000..9f9e30b --- /dev/null +++ b/queue/iommu-amd-Don-t-put-completion-wait-semaphore-on-sta.patch @@ -0,0 +1,151 @@ +From a3de0b63f25363f419fdf26144153dceb94981dd Mon Sep 17 00:00:00 2001 +From: Joerg Roedel <jroedel@suse.de> +Date: Wed, 14 Sep 2016 11:41:59 +0200 +Subject: [PATCH] iommu/amd: Don't put completion-wait semaphore on stack + +commit 4bf5beef578e46393f11eb69dda7d17a065e05ff upstream. + +The semaphore used by the AMD IOMMU to signal command +completion lived on the stack until now, which was safe as +the driver busy-waited on the semaphore with IRQs disabled, +so the stack can't go away under the driver. + +But the recently introduced vmap-based stacks break this as +the physical address of the semaphore can't be determinded +easily anymore. The driver used the __pa() macro, but that +only works in the direct-mapping. The result were +Completion-Wait timeout errors seen by the IOMMU driver, +breaking system boot. + +Since putting the semaphore on the stack is bad design +anyway, move the semaphore into 'struct amd_iommu'. It is +protected by the per-iommu lock and now in the direct +mapping again. This fixes the Completion-Wait timeout errors +and makes AMD IOMMU systems boot again with vmap-based +stacks enabled. + +Reported-by: Borislav Petkov <bp@alien8.de> +Signed-off-by: Joerg Roedel <jroedel@suse.de> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c +index 2d1f9d4c020f..ca127b8c8fea 100644 +--- a/drivers/iommu/amd_iommu.c ++++ b/drivers/iommu/amd_iommu.c +@@ -940,15 +940,13 @@ static void build_inv_irt(struct iommu_cmd *cmd, u16 devid) + * Writes the command to the IOMMUs command buffer and informs the + * hardware about the new command. + */ +-static int iommu_queue_command_sync(struct amd_iommu *iommu, +- struct iommu_cmd *cmd, +- bool sync) ++static int __iommu_queue_command_sync(struct amd_iommu *iommu, ++ struct iommu_cmd *cmd, ++ bool sync) + { + u32 left, tail, head, next_tail; +- unsigned long flags; + + again: +- spin_lock_irqsave(&iommu->lock, flags); + + head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET); + tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET); +@@ -957,15 +955,14 @@ again: + + if (left <= 0x20) { + struct iommu_cmd sync_cmd; +- volatile u64 sem = 0; + int ret; + +- build_completion_wait(&sync_cmd, (u64)&sem); +- copy_cmd_to_buffer(iommu, &sync_cmd, tail); ++ iommu->cmd_sem = 0; + +- spin_unlock_irqrestore(&iommu->lock, flags); ++ build_completion_wait(&sync_cmd, (u64)&iommu->cmd_sem); ++ copy_cmd_to_buffer(iommu, &sync_cmd, tail); + +- if ((ret = wait_on_sem(&sem)) != 0) ++ if ((ret = wait_on_sem(&iommu->cmd_sem)) != 0) + return ret; + + goto again; +@@ -976,9 +973,21 @@ again: + /* We need to sync now to make sure all commands are processed */ + iommu->need_sync = sync; + ++ return 0; ++} ++ ++static int iommu_queue_command_sync(struct amd_iommu *iommu, ++ struct iommu_cmd *cmd, ++ bool sync) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&iommu->lock, flags); ++ ret = __iommu_queue_command_sync(iommu, cmd, sync); + spin_unlock_irqrestore(&iommu->lock, flags); + +- return 0; ++ return ret; + } + + static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) +@@ -993,19 +1002,29 @@ static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd) + static int iommu_completion_wait(struct amd_iommu *iommu) + { + struct iommu_cmd cmd; +- volatile u64 sem = 0; ++ unsigned long flags; + int ret; + + if (!iommu->need_sync) + return 0; + +- build_completion_wait(&cmd, (u64)&sem); + +- ret = iommu_queue_command_sync(iommu, &cmd, false); ++ build_completion_wait(&cmd, (u64)&iommu->cmd_sem); ++ ++ spin_lock_irqsave(&iommu->lock, flags); ++ ++ iommu->cmd_sem = 0; ++ ++ ret = __iommu_queue_command_sync(iommu, &cmd, false); + if (ret) +- return ret; ++ goto out_unlock; ++ ++ ret = wait_on_sem(&iommu->cmd_sem); + +- return wait_on_sem(&sem); ++out_unlock: ++ spin_unlock_irqrestore(&iommu->lock, flags); ++ ++ return ret; + } + + static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) +diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h +index caf5e3822715..9652848e3155 100644 +--- a/drivers/iommu/amd_iommu_types.h ++++ b/drivers/iommu/amd_iommu_types.h +@@ -524,6 +524,8 @@ struct amd_iommu { + struct irq_domain *ir_domain; + struct irq_domain *msi_domain; + #endif ++ ++ volatile u64 __aligned(8) cmd_sem; + }; + + #define ACPIHID_UID_LEN 256 +-- +2.15.0 + diff --git a/queue/kthread-Pin-the-stack-via-try_get_task_stack-put_tas.patch b/queue/kthread-Pin-the-stack-via-try_get_task_stack-put_tas.patch new file mode 100644 index 0000000..3bccea6 --- /dev/null +++ b/queue/kthread-Pin-the-stack-via-try_get_task_stack-put_tas.patch @@ -0,0 +1,75 @@ +From 4f20a35ad56f5ee15bbcc4e14966960647931940 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov <oleg@redhat.com> +Date: Thu, 15 Sep 2016 22:45:44 -0700 +Subject: [PATCH] kthread: Pin the stack via + try_get_task_stack()/put_task_stack() in to_live_kthread() function + +commit 23196f2e5f5d810578a772785807dcdc2b9fdce9 upstream. + +get_task_struct(tsk) no longer pins tsk->stack so all users of +to_live_kthread() should do try_get_task_stack/put_task_stack to protect +"struct kthread" which lives on kthread's stack. + +TODO: Kill to_live_kthread(), perhaps we can even kill "struct kthread" too, +and rework kthread_stop(), it can use task_work_add() to sync with the exiting +kernel thread. + +Message-Id: <20160629180357.GA7178@redhat.com> +Signed-off-by: Oleg Nesterov <oleg@redhat.com> +Signed-off-by: Andy Lutomirski <luto@kernel.org> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Jann Horn <jann@thejh.net> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/cb9b16bbc19d4aea4507ab0552e4644c1211d130.1474003868.git.luto@kernel.org +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/kernel/kthread.c b/kernel/kthread.c +index 850b255649a2..d982c65f1578 100644 +--- a/kernel/kthread.c ++++ b/kernel/kthread.c +@@ -65,7 +65,7 @@ static inline struct kthread *to_kthread(struct task_struct *k) + static struct kthread *to_live_kthread(struct task_struct *k) + { + struct completion *vfork = ACCESS_ONCE(k->vfork_done); +- if (likely(vfork)) ++ if (likely(vfork) && try_get_task_stack(k)) + return __to_kthread(vfork); + return NULL; + } +@@ -427,8 +427,10 @@ void kthread_unpark(struct task_struct *k) + { + struct kthread *kthread = to_live_kthread(k); + +- if (kthread) ++ if (kthread) { + __kthread_unpark(k, kthread); ++ put_task_stack(k); ++ } + } + EXPORT_SYMBOL_GPL(kthread_unpark); + +@@ -457,6 +459,7 @@ int kthread_park(struct task_struct *k) + wait_for_completion(&kthread->parked); + } + } ++ put_task_stack(k); + ret = 0; + } + return ret; +@@ -492,6 +495,7 @@ int kthread_stop(struct task_struct *k) + __kthread_unpark(k, kthread); + wake_up_process(k); + wait_for_completion(&kthread->exited); ++ put_task_stack(k); + } + ret = k->exit_code; + put_task_struct(k); +-- +2.15.0 + diff --git a/queue/lib-syscall-Pin-the-task-stack-in-collect_syscall.patch b/queue/lib-syscall-Pin-the-task-stack-in-collect_syscall.patch new file mode 100644 index 0000000..dd86783 --- /dev/null +++ b/queue/lib-syscall-Pin-the-task-stack-in-collect_syscall.patch @@ -0,0 +1,60 @@ +From 92040c8c2cd1a408802bea57fb586ccbb7a59c15 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski <luto@kernel.org> +Date: Thu, 15 Sep 2016 22:45:47 -0700 +Subject: [PATCH] lib/syscall: Pin the task stack in collect_syscall() + +commit aa1f1a639621672b68f654dc815a7d8298ff396f upstream. + +This will avoid a potential read-after-free if collect_syscall() +(e.g. /proc/PID/syscall) is called on an exiting task. + +Reported-by: Jann Horn <jann@thejh.net> +Signed-off-by: Andy Lutomirski <luto@kernel.org> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/0bfd8e6d4729c97745d3781a29610a33d0a8091d.1474003868.git.luto@kernel.org +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/lib/syscall.c b/lib/syscall.c +index e30e03932480..63239e097b13 100644 +--- a/lib/syscall.c ++++ b/lib/syscall.c +@@ -7,9 +7,19 @@ static int collect_syscall(struct task_struct *target, long *callno, + unsigned long args[6], unsigned int maxargs, + unsigned long *sp, unsigned long *pc) + { +- struct pt_regs *regs = task_pt_regs(target); +- if (unlikely(!regs)) ++ struct pt_regs *regs; ++ ++ if (!try_get_task_stack(target)) { ++ /* Task has no stack, so the task isn't in a syscall. */ ++ *callno = -1; ++ return 0; ++ } ++ ++ regs = task_pt_regs(target); ++ if (unlikely(!regs)) { ++ put_task_stack(target); + return -EAGAIN; ++ } + + *sp = user_stack_pointer(regs); + *pc = instruction_pointer(regs); +@@ -18,6 +28,7 @@ static int collect_syscall(struct task_struct *target, long *callno, + if (*callno != -1L && maxargs > 0) + syscall_get_arguments(target, regs, 0, maxargs, args); + ++ put_task_stack(target); + return 0; + } + +-- +2.15.0 + diff --git a/queue/mm-kmemleak-ensure-that-the-task-stack-is-not-freed-.patch b/queue/mm-kmemleak-ensure-that-the-task-stack-is-not-freed-.patch new file mode 100644 index 0000000..a6e55bb --- /dev/null +++ b/queue/mm-kmemleak-ensure-that-the-task-stack-is-not-freed-.patch @@ -0,0 +1,52 @@ +From 37df49f433bc3a11f5716fe65aaec5189c6402cb Mon Sep 17 00:00:00 2001 +From: Catalin Marinas <catalin.marinas@arm.com> +Date: Thu, 27 Oct 2016 17:46:47 -0700 +Subject: [PATCH] mm: kmemleak: ensure that the task stack is not freed during + scanning + +commit 37df49f433bc3a11f5716fe65aaec5189c6402cb upstream. + +Commit 68f24b08ee89 ("sched/core: Free the stack early if +CONFIG_THREAD_INFO_IN_TASK") may cause the task->stack to be freed +during kmemleak_scan() execution, leading to either a NULL pointer fault +(if task->stack is NULL) or kmemleak accessing already freed memory. + +This patch uses the new try_get_task_stack() API to ensure that the task +stack is not freed during kmemleak stack scanning. + +Addresses https://bugzilla.kernel.org/show_bug.cgi?id=173901. + +Fixes: 68f24b08ee89 ("sched/core: Free the stack early if CONFIG_THREAD_INFO_IN_TASK") +Link: http://lkml.kernel.org/r/1476266223-14325-1-git-send-email-catalin.marinas@arm.com +Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> +Reported-by: CAI Qian <caiqian@redhat.com> +Tested-by: CAI Qian <caiqian@redhat.com> +Acked-by: Michal Hocko <mhocko@suse.com> +Cc: Andy Lutomirski <luto@kernel.org> +Cc: CAI Qian <caiqian@redhat.com> +Cc: Hillf Danton <hillf.zj@alibaba-inc.com> +Cc: Oleg Nesterov <oleg@redhat.com> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> + +diff --git a/mm/kmemleak.c b/mm/kmemleak.c +index a5e453cf05c4..e5355a5b423f 100644 +--- a/mm/kmemleak.c ++++ b/mm/kmemleak.c +@@ -1453,8 +1453,11 @@ static void kmemleak_scan(void) + + read_lock(&tasklist_lock); + do_each_thread(g, p) { +- scan_block(task_stack_page(p), task_stack_page(p) + +- THREAD_SIZE, NULL); ++ void *stack = try_get_task_stack(p); ++ if (stack) { ++ scan_block(stack, stack + THREAD_SIZE, NULL); ++ put_task_stack(p); ++ } + } while_each_thread(g, p); + read_unlock(&tasklist_lock); + } +-- +2.15.0 + diff --git a/queue/series b/queue/series index 9aa0e96..5051e98 100644 --- a/queue/series +++ b/queue/series @@ -1,2 +1,23 @@ +# v4.9-rc1~160^2~60 +dma-api-Teach-the-DMA-from-stack-check-about-vmapped.patch +# v4.9-rc1~160^2~21 +iommu-amd-Don-t-put-completion-wait-semaphore-on-sta.patch +# v4.9-rc1~160^2~18 +kthread-Pin-the-stack-via-try_get_task_stack-put_tas.patch +# v4.9-rc1~160^2~17 +x86-dumpstack-Pin-the-target-stack-when-dumping-it.patch +# v4.9-rc1~160^2~16 +x86-process-Pin-the-target-stack-in-get_wchan.patch +# v4.9-rc1~160^2~15 +lib-syscall-Pin-the-task-stack-in-collect_syscall.patch +# v4.9-rc1~160^2~14 +# sched/core: Free the stack early if CONFIG_THREAD_INFO_IN_TASK + +# v4.9-rc3~24^2~9 +mm-kmemleak-ensure-that-the-task-stack-is-not-freed-.patch + +# v4.9-rc6~36^2 +x86-efi-Prevent-mixed-mode-boot-corruption-with-CONF.patch + # v4.14-rc7~7 assoc_array-Fix-a-buggy-node-splitting-case.patch diff --git a/queue/x86-dumpstack-Pin-the-target-stack-when-dumping-it.patch b/queue/x86-dumpstack-Pin-the-target-stack-when-dumping-it.patch new file mode 100644 index 0000000..811d2e7 --- /dev/null +++ b/queue/x86-dumpstack-Pin-the-target-stack-when-dumping-it.patch @@ -0,0 +1,94 @@ +From 8a567429ebb70da56eb63f05deee51d9328c5c00 Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski <luto@kernel.org> +Date: Thu, 15 Sep 2016 22:45:45 -0700 +Subject: [PATCH] x86/dumpstack: Pin the target stack when dumping it + +commit 1959a60182f48879635812a03a99c02231ea8677 upstream. + +Specifically, pin the stack in save_stack_trace_tsk() and +show_trace_log_lvl(). + +This will prevent a crash if the target task dies before or while +dumping its stack once we start freeing task stacks early. + +Signed-off-by: Andy Lutomirski <luto@kernel.org> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Jann Horn <jann@thejh.net> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/cf0082cde65d1941a996d026f2b2cdbfaca17bfa.1474003868.git.luto@kernel.org +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c +index 09675712eba8..8ad32dc94e8d 100644 +--- a/arch/x86/kernel/dumpstack_32.c ++++ b/arch/x86/kernel/dumpstack_32.c +@@ -95,6 +95,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + unsigned long *stack; + int i; + ++ if (!try_get_task_stack(task)) ++ return; ++ + if (sp == NULL) { + if (regs) + sp = (unsigned long *)regs->sp; +@@ -118,6 +121,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + } + pr_cont("\n"); + show_trace_log_lvl(task, regs, sp, bp, log_lvl); ++ ++ put_task_stack(task); + } + + +diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c +index 9ee4520ce83c..1bcdb164afd9 100644 +--- a/arch/x86/kernel/dumpstack_64.c ++++ b/arch/x86/kernel/dumpstack_64.c +@@ -253,6 +253,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + int cpu; + int i; + ++ if (!try_get_task_stack(task)) ++ return; ++ + preempt_disable(); + cpu = smp_processor_id(); + +@@ -303,6 +306,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, + + pr_cont("\n"); + show_trace_log_lvl(task, regs, sp, bp, log_lvl); ++ ++ put_task_stack(task); + } + + void show_regs(struct pt_regs *regs) +diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c +index 4738f5e0f2ab..b3f32fbe3ba4 100644 +--- a/arch/x86/kernel/stacktrace.c ++++ b/arch/x86/kernel/stacktrace.c +@@ -79,9 +79,14 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) + + void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) + { ++ if (!try_get_task_stack(tsk)) ++ return; ++ + dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; ++ ++ put_task_stack(tsk); + } + EXPORT_SYMBOL_GPL(save_stack_trace_tsk); + +-- +2.15.0 + diff --git a/queue/x86-efi-Prevent-mixed-mode-boot-corruption-with-CONF.patch b/queue/x86-efi-Prevent-mixed-mode-boot-corruption-with-CONF.patch new file mode 100644 index 0000000..0d649d8 --- /dev/null +++ b/queue/x86-efi-Prevent-mixed-mode-boot-corruption-with-CONF.patch @@ -0,0 +1,217 @@ +From f6697df36bdf0bf7fce984605c2918d4a7b4269f Mon Sep 17 00:00:00 2001 +From: Matt Fleming <matt@codeblueprint.co.uk> +Date: Sat, 12 Nov 2016 21:04:24 +0000 +Subject: [PATCH] x86/efi: Prevent mixed mode boot corruption with + CONFIG_VMAP_STACK=y + +commit f6697df36bdf0bf7fce984605c2918d4a7b4269f upstream. + +Booting an EFI mixed mode kernel has been crashing since commit: + + e37e43a497d5 ("x86/mm/64: Enable vmapped stacks (CONFIG_HAVE_ARCH_VMAP_STACK=y)") + +The user-visible effect in my test setup was the kernel being unable +to find the root file system ramdisk. This was likely caused by silent +memory or page table corruption. + +Enabling CONFIG_DEBUG_VIRTUAL=y immediately flagged the thunking code as +abusing virt_to_phys() because it was passing addresses that were not +part of the kernel direct mapping. + +Use the slow version instead, which correctly handles all memory +regions by performing a page table walk. + +Suggested-by: Andy Lutomirski <luto@amacapital.net> +Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk> +Cc: Andy Lutomirski <luto@kernel.org> +Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Cc: linux-efi@vger.kernel.org +Link: http://lkml.kernel.org/r/20161112210424.5157-3-matt@codeblueprint.co.uk +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c +index 58b0f801f66f..319148bd4b05 100644 +--- a/arch/x86/platform/efi/efi_64.c ++++ b/arch/x86/platform/efi/efi_64.c +@@ -31,6 +31,7 @@ + #include <linux/io.h> + #include <linux/reboot.h> + #include <linux/slab.h> ++#include <linux/ucs2_string.h> + + #include <asm/setup.h> + #include <asm/page.h> +@@ -211,6 +212,35 @@ void efi_sync_low_kernel_mappings(void) + memcpy(pud_efi, pud_k, sizeof(pud_t) * num_entries); + } + ++/* ++ * Wrapper for slow_virt_to_phys() that handles NULL addresses. ++ */ ++static inline phys_addr_t ++virt_to_phys_or_null_size(void *va, unsigned long size) ++{ ++ bool bad_size; ++ ++ if (!va) ++ return 0; ++ ++ if (virt_addr_valid(va)) ++ return virt_to_phys(va); ++ ++ /* ++ * A fully aligned variable on the stack is guaranteed not to ++ * cross a page bounary. Try to catch strings on the stack by ++ * checking that 'size' is a power of two. ++ */ ++ bad_size = size > PAGE_SIZE || !is_power_of_2(size); ++ ++ WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size); ++ ++ return slow_virt_to_phys(va); ++} ++ ++#define virt_to_phys_or_null(addr) \ ++ virt_to_phys_or_null_size((addr), sizeof(*(addr))) ++ + int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) + { + unsigned long pfn, text; +@@ -494,8 +524,8 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc) + + spin_lock(&rtc_lock); + +- phys_tm = virt_to_phys(tm); +- phys_tc = virt_to_phys(tc); ++ phys_tm = virt_to_phys_or_null(tm); ++ phys_tc = virt_to_phys_or_null(tc); + + status = efi_thunk(get_time, phys_tm, phys_tc); + +@@ -511,7 +541,7 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm) + + spin_lock(&rtc_lock); + +- phys_tm = virt_to_phys(tm); ++ phys_tm = virt_to_phys_or_null(tm); + + status = efi_thunk(set_time, phys_tm); + +@@ -529,9 +559,9 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, + + spin_lock(&rtc_lock); + +- phys_enabled = virt_to_phys(enabled); +- phys_pending = virt_to_phys(pending); +- phys_tm = virt_to_phys(tm); ++ phys_enabled = virt_to_phys_or_null(enabled); ++ phys_pending = virt_to_phys_or_null(pending); ++ phys_tm = virt_to_phys_or_null(tm); + + status = efi_thunk(get_wakeup_time, phys_enabled, + phys_pending, phys_tm); +@@ -549,7 +579,7 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) + + spin_lock(&rtc_lock); + +- phys_tm = virt_to_phys(tm); ++ phys_tm = virt_to_phys_or_null(tm); + + status = efi_thunk(set_wakeup_time, enabled, phys_tm); + +@@ -558,6 +588,10 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) + return status; + } + ++static unsigned long efi_name_size(efi_char16_t *name) ++{ ++ return ucs2_strsize(name, EFI_VAR_NAME_LEN) + 1; ++} + + static efi_status_t + efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, +@@ -567,11 +601,11 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 phys_name, phys_vendor, phys_attr; + u32 phys_data_size, phys_data; + +- phys_data_size = virt_to_phys(data_size); +- phys_vendor = virt_to_phys(vendor); +- phys_name = virt_to_phys(name); +- phys_attr = virt_to_phys(attr); +- phys_data = virt_to_phys(data); ++ phys_data_size = virt_to_phys_or_null(data_size); ++ phys_vendor = virt_to_phys_or_null(vendor); ++ phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); ++ phys_attr = virt_to_phys_or_null(attr); ++ phys_data = virt_to_phys_or_null_size(data, *data_size); + + status = efi_thunk(get_variable, phys_name, phys_vendor, + phys_attr, phys_data_size, phys_data); +@@ -586,9 +620,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 phys_name, phys_vendor, phys_data; + efi_status_t status; + +- phys_name = virt_to_phys(name); +- phys_vendor = virt_to_phys(vendor); +- phys_data = virt_to_phys(data); ++ phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); ++ phys_vendor = virt_to_phys_or_null(vendor); ++ phys_data = virt_to_phys_or_null_size(data, data_size); + + /* If data_size is > sizeof(u32) we've got problems */ + status = efi_thunk(set_variable, phys_name, phys_vendor, +@@ -605,9 +639,9 @@ efi_thunk_get_next_variable(unsigned long *name_size, + efi_status_t status; + u32 phys_name_size, phys_name, phys_vendor; + +- phys_name_size = virt_to_phys(name_size); +- phys_vendor = virt_to_phys(vendor); +- phys_name = virt_to_phys(name); ++ phys_name_size = virt_to_phys_or_null(name_size); ++ phys_vendor = virt_to_phys_or_null(vendor); ++ phys_name = virt_to_phys_or_null_size(name, *name_size); + + status = efi_thunk(get_next_variable, phys_name_size, + phys_name, phys_vendor); +@@ -621,7 +655,7 @@ efi_thunk_get_next_high_mono_count(u32 *count) + efi_status_t status; + u32 phys_count; + +- phys_count = virt_to_phys(count); ++ phys_count = virt_to_phys_or_null(count); + status = efi_thunk(get_next_high_mono_count, phys_count); + + return status; +@@ -633,7 +667,7 @@ efi_thunk_reset_system(int reset_type, efi_status_t status, + { + u32 phys_data; + +- phys_data = virt_to_phys(data); ++ phys_data = virt_to_phys_or_null_size(data, data_size); + + efi_thunk(reset_system, reset_type, status, data_size, phys_data); + } +@@ -661,9 +695,9 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space, + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) + return EFI_UNSUPPORTED; + +- phys_storage = virt_to_phys(storage_space); +- phys_remaining = virt_to_phys(remaining_space); +- phys_max = virt_to_phys(max_variable_size); ++ phys_storage = virt_to_phys_or_null(storage_space); ++ phys_remaining = virt_to_phys_or_null(remaining_space); ++ phys_max = virt_to_phys_or_null(max_variable_size); + + status = efi_thunk(query_variable_info, attr, phys_storage, + phys_remaining, phys_max); +-- +2.15.0 + diff --git a/queue/x86-process-Pin-the-target-stack-in-get_wchan.patch b/queue/x86-process-Pin-the-target-stack-in-get_wchan.patch new file mode 100644 index 0000000..550411f --- /dev/null +++ b/queue/x86-process-Pin-the-target-stack-in-get_wchan.patch @@ -0,0 +1,78 @@ +From 57d2b47069f4fb80f0736f9101a5899b361bb18f Mon Sep 17 00:00:00 2001 +From: Andy Lutomirski <luto@kernel.org> +Date: Thu, 15 Sep 2016 22:45:46 -0700 +Subject: [PATCH] x86/process: Pin the target stack in get_wchan() + +commit 74327a3e884a0ff895ba7b51d3488e6a177407b2 upstream. + +This will prevent a crash if get_wchan() runs after the task stack +is freed. + +Signed-off-by: Andy Lutomirski <luto@kernel.org> +Cc: Borislav Petkov <bp@alien8.de> +Cc: Brian Gerst <brgerst@gmail.com> +Cc: Denys Vlasenko <dvlasenk@redhat.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Jann Horn <jann@thejh.net> +Cc: Josh Poimboeuf <jpoimboe@redhat.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: Peter Zijlstra <peterz@infradead.org> +Cc: Thomas Gleixner <tglx@linutronix.de> +Link: http://lkml.kernel.org/r/337aeca8614024aa4d8d9c81053bbf8fcffbe4ad.1474003868.git.luto@kernel.org +Signed-off-by: Ingo Molnar <mingo@kernel.org> + +diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c +index 8089f4955bbc..26c7ffa8190c 100644 +--- a/arch/x86/kernel/process.c ++++ b/arch/x86/kernel/process.c +@@ -520,15 +520,18 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) + */ + unsigned long get_wchan(struct task_struct *p) + { +- unsigned long start, bottom, top, sp, fp, ip; ++ unsigned long start, bottom, top, sp, fp, ip, ret = 0; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + ++ if (!try_get_task_stack(p)) ++ return 0; ++ + start = (unsigned long)task_stack_page(p); + if (!start) +- return 0; ++ goto out; + + /* + * Layout of the stack page: +@@ -552,16 +555,21 @@ unsigned long get_wchan(struct task_struct *p) + + sp = READ_ONCE(p->thread.sp); + if (sp < bottom || sp > top) +- return 0; ++ goto out; + + fp = READ_ONCE_NOCHECK(((struct inactive_task_frame *)sp)->bp); + do { + if (fp < bottom || fp > top) +- return 0; ++ goto out; + ip = READ_ONCE_NOCHECK(*(unsigned long *)(fp + sizeof(unsigned long))); +- if (!in_sched_functions(ip)) +- return ip; ++ if (!in_sched_functions(ip)) { ++ ret = ip; ++ goto out; ++ } + fp = READ_ONCE_NOCHECK(*(unsigned long *)fp); + } while (count++ < 16 && p->state != TASK_RUNNING); +- return 0; ++ ++out: ++ put_task_stack(p); ++ return ret; + } +-- +2.15.0 + |