linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Dmitry Vyukov <dvyukov@google.com>
To: Andrew Morton <akpm@linux-foundation.org>,
	Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	Dmitry Vyukov <dvyukov@google.com>,
	kasan-dev <kasan-dev@googlegroups.com>,
	"linux-mm@kvack.org" <linux-mm@kvack.org>,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] x86, kasan: add KASAN checks to atomic operations
Date: Mon, 6 Mar 2017 13:50:47 +0100	[thread overview]
Message-ID: <CACT4Y+YmpTMdJca-rE2nXR-qa=wn_bCqQXaRghtg1uC65-pKyA@mail.gmail.com> (raw)
In-Reply-To: <20170306124254.77615-1-dvyukov@google.com>

On Mon, Mar 6, 2017 at 1:42 PM, Dmitry Vyukov <dvyukov@google.com> wrote:
> KASAN uses compiler instrumentation to intercept all memory accesses.
> But it does not see memory accesses done in assembly code.
> One notable user of assembly code is atomic operations. Frequently,
> for example, an atomic reference decrement is the last access to an
> object and a good candidate for a racy use-after-free.
>
> Add manual KASAN checks to atomic operations.
> Note: we need checks only before asm blocks and don't need them
> in atomic functions composed of other atomic functions
> (e.g. load-cmpxchg loops).

Peter, also pointed me at arch/x86/include/asm/bitops.h. Will add them in v2.


> Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
> Cc: kasan-dev@googlegroups.com
> Cc: linux-mm@kvack.org
> Cc: linux-kernel@vger.kernel.org
>
> ---
> Within a day it has found its first bug:
>
> ==================================================================
> BUG: KASAN: use-after-free in atomic_dec_and_test
> arch/x86/include/asm/atomic.h:123 [inline] at addr ffff880079c30158
> BUG: KASAN: use-after-free in put_task_struct
> include/linux/sched/task.h:93 [inline] at addr ffff880079c30158
> BUG: KASAN: use-after-free in put_ctx+0xcf/0x110
> kernel/events/core.c:1131 at addr ffff880079c30158
> Write of size 4 by task syz-executor6/25698
> CPU: 2 PID: 25698 Comm: syz-executor6 Not tainted 4.10.0+ #302
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
> Call Trace:
>  __dump_stack lib/dump_stack.c:16 [inline]
>  dump_stack+0x2fb/0x3fd lib/dump_stack.c:52
>  kasan_object_err+0x1c/0x90 mm/kasan/report.c:166
>  print_address_description mm/kasan/report.c:208 [inline]
>  kasan_report_error mm/kasan/report.c:292 [inline]
>  kasan_report.part.2+0x1b0/0x460 mm/kasan/report.c:314
>  kasan_report+0x21/0x30 mm/kasan/report.c:301
>  check_memory_region_inline mm/kasan/kasan.c:326 [inline]
>  check_memory_region+0x139/0x190 mm/kasan/kasan.c:333
>  kasan_check_write+0x14/0x20 mm/kasan/kasan.c:344
>  atomic_dec_and_test arch/x86/include/asm/atomic.h:123 [inline]
>  put_task_struct include/linux/sched/task.h:93 [inline]
>  put_ctx+0xcf/0x110 kernel/events/core.c:1131
>  perf_event_release_kernel+0x3ad/0xc90 kernel/events/core.c:4322
>  perf_release+0x37/0x50 kernel/events/core.c:4338
>  __fput+0x332/0x800 fs/file_table.c:209
>  ____fput+0x15/0x20 fs/file_table.c:245
>  task_work_run+0x197/0x260 kernel/task_work.c:116
>  exit_task_work include/linux/task_work.h:21 [inline]
>  do_exit+0xb38/0x29c0 kernel/exit.c:880
>  do_group_exit+0x149/0x420 kernel/exit.c:984
>  get_signal+0x7e0/0x1820 kernel/signal.c:2318
>  do_signal+0xd2/0x2190 arch/x86/kernel/signal.c:808
>  exit_to_usermode_loop+0x200/0x2a0 arch/x86/entry/common.c:157
>  syscall_return_slowpath arch/x86/entry/common.c:191 [inline]
>  do_syscall_64+0x6fc/0x930 arch/x86/entry/common.c:286
>  entry_SYSCALL64_slow_path+0x25/0x25
> RIP: 0033:0x4458d9
> RSP: 002b:00007f3f07187cf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
> RAX: fffffffffffffe00 RBX: 00000000007080c8 RCX: 00000000004458d9
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000007080c8
> RBP: 00000000007080a8 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
> R13: 0000000000000000 R14: 00007f3f071889c0 R15: 00007f3f07188700
> Object at ffff880079c30140, in cache task_struct size: 5376
> Allocated:
> PID = 25681
>  save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
>  save_stack+0x43/0xd0 mm/kasan/kasan.c:513
>  set_track mm/kasan/kasan.c:525 [inline]
>  kasan_kmalloc+0xaa/0xd0 mm/kasan/kasan.c:616
>  kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:555
>  kmem_cache_alloc_node+0x122/0x6f0 mm/slab.c:3662
>  alloc_task_struct_node kernel/fork.c:153 [inline]
>  dup_task_struct kernel/fork.c:495 [inline]
>  copy_process.part.38+0x19c8/0x4aa0 kernel/fork.c:1560
>  copy_process kernel/fork.c:1531 [inline]
>  _do_fork+0x200/0x1010 kernel/fork.c:1994
>  SYSC_clone kernel/fork.c:2104 [inline]
>  SyS_clone+0x37/0x50 kernel/fork.c:2098
>  do_syscall_64+0x2e8/0x930 arch/x86/entry/common.c:281
>  return_from_SYSCALL_64+0x0/0x7a
> Freed:
> PID = 25681
>  save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59
>  save_stack+0x43/0xd0 mm/kasan/kasan.c:513
>  set_track mm/kasan/kasan.c:525 [inline]
>  kasan_slab_free+0x6f/0xb0 mm/kasan/kasan.c:589
>  __cache_free mm/slab.c:3514 [inline]
>  kmem_cache_free+0x71/0x240 mm/slab.c:3774
>  free_task_struct kernel/fork.c:158 [inline]
>  free_task+0x151/0x1d0 kernel/fork.c:370
>  copy_process.part.38+0x18e5/0x4aa0 kernel/fork.c:1931
>  copy_process kernel/fork.c:1531 [inline]
>  _do_fork+0x200/0x1010 kernel/fork.c:1994
>  SYSC_clone kernel/fork.c:2104 [inline]
>  SyS_clone+0x37/0x50 kernel/fork.c:2098
>  do_syscall_64+0x2e8/0x930 arch/x86/entry/common.c:281
>  return_from_SYSCALL_64+0x0/0x7a
> ---
>  arch/x86/include/asm/atomic.h      | 11 +++++++++++
>  arch/x86/include/asm/atomic64_64.h | 10 ++++++++++
>  arch/x86/include/asm/cmpxchg.h     |  4 ++++
>  3 files changed, 25 insertions(+)
>
> diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
> index 14635c5ea025..64f0a7fb9b2f 100644
> --- a/arch/x86/include/asm/atomic.h
> +++ b/arch/x86/include/asm/atomic.h
> @@ -2,6 +2,7 @@
>  #define _ASM_X86_ATOMIC_H
>
>  #include <linux/compiler.h>
> +#include <linux/kasan-checks.h>
>  #include <linux/types.h>
>  #include <asm/alternative.h>
>  #include <asm/cmpxchg.h>
> @@ -47,6 +48,7 @@ static __always_inline void atomic_set(atomic_t *v, int i)
>   */
>  static __always_inline void atomic_add(int i, atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "addl %1,%0"
>                      : "+m" (v->counter)
>                      : "ir" (i));
> @@ -61,6 +63,7 @@ static __always_inline void atomic_add(int i, atomic_t *v)
>   */
>  static __always_inline void atomic_sub(int i, atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "subl %1,%0"
>                      : "+m" (v->counter)
>                      : "ir" (i));
> @@ -77,6 +80,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v)
>   */
>  static __always_inline bool atomic_sub_and_test(int i, atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_BINARY_RMWcc(LOCK_PREFIX "subl", v->counter, "er", i, "%0", e);
>  }
>
> @@ -88,6 +92,7 @@ static __always_inline bool atomic_sub_and_test(int i, atomic_t *v)
>   */
>  static __always_inline void atomic_inc(atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "incl %0"
>                      : "+m" (v->counter));
>  }
> @@ -100,6 +105,7 @@ static __always_inline void atomic_inc(atomic_t *v)
>   */
>  static __always_inline void atomic_dec(atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "decl %0"
>                      : "+m" (v->counter));
>  }
> @@ -114,6 +120,7 @@ static __always_inline void atomic_dec(atomic_t *v)
>   */
>  static __always_inline bool atomic_dec_and_test(atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", e);
>  }
>
> @@ -127,6 +134,7 @@ static __always_inline bool atomic_dec_and_test(atomic_t *v)
>   */
>  static __always_inline bool atomic_inc_and_test(atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_UNARY_RMWcc(LOCK_PREFIX "incl", v->counter, "%0", e);
>  }
>
> @@ -141,6 +149,7 @@ static __always_inline bool atomic_inc_and_test(atomic_t *v)
>   */
>  static __always_inline bool atomic_add_negative(int i, atomic_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_BINARY_RMWcc(LOCK_PREFIX "addl", v->counter, "er", i, "%0", s);
>  }
>
> @@ -194,6 +203,7 @@ static inline int atomic_xchg(atomic_t *v, int new)
>  #define ATOMIC_OP(op)                                                  \
>  static inline void atomic_##op(int i, atomic_t *v)                     \
>  {                                                                      \
> +       kasan_check_write(v, sizeof(*v));                               \
>         asm volatile(LOCK_PREFIX #op"l %1,%0"                           \
>                         : "+m" (v->counter)                             \
>                         : "ir" (i)                                      \
> @@ -258,6 +268,7 @@ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)
>   */
>  static __always_inline short int atomic_inc_short(short int *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
>         return *v;
>  }
> diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h
> index 89ed2f6ae2f7..13fe8ff5a126 100644
> --- a/arch/x86/include/asm/atomic64_64.h
> +++ b/arch/x86/include/asm/atomic64_64.h
> @@ -2,6 +2,7 @@
>  #define _ASM_X86_ATOMIC64_64_H
>
>  #include <linux/types.h>
> +#include <linux/kasan-checks.h>
>  #include <asm/alternative.h>
>  #include <asm/cmpxchg.h>
>
> @@ -42,6 +43,7 @@ static inline void atomic64_set(atomic64_t *v, long i)
>   */
>  static __always_inline void atomic64_add(long i, atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "addq %1,%0"
>                      : "=m" (v->counter)
>                      : "er" (i), "m" (v->counter));
> @@ -56,6 +58,7 @@ static __always_inline void atomic64_add(long i, atomic64_t *v)
>   */
>  static inline void atomic64_sub(long i, atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "subq %1,%0"
>                      : "=m" (v->counter)
>                      : "er" (i), "m" (v->counter));
> @@ -72,6 +75,7 @@ static inline void atomic64_sub(long i, atomic64_t *v)
>   */
>  static inline bool atomic64_sub_and_test(long i, atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_BINARY_RMWcc(LOCK_PREFIX "subq", v->counter, "er", i, "%0", e);
>  }
>
> @@ -83,6 +87,7 @@ static inline bool atomic64_sub_and_test(long i, atomic64_t *v)
>   */
>  static __always_inline void atomic64_inc(atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "incq %0"
>                      : "=m" (v->counter)
>                      : "m" (v->counter));
> @@ -96,6 +101,7 @@ static __always_inline void atomic64_inc(atomic64_t *v)
>   */
>  static __always_inline void atomic64_dec(atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         asm volatile(LOCK_PREFIX "decq %0"
>                      : "=m" (v->counter)
>                      : "m" (v->counter));
> @@ -111,6 +117,7 @@ static __always_inline void atomic64_dec(atomic64_t *v)
>   */
>  static inline bool atomic64_dec_and_test(atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_UNARY_RMWcc(LOCK_PREFIX "decq", v->counter, "%0", e);
>  }
>
> @@ -124,6 +131,7 @@ static inline bool atomic64_dec_and_test(atomic64_t *v)
>   */
>  static inline bool atomic64_inc_and_test(atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_UNARY_RMWcc(LOCK_PREFIX "incq", v->counter, "%0", e);
>  }
>
> @@ -138,6 +146,7 @@ static inline bool atomic64_inc_and_test(atomic64_t *v)
>   */
>  static inline bool atomic64_add_negative(long i, atomic64_t *v)
>  {
> +       kasan_check_write(v, sizeof(*v));
>         GEN_BINARY_RMWcc(LOCK_PREFIX "addq", v->counter, "er", i, "%0", s);
>  }
>
> @@ -233,6 +242,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v)
>  #define ATOMIC64_OP(op)                                                        \
>  static inline void atomic64_##op(long i, atomic64_t *v)                        \
>  {                                                                      \
> +       kasan_check_write(v, sizeof(*v));                               \
>         asm volatile(LOCK_PREFIX #op"q %1,%0"                           \
>                         : "+m" (v->counter)                             \
>                         : "er" (i)                                      \
> diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h
> index 97848cdfcb1a..a10e7fb09210 100644
> --- a/arch/x86/include/asm/cmpxchg.h
> +++ b/arch/x86/include/asm/cmpxchg.h
> @@ -2,6 +2,7 @@
>  #define ASM_X86_CMPXCHG_H
>
>  #include <linux/compiler.h>
> +#include <linux/kasan-checks.h>
>  #include <asm/cpufeatures.h>
>  #include <asm/alternative.h> /* Provides LOCK_PREFIX */
>
> @@ -41,6 +42,7 @@ extern void __add_wrong_size(void)
>  #define __xchg_op(ptr, arg, op, lock)                                  \
>         ({                                                              \
>                 __typeof__ (*(ptr)) __ret = (arg);                      \
> +               kasan_check_write((void *)(ptr), sizeof(*(ptr)));       \
>                 switch (sizeof(*(ptr))) {                               \
>                 case __X86_CASE_B:                                      \
>                         asm volatile (lock #op "b %b0, %1\n"            \
> @@ -86,6 +88,7 @@ extern void __add_wrong_size(void)
>         __typeof__(*(ptr)) __ret;                                       \
>         __typeof__(*(ptr)) __old = (old);                               \
>         __typeof__(*(ptr)) __new = (new);                               \
> +       kasan_check_write((void *)(ptr), sizeof(*(ptr)));               \
>         switch (size) {                                                 \
>         case __X86_CASE_B:                                              \
>         {                                                               \
> @@ -171,6 +174,7 @@ extern void __add_wrong_size(void)
>         BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long));                    \
>         VM_BUG_ON((unsigned long)(p1) % (2 * sizeof(long)));            \
>         VM_BUG_ON((unsigned long)((p1) + 1) != (unsigned long)(p2));    \
> +       kasan_check_write((void *)(p1), 2 * sizeof(*(p1)));             \
>         asm volatile(pfx "cmpxchg%c4b %2; sete %0"                      \
>                      : "=a" (__ret), "+d" (__old2),                     \
>                        "+m" (*(p1)), "+m" (*(p2))                       \
> --
> 2.12.0.rc1.440.g5b76565f74-goog
>

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  reply	other threads:[~2017-03-06 12:51 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-06 12:42 Dmitry Vyukov
2017-03-06 12:50 ` Dmitry Vyukov [this message]
2017-03-06 12:58   ` Peter Zijlstra
2017-03-06 13:01     ` Peter Zijlstra
2017-03-06 14:24       ` Dmitry Vyukov
2017-03-06 15:20         ` Peter Zijlstra
2017-03-06 16:04           ` Mark Rutland
2017-03-06 15:33         ` Peter Zijlstra
2017-03-06 16:20         ` Mark Rutland
2017-03-06 16:27           ` Dmitry Vyukov
2017-03-06 17:25             ` Mark Rutland
2017-03-06 20:35           ` Peter Zijlstra
2017-03-08 13:42             ` Dmitry Vyukov
2017-03-08 15:20               ` Mark Rutland
2017-03-08 15:27                 ` Dmitry Vyukov
2017-03-08 15:43                   ` Mark Rutland
2017-03-08 15:45                     ` Dmitry Vyukov
2017-03-08 15:48                       ` Mark Rutland
2017-03-08 17:43                 ` Will Deacon
2017-03-14 15:22                   ` Dmitry Vyukov
2017-03-14 15:31                     ` Peter Zijlstra
2017-03-14 15:32                     ` Peter Zijlstra
2017-03-14 15:44                       ` Mark Rutland
2017-03-14 19:25                         ` Dmitry Vyukov
2017-03-06 16:48         ` Andrey Ryabinin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CACT4Y+YmpTMdJca-rE2nXR-qa=wn_bCqQXaRghtg1uC65-pKyA@mail.gmail.com' \
    --to=dvyukov@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=aryabinin@virtuozzo.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox