Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1431600 > unrolled thread
| Started by | Andy Lutomirski <luto@kernel.org> |
|---|---|
| First post | 2016-06-27 00:00 +0200 |
| Last post | 2016-06-28 15:30 +0200 |
| Articles | 20 on this page of 70 — 11 participants |
Back to article view | Back to linux.kernel
[PATCH v4 00/29] virtually mapped stacks and thread_info cleanup Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 07/29] mm: Fix memcg stack accounting for sub-page stacks Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 24/29] x86/entry: Get rid of pt_regs_to_thread_info() Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Borislav Petkov <bp@alien8.de> - 2016-07-02 19:30 +0200
Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Josh Poimboeuf <jpoimboe@redhat.com> - 2016-07-02 20:40 +0200
Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Borislav Petkov <bp@alien8.de> - 2016-07-03 11:50 +0200
Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Andy Lutomirski <luto@amacapital.net> - 2016-07-03 16:30 +0200
Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack Borislav Petkov <bp@alien8.de> - 2016-07-03 20:50 +0200
[PATCH v4 12/29] x86/dumpstack: When dumping stack bytes due to OOPS, start with regs->sp Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 06/29] mm: Track NR_KERNEL_STACK in KiB instead of number of stacks Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 14/29] x86/dumpstack/64: Handle faults when printing the "Stack:" part of an OOPS Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
[PATCH v4 26/29] sched: Allow putting thread_info into task_struct Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct Mark Rutland <mark.rutland@arm.com> - 2016-07-11 12:10 +0200
Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct Andy Lutomirski <luto@amacapital.net> - 2016-07-11 17:00 +0200
Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct Mark Rutland <mark.rutland@arm.com> - 2016-07-11 17:10 +0200
Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct Mark Rutland <mark.rutland@arm.com> - 2016-07-11 18:40 +0200
Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct Linus Torvalds <torvalds@linux-foundation.org> - 2016-07-11 18:50 +0200
[PATCH v4 08/29] dma-api: Teach the "DMA-from-stack" check about vmapped stacks Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:00 +0200
Re: [PATCH v4 08/29] dma-api: Teach the "DMA-from-stack" check about vmapped stacks Borislav Petkov <bp@alien8.de> - 2016-06-30 21:40 +0200
Re: [PATCH v4 08/29] dma-api: Teach the "DMA-from-stack" check about vmapped stacks Andy Lutomirski <luto@amacapital.net> - 2016-07-06 15:30 +0200
[PATCH v4 25/29] um: Stop conflating task_struct::stack with thread_info Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 25/29] um: Stop conflating task_struct::stack with thread_info Andy Lutomirski <luto@amacapital.net> - 2016-06-27 01:50 +0200
Re: [PATCH v4 25/29] um: Stop conflating task_struct::stack with thread_info Brian Gerst <brgerst@gmail.com> - 2016-06-27 01:50 +0200
[PATCH v4 22/29] x86/asm: Move 'status' from struct thread_info to struct thread_struct Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 22/29] x86/asm: Move 'status' from struct thread_info to struct thread_struct Brian Gerst <brgerst@gmail.com> - 2016-06-27 02:00 +0200
Re: [PATCH v4 22/29] x86/asm: Move 'status' from struct thread_info to struct thread_struct Andy Lutomirski <luto@amacapital.net> - 2016-06-27 02:30 +0200
Re: [PATCH v4 22/29] x86/asm: Move 'status' from struct thread_info to struct thread_struct Brian Gerst <brgerst@gmail.com> - 2016-06-27 02:40 +0200
Re: [PATCH v4 22/29] x86/asm: Move 'status' from struct thread_info to struct thread_struct Andy Lutomirski <luto@amacapital.net> - 2016-06-27 02:50 +0200
[PATCH v4 19/29] signal: Consolidate {TS,TLF}_RESTORE_SIGMASK code Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Brian Gerst <brgerst@gmail.com> - 2016-06-27 17:10 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Brian Gerst <brgerst@gmail.com> - 2016-06-27 17:20 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Andy Lutomirski <luto@amacapital.net> - 2016-06-27 17:30 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Andy Lutomirski <luto@amacapital.net> - 2016-06-27 18:00 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Brian Gerst <brgerst@gmail.com> - 2016-06-27 18:20 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Andy Lutomirski <luto@amacapital.net> - 2016-06-27 18:40 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Brian Gerst <brgerst@gmail.com> - 2016-06-27 19:10 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Brian Gerst <brgerst@gmail.com> - 2016-06-27 19:30 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Linus Torvalds <torvalds@linux-foundation.org> - 2016-06-27 19:30 +0200
Re: [PATCH v4 15/29] x86/mm/64: Enable vmapped stacks Andy Lutomirski <luto@amacapital.net> - 2016-06-27 19:40 +0200
[PATCH v4 18/29] x86: Move addr_limit to thread_struct Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 17/29] x86: Move uaccess_err and sig_on_uaccess_err to thread_struct Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 03/29] x86/mm/hotplug: Don't remove PGD entries in remove_pagetable() Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 23/29] kdb: Use task_cpu() instead of task_thread_info()->cpu Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 16/29] x86/mm: Improve stack-overflow #PF handling Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 20/29] x86/smp: Remove stack_smp_processor_id() Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
[PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 09:40 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad Herbert Xu <herbert@gondor.apana.org.au> - 2016-06-28 09:40 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 11:10 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad Herbert Xu <herbert@gondor.apana.org.au> - 2016-06-28 11:50 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 09:50 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 10:00 +0200
[PATCH v4 04/29] x86/cpa: In populate_pgd, don't set the pgd entry until it's populated Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 04/29] x86/cpa: In populate_pgd, don't set the pgd entry until it's populated Borislav Petkov <bp@alien8.de> - 2016-06-28 21:10 +0200
Re: [PATCH v4 04/29] x86/cpa: In populate_pgd, don't set the pgd entry until it's populated Andy Lutomirski <luto@amacapital.net> - 2016-06-28 21:10 +0200
[PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Marcel Holtmann <marcel@holtmann.org> - 2016-06-27 08:00 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Ingo Molnar <mingo@kernel.org> - 2016-06-27 11:00 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Marcel Holtmann <marcel@holtmann.org> - 2016-06-28 00:40 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Andy Lutomirski <luto@amacapital.net> - 2016-06-28 00:40 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Marcel Holtmann <marcel@holtmann.org> - 2016-07-04 20:00 +0200
Re: [PATCH v4 01/29] bluetooth: Switch SMP to crypto_cipher_encrypt_one() Andy Lutomirski <luto@amacapital.net> - 2016-07-06 15:20 +0200
[PATCH v4 21/29] x86/smp: Remove unnecessary initialization of thread_info::cpu Andy Lutomirski <luto@kernel.org> - 2016-06-27 00:10 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad Herbert Xu <herbert@gondor.apana.org.au> - 2016-06-28 10:00 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 11:00 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad Herbert Xu <herbert@gondor.apana.org.au> - 2016-06-28 11:50 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 12:10 +0200
Re: [PATCH v4 02/29] rxrpc: Avoid using stack memory in SG lists in rxkad David Howells <dhowells@redhat.com> - 2016-06-28 15:30 +0200
Page 1 of 4 [1] 2 3 4 Next page →
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 00/29] virtually mapped stacks and thread_info cleanup |
| Message-ID | <rOqfT-8f8-5@gated-at.bofh.it> |
Hi all-
Since the dawn of time, a kernel stack overflow has been a real PITA
to debug, has caused nondeterministic crashes some time after the
actual overflow, and has generally been easy to exploit for root.
With this series, arches can enable HAVE_ARCH_VMAP_STACK. Arches
that enable it (just x86 for now) get virtually mapped stacks with
guard pages. This causes reliable faults when the stack overflows.
If the arch implements it well, we get a nice OOPS on stack overflow
(as opposed to panicing directly or otherwise exploding badly). On
x86, the OOPS is nice, has a usable call trace, and the overflowing
task is killed cleanly.
This series (starting with this version, v4) also extensively cleans
up thread_info. thread_info has been partially redundant with
thread_struct for a long time -- both are places for arch code to
add additional per-task variables. thread_struct is much cleaner:
it's always in task_struct, and there's nothing particularly magical
about it. So this series contains a bunch of cleanups on x86 to
move almost everything from thread_info to thread_struct (which,
even by itself, deletes more code than it adds) and to remove x86's
dependence on thread_info's position on the stack. Then it opts x86
into a new config option THREAD_INFO_IN_TASK to get rid of
arch-specific thread_info entirely and simply embed a defanged
thread_info (containing only flags) and 'int cpu' into task_struct.
Once thread_info stops being magical, there's another benefit: we
can free the thread stack as soon as the task is dead (without
waiting for RCU) and then, if vmapped stacks are in use, cache the
entire stack for reuse on the same cpu.
This seems to be an overall speedup of about 0.5-1 µs per
pthread_create/join in a simple test -- a percpu cache of vmalloced
stacks appears to be a bit faster than a high-order stack
allocation, at least when the cache hits. (I expect that workloads
with a low cache hit rate are likely to be dominated by other
effects anyway.)
This does not address interrupt stacks.
It's worth noting that s390 has an arch-specific gcc feature that
detects stack overflows by adjusting function prologues. Arches
with features like that may wish to avoid using vmapped stacks to
minimize the performance hit.
Known issues:
- tcp md5, virtio_net, and virtio_console will have issues. Eric Dumazet
has a patch for tcp md5, and Michael Tsirkin says he'll fix virtio_net
and virtio_console.
Changes from v3:
- Minor cleanups
- Rebased onto Linus' tree
- All the thread_info stuff is new
Changes from v2:
- Delete kerne_unmap_pages_in_pgd rather than hardening it (Borislav)
- Fix sub-page stack accounting better (Josh)
Changes from v1:
- Fix rewind_stack_and_do_exit (Josh)
- Fix deadlock under load
- Clean up generic stack vmalloc code
- Many other minor fixes
Andy Lutomirski (25):
bluetooth: Switch SMP to crypto_cipher_encrypt_one()
x86/cpa: In populate_pgd, don't set the pgd entry until it's populated
x86/mm: Remove kernel_unmap_pages_in_pgd() and
efi_cleanup_page_tables()
mm: Track NR_KERNEL_STACK in KiB instead of number of stacks
mm: Fix memcg stack accounting for sub-page stacks
dma-api: Teach the "DMA-from-stack" check about vmapped stacks
fork: Add generic vmalloced stack support
x86/die: Don't try to recover from an OOPS on a non-default stack
x86/dumpstack: When OOPSing, rewind the stack before do_exit
x86/dumpstack: When dumping stack bytes due to OOPS, start with
regs->sp
x86/dumpstack: Try harder to get a call trace on stack overflow
x86/dumpstack/64: Handle faults when printing the "Stack:" part of an
OOPS
x86/mm/64: Enable vmapped stacks
x86/mm: Improve stack-overflow #PF handling
x86: Move uaccess_err and sig_on_uaccess_err to thread_struct
x86: Move addr_limit to thread_struct
signal: Consolidate {TS,TLF}_RESTORE_SIGMASK code
x86/smp: Remove stack_smp_processor_id()
x86/smp: Remove unnecessary initialization of thread_info::cpu
x86/asm: Move 'status' from struct thread_info to struct thread_struct
kdb: Use task_cpu() instead of task_thread_info()->cpu
sched: Allow putting thread_info into task_struct
x86: Move thread_info into task_struct
sched: Free the stack early if CONFIG_THREAD_INFO_IN_TASK
fork: Cache two thread stacks per cpu if CONFIG_VMAP_STACK is set
Herbert Xu (1):
rxrpc: Avoid using stack memory in SG lists in rxkad
Ingo Molnar (1):
x86/mm/hotplug: Don't remove PGD entries in remove_pagetable()
Linus Torvalds (2):
x86/entry: Get rid of pt_regs_to_thread_info()
um: Stop conflating task_struct::stack with thread_info
arch/Kconfig | 29 ++++++
arch/alpha/include/asm/thread_info.h | 27 -----
arch/ia64/include/asm/thread_info.h | 30 +-----
arch/microblaze/include/asm/thread_info.h | 27 -----
arch/powerpc/include/asm/thread_info.h | 25 -----
arch/sh/include/asm/thread_info.h | 26 -----
arch/sparc/include/asm/thread_info_64.h | 24 -----
arch/tile/include/asm/thread_info.h | 27 -----
arch/x86/Kconfig | 2 +
arch/x86/entry/common.c | 25 ++---
arch/x86/entry/entry_32.S | 11 +++
arch/x86/entry/entry_64.S | 20 +++-
arch/x86/entry/vsyscall/vsyscall_64.c | 6 +-
arch/x86/include/asm/checksum_32.h | 3 +-
arch/x86/include/asm/cpu.h | 1 -
arch/x86/include/asm/efi.h | 1 -
arch/x86/include/asm/pgtable_types.h | 2 -
arch/x86/include/asm/processor.h | 32 ++++--
arch/x86/include/asm/smp.h | 6 --
arch/x86/include/asm/switch_to.h | 34 ++++++-
arch/x86/include/asm/syscall.h | 23 +----
arch/x86/include/asm/thread_info.h | 102 +------------------
arch/x86/include/asm/traps.h | 6 ++
arch/x86/include/asm/uaccess.h | 10 +-
arch/x86/kernel/asm-offsets.c | 5 +-
arch/x86/kernel/cpu/common.c | 2 +-
arch/x86/kernel/dumpstack.c | 20 +++-
arch/x86/kernel/dumpstack_32.c | 4 +-
arch/x86/kernel/dumpstack_64.c | 16 ++-
arch/x86/kernel/fpu/init.c | 1 -
arch/x86/kernel/irq_64.c | 3 +-
arch/x86/kernel/process.c | 6 +-
arch/x86/kernel/process_64.c | 4 +-
arch/x86/kernel/ptrace.c | 2 +-
arch/x86/kernel/smpboot.c | 1 -
arch/x86/kernel/traps.c | 32 ++++++
arch/x86/lib/copy_user_64.S | 8 +-
arch/x86/lib/csum-wrappers_64.c | 1 +
arch/x86/lib/getuser.S | 20 ++--
arch/x86/lib/putuser.S | 10 +-
arch/x86/lib/usercopy_64.c | 2 +-
arch/x86/mm/extable.c | 2 +-
arch/x86/mm/fault.c | 41 +++++++-
arch/x86/mm/init_64.c | 27 -----
arch/x86/mm/pageattr.c | 32 +-----
arch/x86/mm/tlb.c | 15 +++
arch/x86/platform/efi/efi.c | 2 -
arch/x86/platform/efi/efi_32.c | 3 -
arch/x86/platform/efi/efi_64.c | 5 -
arch/x86/um/ptrace_32.c | 8 +-
drivers/base/node.c | 3 +-
drivers/pnp/isapnp/proc.c | 2 +-
fs/proc/meminfo.c | 2 +-
include/linux/init_task.h | 9 ++
include/linux/kdb.h | 2 +-
include/linux/memcontrol.h | 2 +-
include/linux/mmzone.h | 2 +-
include/linux/sched.h | 115 +++++++++++++++++++++-
include/linux/thread_info.h | 56 +++--------
init/Kconfig | 3 +
init/init_task.c | 7 +-
kernel/fork.c | 158 +++++++++++++++++++++++++-----
kernel/sched/core.c | 9 ++
kernel/sched/sched.h | 4 +
lib/bitmap.c | 2 +-
lib/dma-debug.c | 39 ++++++--
mm/memcontrol.c | 2 +-
mm/page_alloc.c | 3 +-
net/bluetooth/smp.c | 67 ++++++-------
net/rxrpc/ar-internal.h | 1 +
net/rxrpc/rxkad.c | 103 ++++++++-----------
71 files changed, 714 insertions(+), 648 deletions(-)
--
2.7.4
[toc] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 07/29] mm: Fix memcg stack accounting for sub-page stacks |
| Message-ID | <rOqfU-8f8-17@gated-at.bofh.it> |
| In reply to | #1431600 |
We should account for stacks regardless of stack size, and we need
to account in sub-page units if THREAD_SIZE < PAGE_SIZE. Change the
units to kilobytes and Move it into account_kernel_stack().
Fixes: 12580e4b54ba8 ("mm: memcontrol: report kernel stack usage in cgroup2 memory.stat")
Cc: Vladimir Davydov <vdavydov@virtuozzo.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: linux-mm@kvack.org
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
include/linux/memcontrol.h | 2 +-
kernel/fork.c | 19 ++++++++-----------
mm/memcontrol.c | 2 +-
3 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index a805474df4ab..3b653b86bb8f 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -52,7 +52,7 @@ enum mem_cgroup_stat_index {
MEM_CGROUP_STAT_SWAP, /* # of pages, swapped out */
MEM_CGROUP_STAT_NSTATS,
/* default hierarchy stats */
- MEMCG_KERNEL_STACK = MEM_CGROUP_STAT_NSTATS,
+ MEMCG_KERNEL_STACK_KB = MEM_CGROUP_STAT_NSTATS,
MEMCG_SLAB_RECLAIMABLE,
MEMCG_SLAB_UNRECLAIMABLE,
MEMCG_SOCK,
diff --git a/kernel/fork.c b/kernel/fork.c
index 466ba8febe3b..146c9840c079 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -165,20 +165,12 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk,
struct page *page = alloc_kmem_pages_node(node, THREADINFO_GFP,
THREAD_SIZE_ORDER);
- if (page)
- memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
- 1 << THREAD_SIZE_ORDER);
-
return page ? page_address(page) : NULL;
}
static inline void free_thread_stack(unsigned long *stack)
{
- struct page *page = virt_to_page(stack);
-
- memcg_kmem_update_page_stat(page, MEMCG_KERNEL_STACK,
- -(1 << THREAD_SIZE_ORDER));
- __free_kmem_pages(page, THREAD_SIZE_ORDER);
+ free_kmem_pages((unsigned long)stack, THREAD_SIZE_ORDER);
}
# else
static struct kmem_cache *thread_stack_cache;
@@ -223,10 +215,15 @@ static struct kmem_cache *mm_cachep;
static void account_kernel_stack(unsigned long *stack, int account)
{
- struct zone *zone = page_zone(virt_to_page(stack));
+ /* All stack pages are in the same zone and belong to the same memcg. */
+ struct page *first_page = virt_to_page(stack);
- mod_zone_page_state(zone, NR_KERNEL_STACK_KB,
+ mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
THREAD_SIZE / 1024 * account);
+
+ memcg_kmem_update_page_stat(
+ first_page, MEMCG_KERNEL_STACK_KB,
+ account * (THREAD_SIZE / 1024));
}
void free_task(struct task_struct *tsk)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index ac8664db3823..ee44afc1f2d0 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5133,7 +5133,7 @@ static int memory_stat_show(struct seq_file *m, void *v)
seq_printf(m, "file %llu\n",
(u64)stat[MEM_CGROUP_STAT_CACHE] * PAGE_SIZE);
seq_printf(m, "kernel_stack %llu\n",
- (u64)stat[MEMCG_KERNEL_STACK] * PAGE_SIZE);
+ (u64)stat[MEMCG_KERNEL_STACK_KB] * 1024);
seq_printf(m, "slab %llu\n",
(u64)(stat[MEMCG_SLAB_RECLAIMABLE] +
stat[MEMCG_SLAB_UNRECLAIMABLE]) * PAGE_SIZE);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 24/29] x86/entry: Get rid of pt_regs_to_thread_info() |
| Message-ID | <rOqfU-8f8-25@gated-at.bofh.it> |
| In reply to | #1431600 |
From: Linus Torvalds <torvalds@linux-foundation.org>
It was a nice optimization while it lasted, but thread_info is moving
and this optimization will no longer work.
Quoting Linus:
Oh Gods, Andy. That pt_regs_to_thread_info() thing made me want
to do unspeakable acts on a poor innocent wax figure that looked
_exactly_ like you.
[changelog written by Andy]
Message-Id: <CA+55aFxvZhBu9U1cqpVm4frv0p5mqu=0TxsSqE-=95ft8HvCVA@mail.gmail.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
arch/x86/entry/common.c | 21 +++++++--------------
1 file changed, 7 insertions(+), 14 deletions(-)
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index c4150bec7982..804487f126cb 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -31,13 +31,6 @@
#define CREATE_TRACE_POINTS
#include <trace/events/syscalls.h>
-static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs)
-{
- unsigned long top_of_stack =
- (unsigned long)(regs + 1) + TOP_OF_KERNEL_STACK_PADDING;
- return (struct thread_info *)(top_of_stack - THREAD_SIZE);
-}
-
#ifdef CONFIG_CONTEXT_TRACKING
/* Called on entry from user mode with IRQs off. */
__visible void enter_from_user_mode(void)
@@ -78,7 +71,7 @@ static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch)
*/
unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
unsigned long ret = 0;
u32 work;
@@ -156,7 +149,7 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)
long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch,
unsigned long phase1_result)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
long ret = 0;
u32 work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY;
@@ -239,7 +232,7 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
/* Disable IRQs and retry */
local_irq_disable();
- cached_flags = READ_ONCE(pt_regs_to_thread_info(regs)->flags);
+ cached_flags = READ_ONCE(current_thread_info()->flags);
if (!(cached_flags & EXIT_TO_USERMODE_LOOP_FLAGS))
break;
@@ -250,7 +243,7 @@ static void exit_to_usermode_loop(struct pt_regs *regs, u32 cached_flags)
/* Called with IRQs disabled. */
__visible inline void prepare_exit_to_usermode(struct pt_regs *regs)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
u32 cached_flags;
if (IS_ENABLED(CONFIG_PROVE_LOCKING) && WARN_ON(!irqs_disabled()))
@@ -309,7 +302,7 @@ static void syscall_slow_exit_work(struct pt_regs *regs, u32 cached_flags)
*/
__visible inline void syscall_return_slowpath(struct pt_regs *regs)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
u32 cached_flags = READ_ONCE(ti->flags);
CT_WARN_ON(ct_state() != CONTEXT_KERNEL);
@@ -332,7 +325,7 @@ __visible inline void syscall_return_slowpath(struct pt_regs *regs)
#ifdef CONFIG_X86_64
__visible void do_syscall_64(struct pt_regs *regs)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
unsigned long nr = regs->orig_ax;
enter_from_user_mode();
@@ -365,7 +358,7 @@ __visible void do_syscall_64(struct pt_regs *regs)
*/
static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
{
- struct thread_info *ti = pt_regs_to_thread_info(regs);
+ struct thread_info *ti = current_thread_info();
unsigned int nr = (unsigned int)regs->orig_ax;
#ifdef CONFIG_IA32_EMULATION
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rOqfU-8f8-37@gated-at.bofh.it> |
| In reply to | #1431600 |
It's not going to work, because the scheduler will explode if we try
to schedule when running on an IST stack or similar.
This will matter when we let kernel stack overflows (which are #DF)
call die().
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
arch/x86/kernel/dumpstack.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index ef8017ca5ba9..352f022cfd5b 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -245,6 +245,9 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
return;
if (in_interrupt())
panic("Fatal exception in interrupt");
+ if (((current_stack_pointer() ^ (current_top_of_stack() - 1))
+ & ~(THREAD_SIZE - 1)) != 0)
+ panic("Fatal exception on special stack");
if (panic_on_oops)
panic("Fatal exception");
do_exit(signr);
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-07-02 19:30 +0200 |
| Subject | Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rQwTU-6l3-35@gated-at.bofh.it> |
| In reply to | #1431603 |
On Sun, Jun 26, 2016 at 02:55:32PM -0700, Andy Lutomirski wrote:
> It's not going to work, because the scheduler will explode if we try
> to schedule when running on an IST stack or similar.
>
> This will matter when we let kernel stack overflows (which are #DF)
> call die().
>
> Signed-off-by: Andy Lutomirski <luto@kernel.org>
> ---
> arch/x86/kernel/dumpstack.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
> index ef8017ca5ba9..352f022cfd5b 100644
> --- a/arch/x86/kernel/dumpstack.c
> +++ b/arch/x86/kernel/dumpstack.c
> @@ -245,6 +245,9 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
> return;
> if (in_interrupt())
> panic("Fatal exception in interrupt");
> + if (((current_stack_pointer() ^ (current_top_of_stack() - 1))
> + & ~(THREAD_SIZE - 1)) != 0)
Ugh, that's hard to parse. You could remove the "!= 0" at least to
shorten it a bit and have one less braces level.
Or maybe even do something like that to make it a bit more readable:
if ((current_stack_pointer() ^ (current_top_of_stack() - 1))
&
~(THREAD_SIZE - 1))
panic("Fatal exception on non-default stack");
Meh.
> + panic("Fatal exception on special stack");
"Fatal exception on non-default stack"
maybe?
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Josh Poimboeuf <jpoimboe@redhat.com> |
|---|---|
| Date | 2016-07-02 20:40 +0200 |
| Subject | Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rQxZD-6Wy-11@gated-at.bofh.it> |
| In reply to | #1435848 |
On Sat, Jul 02, 2016 at 07:24:41PM +0200, Borislav Petkov wrote:
> On Sun, Jun 26, 2016 at 02:55:32PM -0700, Andy Lutomirski wrote:
> > It's not going to work, because the scheduler will explode if we try
> > to schedule when running on an IST stack or similar.
> >
> > This will matter when we let kernel stack overflows (which are #DF)
> > call die().
> >
> > Signed-off-by: Andy Lutomirski <luto@kernel.org>
> > ---
> > arch/x86/kernel/dumpstack.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
> > index ef8017ca5ba9..352f022cfd5b 100644
> > --- a/arch/x86/kernel/dumpstack.c
> > +++ b/arch/x86/kernel/dumpstack.c
> > @@ -245,6 +245,9 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
> > return;
> > if (in_interrupt())
> > panic("Fatal exception in interrupt");
> > + if (((current_stack_pointer() ^ (current_top_of_stack() - 1))
> > + & ~(THREAD_SIZE - 1)) != 0)
>
> Ugh, that's hard to parse. You could remove the "!= 0" at least to
> shorten it a bit and have one less braces level.
>
> Or maybe even do something like that to make it a bit more readable:
>
> if ((current_stack_pointer() ^ (current_top_of_stack() - 1))
> &
> ~(THREAD_SIZE - 1))
> panic("Fatal exception on non-default stack");
>
> Meh.
A helper function would be even better.
The existing 'object_is_on_stack()' can probably be used:
if (!object_is_on_stack(current_top_of_stack()))
panic("...");
Though that function isn't quite accurately named. It should really
have 'task_stack' in its name, like 'object_is_on_task_stack()'. Or
even better, something more concise like 'on_task_stack()'.
--
Josh
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-07-03 11:50 +0200 |
| Subject | Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rQMci-73U-11@gated-at.bofh.it> |
| In reply to | #1435853 |
On Sat, Jul 02, 2016 at 01:34:51PM -0500, Josh Poimboeuf wrote:
> The existing 'object_is_on_stack()' can probably be used:
>
> if (!object_is_on_stack(current_top_of_stack()))
> panic("...");
>
> Though that function isn't quite accurately named. It should really
> have 'task_stack' in its name, like 'object_is_on_task_stack()'. Or
> even better, something more concise like 'on_task_stack()'.
So I'm obviously missing something here:
object_is_on_stack() uses task_stack_page(current) -> task_struct.stack
while current_stack_pointer() reads %rsp directly.
I'm guessing %rsp and task_struct.stack are in sync?
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-07-03 16:30 +0200 |
| Subject | Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rQQzf-1jL-1@gated-at.bofh.it> |
| In reply to | #1435853 |
On Sat, Jul 2, 2016 at 11:34 AM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> On Sat, Jul 02, 2016 at 07:24:41PM +0200, Borislav Petkov wrote:
>> On Sun, Jun 26, 2016 at 02:55:32PM -0700, Andy Lutomirski wrote:
>> > It's not going to work, because the scheduler will explode if we try
>> > to schedule when running on an IST stack or similar.
>> >
>> > This will matter when we let kernel stack overflows (which are #DF)
>> > call die().
>> >
>> > Signed-off-by: Andy Lutomirski <luto@kernel.org>
>> > ---
>> > arch/x86/kernel/dumpstack.c | 3 +++
>> > 1 file changed, 3 insertions(+)
>> >
>> > diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
>> > index ef8017ca5ba9..352f022cfd5b 100644
>> > --- a/arch/x86/kernel/dumpstack.c
>> > +++ b/arch/x86/kernel/dumpstack.c
>> > @@ -245,6 +245,9 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr)
>> > return;
>> > if (in_interrupt())
>> > panic("Fatal exception in interrupt");
>> > + if (((current_stack_pointer() ^ (current_top_of_stack() - 1))
>> > + & ~(THREAD_SIZE - 1)) != 0)
>>
>> Ugh, that's hard to parse. You could remove the "!= 0" at least to
>> shorten it a bit and have one less braces level.
>>
>> Or maybe even do something like that to make it a bit more readable:
>>
>> if ((current_stack_pointer() ^ (current_top_of_stack() - 1))
>> &
>> ~(THREAD_SIZE - 1))
>> panic("Fatal exception on non-default stack");
>>
>> Meh.
>
> A helper function would be even better.
>
> The existing 'object_is_on_stack()' can probably be used:
>
> if (!object_is_on_stack(current_top_of_stack()))
> panic("...");
>
> Though that function isn't quite accurately named. It should really
> have 'task_stack' in its name, like 'object_is_on_task_stack()'. Or
> even better, something more concise like 'on_task_stack()'.
>
Given that the very next patch deletes this code, I vote for leaving
it alone. Or I could fold the patches together.
--Andy
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-07-03 20:50 +0200 |
| Subject | Re: [PATCH v4 10/29] x86/die: Don't try to recover from an OOPS on a non-default stack |
| Message-ID | <rQUCR-3Hu-3@gated-at.bofh.it> |
| In reply to | #1435968 |
On Sun, Jul 03, 2016 at 07:25:05AM -0700, Andy Lutomirski wrote: > Given that the very next patch deletes this code, I vote for leaving > it alone. Or I could fold the patches together. Ah, true. Yes, please fold them together. -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 12/29] x86/dumpstack: When dumping stack bytes due to OOPS, start with regs->sp |
| Message-ID | <rOqfU-8f8-27@gated-at.bofh.it> |
| In reply to | #1431600 |
The comment suggests that show_stack(NULL, NULL) should backtrace
the current context, but the code doesn't match the comment. If
regs are given, start the "Stack:" hexdump at regs->sp.
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
arch/x86/kernel/dumpstack_32.c | 4 +++-
arch/x86/kernel/dumpstack_64.c | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index fef917e79b9d..948d77da3881 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -96,7 +96,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
int i;
if (sp == NULL) {
- if (task)
+ if (regs)
+ sp = (unsigned long *)regs->sp;
+ else if (task)
sp = (unsigned long *)task->thread.sp;
else
sp = (unsigned long *)&sp;
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index d558a8a49016..a81e1ef73bf2 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -264,7 +264,9 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
* back trace for this cpu:
*/
if (sp == NULL) {
- if (task)
+ if (regs)
+ sp = (unsigned long *)regs->sp;
+ else if (task)
sp = (unsigned long *)task->thread.sp;
else
sp = (unsigned long *)&sp;
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 06/29] mm: Track NR_KERNEL_STACK in KiB instead of number of stacks |
| Message-ID | <rOqfU-8f8-29@gated-at.bofh.it> |
| In reply to | #1431600 |
Currently, NR_KERNEL_STACK tracks the number of kernel stacks in a
zone. This only makes sense if each kernel stack exists entirely in
one zone, and allowing vmapped stacks could break this assumption.
Since frv has THREAD_SIZE < PAGE_SIZE, we need to track kernel stack
allocations in a unit that divides both THREAD_SIZE and PAGE_SIZE on
all architectures. Keep it simple and use KiB.
Cc: Vladimir Davydov <vdavydov@virtuozzo.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: linux-mm@kvack.org
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Reviewed-by: Vladimir Davydov <vdavydov@virtuozzo.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
drivers/base/node.c | 3 +--
fs/proc/meminfo.c | 2 +-
include/linux/mmzone.h | 2 +-
kernel/fork.c | 3 ++-
mm/page_alloc.c | 3 +--
5 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 560751bad294..27dc68a0ed2d 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -121,8 +121,7 @@ static ssize_t node_read_meminfo(struct device *dev,
nid, K(node_page_state(nid, NR_FILE_MAPPED)),
nid, K(node_page_state(nid, NR_ANON_PAGES)),
nid, K(i.sharedram),
- nid, node_page_state(nid, NR_KERNEL_STACK) *
- THREAD_SIZE / 1024,
+ nid, node_page_state(nid, NR_KERNEL_STACK_KB),
nid, K(node_page_state(nid, NR_PAGETABLE)),
nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
nid, K(node_page_state(nid, NR_BOUNCE)),
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 83720460c5bc..239b5a06cee0 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -145,7 +145,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
global_page_state(NR_SLAB_UNRECLAIMABLE)),
K(global_page_state(NR_SLAB_RECLAIMABLE)),
K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
- global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024,
+ global_page_state(NR_KERNEL_STACK_KB),
K(global_page_state(NR_PAGETABLE)),
#ifdef CONFIG_QUICKLIST
K(quicklist_total_size()),
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 02069c23486d..63f05a7efb54 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -127,7 +127,7 @@ enum zone_stat_item {
NR_SLAB_RECLAIMABLE,
NR_SLAB_UNRECLAIMABLE,
NR_PAGETABLE, /* used for pagetables */
- NR_KERNEL_STACK,
+ NR_KERNEL_STACK_KB, /* measured in KiB */
/* Second 128 byte cacheline */
NR_UNSTABLE_NFS, /* NFS unstable pages */
NR_BOUNCE,
diff --git a/kernel/fork.c b/kernel/fork.c
index 4a7ec0c6c88c..466ba8febe3b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -225,7 +225,8 @@ static void account_kernel_stack(unsigned long *stack, int account)
{
struct zone *zone = page_zone(virt_to_page(stack));
- mod_zone_page_state(zone, NR_KERNEL_STACK, account);
+ mod_zone_page_state(zone, NR_KERNEL_STACK_KB,
+ THREAD_SIZE / 1024 * account);
}
void free_task(struct task_struct *tsk)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6903b695ebae..a277dea926c9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4457,8 +4457,7 @@ void show_free_areas(unsigned int filter)
K(zone_page_state(zone, NR_SHMEM)),
K(zone_page_state(zone, NR_SLAB_RECLAIMABLE)),
K(zone_page_state(zone, NR_SLAB_UNRECLAIMABLE)),
- zone_page_state(zone, NR_KERNEL_STACK) *
- THREAD_SIZE / 1024,
+ zone_page_state(zone, NR_KERNEL_STACK_KB),
K(zone_page_state(zone, NR_PAGETABLE)),
K(zone_page_state(zone, NR_UNSTABLE_NFS)),
K(zone_page_state(zone, NR_BOUNCE)),
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 14/29] x86/dumpstack/64: Handle faults when printing the "Stack:" part of an OOPS |
| Message-ID | <rOqfU-8f8-39@gated-at.bofh.it> |
| In reply to | #1431600 |
If we overflow the stack into a guard page, we'll recursively fault
when trying to dump the contents of the guard page. Use
probe_kernel_address so we can recover if this happens.
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
arch/x86/kernel/dumpstack_64.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index a81e1ef73bf2..6dede08dd98b 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -274,6 +274,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
stack = sp;
for (i = 0; i < kstack_depth_to_print; i++) {
+ unsigned long word;
+
if (stack >= irq_stack && stack <= irq_stack_end) {
if (stack == irq_stack_end) {
stack = (unsigned long *) (irq_stack_end[-1]);
@@ -283,12 +285,18 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
if (kstack_end(stack))
break;
}
+
+ if (probe_kernel_address(stack, word))
+ break;
+
if ((i % STACKSLOTS_PER_LINE) == 0) {
if (i != 0)
pr_cont("\n");
- printk("%s %016lx", log_lvl, *stack++);
+ printk("%s %016lx", log_lvl, word);
} else
- pr_cont(" %016lx", *stack++);
+ pr_cont(" %016lx", word);
+
+ stack++;
touch_nmi_watchdog();
}
preempt_enable();
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rOqfU-8f8-33@gated-at.bofh.it> |
| In reply to | #1431600 |
If an arch opts in by setting CONFIG_THREAD_INFO_IN_TASK_STRUCT,
then thread_info is defined as a single 'u32 flags' and is the first
entry of task_struct. thread_info::task is removed (it serves no
purpose if thread_info is embedded in task_struct), and
thread_info::cpu gets its own slot in task_struct.
This is heavily based on a patch written by Linus.
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
include/linux/init_task.h | 9 +++++++++
include/linux/sched.h | 36 ++++++++++++++++++++++++++++++++++--
include/linux/thread_info.h | 15 +++++++++++++++
init/Kconfig | 3 +++
init/init_task.c | 7 +++++--
kernel/sched/sched.h | 4 ++++
6 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index f8834f820ec2..9c04d44eeb3c 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -15,6 +15,8 @@
#include <net/net_namespace.h>
#include <linux/sched/rt.h>
+#include <asm/thread_info.h>
+
#ifdef CONFIG_SMP
# define INIT_PUSHABLE_TASKS(tsk) \
.pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO),
@@ -183,12 +185,19 @@ extern struct task_group root_task_group;
# define INIT_KASAN(tsk)
#endif
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+# define INIT_TASK_TI(tsk) .thread_info = INIT_THREAD_INFO(tsk),
+#else
+# define INIT_TASK_TI(tsk)
+#endif
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
*/
#define INIT_TASK(tsk) \
{ \
+ INIT_TASK_TI(tsk) \
.state = 0, \
.stack = init_stack, \
.usage = ATOMIC_INIT(2), \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 569df670407a..4108b4880b86 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1456,6 +1456,13 @@ struct tlbflush_unmap_batch {
};
struct task_struct {
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ /*
+ * For reasons of header soup (see current_thread_info()), this
+ * must be the first element of task_struct.
+ */
+ struct thread_info thread_info;
+#endif
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
@@ -1465,6 +1472,9 @@ struct task_struct {
#ifdef CONFIG_SMP
struct llist_node wake_entry;
int on_cpu;
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ unsigned int cpu; /* current CPU */
+#endif
unsigned int wakee_flips;
unsigned long wakee_flip_decay_ts;
struct task_struct *last_wakee;
@@ -2557,7 +2567,9 @@ extern void set_curr_task(int cpu, struct task_struct *p);
void yield(void);
union thread_union {
+#ifndef CONFIG_THREAD_INFO_IN_TASK
struct thread_info thread_info;
+#endif
unsigned long stack[THREAD_SIZE/sizeof(long)];
};
@@ -3045,10 +3057,26 @@ static inline void threadgroup_change_end(struct task_struct *tsk)
cgroup_threadgroup_change_end(tsk);
}
-#ifndef __HAVE_THREAD_FUNCTIONS
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+
+static inline struct thread_info *task_thread_info(struct task_struct *task)
+{
+ return &task->thread_info;
+}
+static inline void *task_stack_page(const struct task_struct *task)
+{
+ return task->stack;
+}
+#define setup_thread_stack(new,old) do { } while(0)
+static inline unsigned long *end_of_stack(const struct task_struct *task)
+{
+ return task->stack;
+}
+
+#elif !defined(__HAVE_THREAD_FUNCTIONS)
#define task_thread_info(task) ((struct thread_info *)(task)->stack)
-#define task_stack_page(task) ((task)->stack)
+#define task_stack_page(task) ((void *)(task)->stack)
static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
{
@@ -3348,7 +3376,11 @@ static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume)
static inline unsigned int task_cpu(const struct task_struct *p)
{
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ return p->cpu;
+#else
return task_thread_info(p)->cpu;
+#endif
}
static inline int task_node(const struct task_struct *p)
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 352b1542f5cc..b2b32d63bc8e 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -13,6 +13,21 @@
struct timespec;
struct compat_timespec;
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+struct thread_info {
+ u32 flags; /* low level flags */
+};
+
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .flags = 0, \
+}
+#endif
+
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+#define current_thread_info() ((struct thread_info *)current)
+#endif
+
/*
* System call restart block.
*/
diff --git a/init/Kconfig b/init/Kconfig
index f755a602d4a1..0c83af6d3753 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -26,6 +26,9 @@ config IRQ_WORK
config BUILDTIME_EXTABLE_SORT
bool
+config THREAD_INFO_IN_TASK
+ bool
+
menu "General setup"
config BROKEN
diff --git a/init/init_task.c b/init/init_task.c
index ba0a7f362d9e..11f83be1fa79 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -22,5 +22,8 @@ EXPORT_SYMBOL(init_task);
* Initial thread structure. Alignment of this is handled by a special
* linker map entry.
*/
-union thread_union init_thread_union __init_task_data =
- { INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union __init_task_data = {
+#ifndef CONFIG_THREAD_INFO_IN_TASK
+ INIT_THREAD_INFO(init_task)
+#endif
+};
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 7cbeb92a1cb9..a1cabcea4c54 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -999,7 +999,11 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
* per-task data have been completed by this moment.
*/
smp_wmb();
+#ifdef CONFIG_THREAD_INFO_IN_TASK
+ p->cpu = cpu;
+#else
task_thread_info(p)->cpu = cpu;
+#endif
p->wake_cpu = cpu;
#endif
}
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2016-07-11 12:10 +0200 |
| Subject | Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rTGk2-5Co-29@gated-at.bofh.it> |
| In reply to | #1431607 |
Hi,
On Sun, Jun 26, 2016 at 02:55:48PM -0700, Andy Lutomirski wrote:
> If an arch opts in by setting CONFIG_THREAD_INFO_IN_TASK_STRUCT,
> then thread_info is defined as a single 'u32 flags' and is the first
> entry of task_struct. thread_info::task is removed (it serves no
> purpose if thread_info is embedded in task_struct), and
> thread_info::cpu gets its own slot in task_struct.
>
> This is heavily based on a patch written by Linus.
I've been considering how we'd implement this for arm64, and I suspect
that we'll also need to fold our preempt_count into task_struct
(following from the style of asm-generic/preempt.h).
As far as I can see, we can't make our preempt-count a percpu variable
as with x86, as our percpu ops themselves are based on disabling
preemption.
To that end, would it be possible to keep the thread_info definition per
arch, even with CONFIG_THREAD_INFO_IN_TASK?
Thanks,
Mark.
>
> Signed-off-by: Andy Lutomirski <luto@kernel.org>
> ---
> include/linux/init_task.h | 9 +++++++++
> include/linux/sched.h | 36 ++++++++++++++++++++++++++++++++++--
> include/linux/thread_info.h | 15 +++++++++++++++
> init/Kconfig | 3 +++
> init/init_task.c | 7 +++++--
> kernel/sched/sched.h | 4 ++++
> 6 files changed, 70 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/init_task.h b/include/linux/init_task.h
> index f8834f820ec2..9c04d44eeb3c 100644
> --- a/include/linux/init_task.h
> +++ b/include/linux/init_task.h
> @@ -15,6 +15,8 @@
> #include <net/net_namespace.h>
> #include <linux/sched/rt.h>
>
> +#include <asm/thread_info.h>
> +
> #ifdef CONFIG_SMP
> # define INIT_PUSHABLE_TASKS(tsk) \
> .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO),
> @@ -183,12 +185,19 @@ extern struct task_group root_task_group;
> # define INIT_KASAN(tsk)
> #endif
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +# define INIT_TASK_TI(tsk) .thread_info = INIT_THREAD_INFO(tsk),
> +#else
> +# define INIT_TASK_TI(tsk)
> +#endif
> +
> /*
> * INIT_TASK is used to set up the first task table, touch at
> * your own risk!. Base=0, limit=0x1fffff (=2MB)
> */
> #define INIT_TASK(tsk) \
> { \
> + INIT_TASK_TI(tsk) \
> .state = 0, \
> .stack = init_stack, \
> .usage = ATOMIC_INIT(2), \
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 569df670407a..4108b4880b86 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1456,6 +1456,13 @@ struct tlbflush_unmap_batch {
> };
>
> struct task_struct {
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + /*
> + * For reasons of header soup (see current_thread_info()), this
> + * must be the first element of task_struct.
> + */
> + struct thread_info thread_info;
> +#endif
> volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
> void *stack;
> atomic_t usage;
> @@ -1465,6 +1472,9 @@ struct task_struct {
> #ifdef CONFIG_SMP
> struct llist_node wake_entry;
> int on_cpu;
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + unsigned int cpu; /* current CPU */
> +#endif
> unsigned int wakee_flips;
> unsigned long wakee_flip_decay_ts;
> struct task_struct *last_wakee;
> @@ -2557,7 +2567,9 @@ extern void set_curr_task(int cpu, struct task_struct *p);
> void yield(void);
>
> union thread_union {
> +#ifndef CONFIG_THREAD_INFO_IN_TASK
> struct thread_info thread_info;
> +#endif
> unsigned long stack[THREAD_SIZE/sizeof(long)];
> };
>
> @@ -3045,10 +3057,26 @@ static inline void threadgroup_change_end(struct task_struct *tsk)
> cgroup_threadgroup_change_end(tsk);
> }
>
> -#ifndef __HAVE_THREAD_FUNCTIONS
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +
> +static inline struct thread_info *task_thread_info(struct task_struct *task)
> +{
> + return &task->thread_info;
> +}
> +static inline void *task_stack_page(const struct task_struct *task)
> +{
> + return task->stack;
> +}
> +#define setup_thread_stack(new,old) do { } while(0)
> +static inline unsigned long *end_of_stack(const struct task_struct *task)
> +{
> + return task->stack;
> +}
> +
> +#elif !defined(__HAVE_THREAD_FUNCTIONS)
>
> #define task_thread_info(task) ((struct thread_info *)(task)->stack)
> -#define task_stack_page(task) ((task)->stack)
> +#define task_stack_page(task) ((void *)(task)->stack)
>
> static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
> {
> @@ -3348,7 +3376,11 @@ static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume)
>
> static inline unsigned int task_cpu(const struct task_struct *p)
> {
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + return p->cpu;
> +#else
> return task_thread_info(p)->cpu;
> +#endif
> }
>
> static inline int task_node(const struct task_struct *p)
> diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
> index 352b1542f5cc..b2b32d63bc8e 100644
> --- a/include/linux/thread_info.h
> +++ b/include/linux/thread_info.h
> @@ -13,6 +13,21 @@
> struct timespec;
> struct compat_timespec;
>
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +struct thread_info {
> + u32 flags; /* low level flags */
> +};
> +
> +#define INIT_THREAD_INFO(tsk) \
> +{ \
> + .flags = 0, \
> +}
> +#endif
> +
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> +#define current_thread_info() ((struct thread_info *)current)
> +#endif
> +
> /*
> * System call restart block.
> */
> diff --git a/init/Kconfig b/init/Kconfig
> index f755a602d4a1..0c83af6d3753 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -26,6 +26,9 @@ config IRQ_WORK
> config BUILDTIME_EXTABLE_SORT
> bool
>
> +config THREAD_INFO_IN_TASK
> + bool
> +
> menu "General setup"
>
> config BROKEN
> diff --git a/init/init_task.c b/init/init_task.c
> index ba0a7f362d9e..11f83be1fa79 100644
> --- a/init/init_task.c
> +++ b/init/init_task.c
> @@ -22,5 +22,8 @@ EXPORT_SYMBOL(init_task);
> * Initial thread structure. Alignment of this is handled by a special
> * linker map entry.
> */
> -union thread_union init_thread_union __init_task_data =
> - { INIT_THREAD_INFO(init_task) };
> +union thread_union init_thread_union __init_task_data = {
> +#ifndef CONFIG_THREAD_INFO_IN_TASK
> + INIT_THREAD_INFO(init_task)
> +#endif
> +};
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index 7cbeb92a1cb9..a1cabcea4c54 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -999,7 +999,11 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
> * per-task data have been completed by this moment.
> */
> smp_wmb();
> +#ifdef CONFIG_THREAD_INFO_IN_TASK
> + p->cpu = cpu;
> +#else
> task_thread_info(p)->cpu = cpu;
> +#endif
> p->wake_cpu = cpu;
> #endif
> }
> --
> 2.7.4
>
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@amacapital.net> |
|---|---|
| Date | 2016-07-11 17:00 +0200 |
| Subject | Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rTKQG-8n2-1@gated-at.bofh.it> |
| In reply to | #1440419 |
On Jul 11, 2016 3:08 AM, "Mark Rutland" <mark.rutland@arm.com> wrote: > > Hi, > > On Sun, Jun 26, 2016 at 02:55:48PM -0700, Andy Lutomirski wrote: > > If an arch opts in by setting CONFIG_THREAD_INFO_IN_TASK_STRUCT, > > then thread_info is defined as a single 'u32 flags' and is the first > > entry of task_struct. thread_info::task is removed (it serves no > > purpose if thread_info is embedded in task_struct), and > > thread_info::cpu gets its own slot in task_struct. > > > > This is heavily based on a patch written by Linus. > > I've been considering how we'd implement this for arm64, and I suspect > that we'll also need to fold our preempt_count into task_struct > (following from the style of asm-generic/preempt.h). > > As far as I can see, we can't make our preempt-count a percpu variable > as with x86, as our percpu ops themselves are based on disabling > preemption. How do you intend to find 'current' to get to the preempt count without first disabling preemption? > > To that end, would it be possible to keep the thread_info definition per > arch, even with CONFIG_THREAD_INFO_IN_TASK? In principal, yes, but could you alternatively put it in thread_struct? My goal here is to encourage people to clean up their use of thread_info vs thread_struct at the same time. For x86, that cleanup was trivial -- most of the work was addressing relative to current instead of the stack pointer, and that had to happen regardless. --Andy
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2016-07-11 17:10 +0200 |
| Subject | Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rTL0l-ej-3@gated-at.bofh.it> |
| In reply to | #1440689 |
On Mon, Jul 11, 2016 at 07:55:17AM -0700, Andy Lutomirski wrote: > On Jul 11, 2016 3:08 AM, "Mark Rutland" <mark.rutland@arm.com> wrote: > > > > Hi, > > > > On Sun, Jun 26, 2016 at 02:55:48PM -0700, Andy Lutomirski wrote: > > > If an arch opts in by setting CONFIG_THREAD_INFO_IN_TASK_STRUCT, > > > then thread_info is defined as a single 'u32 flags' and is the first > > > entry of task_struct. thread_info::task is removed (it serves no > > > purpose if thread_info is embedded in task_struct), and > > > thread_info::cpu gets its own slot in task_struct. > > > > > > This is heavily based on a patch written by Linus. > > > > I've been considering how we'd implement this for arm64, and I suspect > > that we'll also need to fold our preempt_count into task_struct > > (following from the style of asm-generic/preempt.h). > > > > As far as I can see, we can't make our preempt-count a percpu variable > > as with x86, as our percpu ops themselves are based on disabling > > preemption. > > How do you intend to find 'current' to get to the preempt count > without first disabling preemption? Good point. For some reason I had convinced myself that it only mattered for RMW sequences, so evidently I hadn't considered things thoroughly enough. :( > > To that end, would it be possible to keep the thread_info definition per > > arch, even with CONFIG_THREAD_INFO_IN_TASK? > > In principal, yes, but could you alternatively put it in > thread_struct? My goal here is to encourage people to clean up their > use of thread_info vs thread_struct at the same time. For x86, that > cleanup was trivial -- most of the work was addressing relative to > current instead of the stack pointer, and that had to happen > regardless. I'm more than happy to do that, modulo the above permitting. Sorry for the noise! Thanks, Mark.
[toc] | [prev] | [next] | [standalone]
| From | Mark Rutland <mark.rutland@arm.com> |
|---|---|
| Date | 2016-07-11 18:40 +0200 |
| Subject | Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rTMpr-19f-13@gated-at.bofh.it> |
| In reply to | #1440689 |
On Mon, Jul 11, 2016 at 09:06:58AM -0700, Linus Torvalds wrote: > On Jul 11, 2016 7:55 AM, "Andy Lutomirski" <[1]luto@amacapital.net> wrote: > > > > How do you intend to find 'current' to get to the preempt count > > without first disabling preemption? > > Actually, that is the classic case of "not a problem". > > The thing is, it doesn't matter if you schedule away while looking up > current or the preempt count - because both values are idempotent wet > scheduling. > > So until you do the wire that actually disables preemption you can > schedule away as much as you want, and after that write you no longer > will. I was assuming a percpu pointer to current (or preempt count). The percpu offset might be stale at the point you try to dereference that, even though current itself hasn't changed, and you may access the wrong CPU's value. > This is different wrt a per-cpu area - which is clearly not idempotent wrt > scheduling. > > The reason per-cpu works on x86 is that we have an atomic rmw operation > that is *also* atomic wrt the CPU lookup (thanks to the segment base) Sure, understood. Mark.
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2016-07-11 18:50 +0200 |
| Subject | Re: [kernel-hardening] [PATCH v4 26/29] sched: Allow putting thread_info into task_struct |
| Message-ID | <rTMz8-1cS-29@gated-at.bofh.it> |
| In reply to | #1440748 |
On Mon, Jul 11, 2016 at 9:31 AM, Mark Rutland <mark.rutland@arm.com> wrote:
>>
>> So until you do the wire that actually disables preemption you can
>> schedule away as much as you want, and after that write you no longer
>> will.
>
> I was assuming a percpu pointer to current (or preempt count).
So for the same reason that is ok *iff* you have
- some kind of dedicated percpu register (or other base pointer - x86
has the segment thing) that gets updated when you schedule.
- an instruction that can load 'current' directly off that register atomically.
But yes, percpu data in general is obviously not safe to access
without preemption.
Linus
[toc] | [prev] | [next] | [standalone]
| From | Andy Lutomirski <luto@kernel.org> |
|---|---|
| Date | 2016-06-27 00:00 +0200 |
| Subject | [PATCH v4 08/29] dma-api: Teach the "DMA-from-stack" check about vmapped stacks |
| Message-ID | <rOqfU-8f8-35@gated-at.bofh.it> |
| In reply to | #1431600 |
If we're using CONFIG_VMAP_STACK 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.
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andy Lutomirski <luto@kernel.org>
---
lib/dma-debug.c | 39 +++++++++++++++++++++++++++++++++------
1 file changed, 33 insertions(+), 6 deletions(-)
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 51a76af25c66..5b2e63cba90e 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>
@@ -1162,11 +1163,35 @@ 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)
@@ -1289,10 +1314,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);
}
@@ -1384,8 +1410,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.7.4
[toc] | [prev] | [next] | [standalone]
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Date | 2016-06-30 21:40 +0200 |
| Subject | Re: [PATCH v4 08/29] dma-api: Teach the "DMA-from-stack" check about vmapped stacks |
| Message-ID | <rPPYB-58Z-25@gated-at.bofh.it> |
| In reply to | #1431608 |
On Sun, Jun 26, 2016 at 02:55:30PM -0700, Andy Lutomirski wrote:
> If we're using CONFIG_VMAP_STACK 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.
>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Andy Lutomirski <luto@kernel.org>
> ---
> lib/dma-debug.c | 39 +++++++++++++++++++++++++++++++++------
> 1 file changed, 33 insertions(+), 6 deletions(-)
>
> diff --git a/lib/dma-debug.c b/lib/dma-debug.c
> index 51a76af25c66..5b2e63cba90e 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>
> @@ -1162,11 +1163,35 @@ 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);
lib/dma-debug.c: In function ‘check_for_stack’:
lib/dma-debug.c:1170:36: error: implicit declaration of function ‘task_stack_vm_area’ [-Werror=implicit-function-declaration]
struct vm_struct *stack_vm_area = task_stack_vm_area(current);
^
lib/dma-debug.c:1170:36: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
cc1: some warnings being treated as errors
make[1]: *** [lib/dma-debug.o] Error 1
make: *** [lib] Error 2
make: *** Waiting for unfinished jobs....
Probably reorder pieces from patch 9 to earlier ones...
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
[toc] | [prev] | [next] | [standalone]
Page 1 of 4 [1] 2 3 4 Next page →
Back to top | Article view | linux.kernel
csiph-web