x86, kasan: add KASAN checks to atomic operations
Subsystems (5)
Dmitry Vyukov
reviewerv4 cover x86, kasan: add KASAN checks to atomic operations
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
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 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: 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 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 __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
Changes since v1:
- dropped "x86: remove unused atomic_inc_short()" patch it is mailed separately
- rebased on top of tip/locking/core head
- other changes noted within individual patches
Changes since v2:
- rebased on top of tip/locking/core head
- dropped a pervasive "x86: use long long for 64-bit atomic ops" commit, instead use s64 type in wrappers
- added "x86: use s64* for old arg of atomic64_try_cmpxchg()" commit
Changes since v3 are noted in individual commits.
Tested:
- build/boot x86_64 defconfig
- build/boot x86_64 defconfig+KASAN
- build i686/powerpc defconfig
Dmitry Vyukov (7):
x86: un-macro-ify atomic ops implementation
x86: use s64* for old arg of atomic64_try_cmpxchg()
asm-generic: add atomic-instrumented.h
x86: switch atomic.h to use atomic-instrumented.h
kasan: allow kasan_check_read/write() to accept pointers to volatiles
asm-generic: add KASAN instrumentation to atomic operations asm-generic, x86: add comments for atomic instrumentation
arch/x86/include/asm/atomic.h | 150 ++++++----- arch/x86/include/asm/atomic64_32.h | 153 ++++++----- arch/x86/include/asm/atomic64_64.h | 151 ++++++----- arch/x86/include/asm/cmpxchg.h | 14 +- arch/x86/include/asm/cmpxchg_32.h | 8 +- arch/x86/include/asm/cmpxchg_64.h | 4 +- include/asm-generic/atomic-instrumented.h | 414 ++++++++++++++++++++++++++++++ include/linux/kasan-checks.h | 10 +- mm/kasan/kasan.c | 4 +- 9 files changed, 702 insertions(+), 206 deletions(-) create mode 100644 include/asm-generic/atomic-instrumented.h
Signature · 1 line
2.13.1.518.g3df882009-goog
Dmitry Vyukov
reviewerPATCH v4 1/7 x86: un-macro-ify atomic ops implementation
CPP turns perfectly readable code into an unreadable, unmaintainable mess. Ingo suggested to write them out as-is. Do this.
--- arch/x86/include/asm/atomic.h | 80 ++++++++++++++++++++++++-------------- arch/x86/include/asm/atomic64_32.h | 77 ++++++++++++++++++++++++------------ arch/x86/include/asm/atomic64_64.h | 67 ++++++++++++++++++++----------- 3 files changed, 148 insertions(+), 76 deletions(-)
arch/x86/include/asm/atomic.h +51 -29
@@ -197,35 +197,57 @@ static inline int atomic_xchg(atomic_t *v, int new)return xchg (&v->counter, new); } -#define ATOMIC_OP (op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - asm volatile(LOCK_PREFIX #op"l %1,%0" \ - : "+m" (v->counter) \ - : "ir" (i) \ - : "memory"); \ -} - -#define ATOMIC_FETCH_OP (op, c_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - int val = atomic_read(v); \ - do { \ - } while (!atomic_try_cmpxchg(v, &val, val c_op i)); \ - return val; \ -} - -#define ATOMIC_OPS (op, c_op) \ - ATOMIC_OP(op) \ - ATOMIC_FETCH_OP(op, c_op) - -ATOMIC_OPS(and, &) -ATOMIC_OPS(or , |) -ATOMIC_OPS(xor, ^) - -#undef ATOMIC_OPS -#undef ATOMIC_FETCH_OP -#undef ATOMIC_OP +static inline void atomic_and (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "andl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_and (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { + }while (!atomic_try_cmpxchg (v, &val, val & i)); +return val; +} + +static inline void atomic_or (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "orl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_or (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { + }while (!atomic_try_cmpxchg (v, &val, val | i)); +return val; +} + + +static inline void atomic_xor (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "xorl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_xor (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { + }while (!atomic_try_cmpxchg (v, &val, val ^ i)); +return val; +}/** * __atomic_add_unless - add unless the number is already a given value
arch/x86/include/asm/atomic64_32.h +53 -24
90 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +44 -23
78 lines not on this page · raw message
Signature · 1 line
2.13.1.518.g3df882009-goog
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic/x86: Un-macro-ify atomic ops implementation
locking/atomic/x86: Un-macro-ify atomic ops implementation
Commit-ID: 0f2376eb0ff8851124c876eb81806d7ec1b421d1 Gitweb: http://git.kernel.org/tip/0f2376eb0ff8851124c876eb81806d7ec1b421d1 Author: Dmitry Vyukov <[email protected]> AuthorDate: Sat, 17 Jun 2017 11:15:27 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 22 Jun 2017 10:19:56 +0200
locking/atomic/x86: Un-macro-ify atomic ops implementation
CPP turns perfectly readable code into a much harder to read syntactic soup.
Ingo suggested to write them out as-is in C and ignore the higher linecount.
Do this.
(As a side effect, plain C functions will be easier to KASAN-instrument as well.)
[ Beautified the C code some more and twiddled the changelog
to mention the linecount increase and the KASAN benefit. ]
--- arch/x86/include/asm/atomic.h | 69 +++++++++++++++++++++----------- arch/x86/include/asm/atomic64_32.h | 81 +++++++++++++++++++++++++++----------- arch/x86/include/asm/atomic64_64.h | 67 ++++++++++++++++++++----------- 3 files changed, 147 insertions(+), 70 deletions(-)
arch/x86/include/asm/atomic.h +46 -23
@@ -197,35 +197,56 @@ static inline int atomic_xchg(atomic_t *v, int new)return xchg (&v->counter, new); } -#define ATOMIC_OP (op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - asm volatile(LOCK_PREFIX #op"l %1,%0" \ - : "+m" (v->counter) \ - : "ir" (i) \ - : "memory"); \ +static inline void atomic_and (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "andl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_and (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { }while (!atomic_try_cmpxchg (v, &val, val & i)); + +return val; } -#define ATOMIC_FETCH_OP (op, c_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - int val = atomic_read(v); \ - do { \ - } while (!atomic_try_cmpxchg(v, &val, val c_op i)); \ - return val; \ +static inline void atomic_or (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "orl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); } -#define ATOMIC_OPS (op, c_op) \ - ATOMIC_OP(op) \ - ATOMIC_FETCH_OP(op, c_op) +static inline int atomic_fetch_or (int i,atomic_t *v) +{ +int val =atomic_read (v); -ATOMIC_OPS(and, &) -ATOMIC_OPS(or , |) -ATOMIC_OPS(xor, ^) +do { }while (!atomic_try_cmpxchg (v, &val, val | i)); -#undef ATOMIC_OPS -#undef ATOMIC_FETCH_OP -#undef ATOMIC_OP +return val; +} + +static inline void atomic_xor (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "xorl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_xor (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { }while (!atomic_try_cmpxchg (v, &val, val ^ i)); + +return val; +}/** * __atomic_add_unless - add unless the number is already a given value
@@ -239,10 +260,12 @@ ATOMIC_OPS(xor, ^) static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) {int c =atomic_read (v); +do {if (unlikely (c == u))break ; }while (!atomic_try_cmpxchg (v, &c, c + a)); +return c; }
arch/x86/include/asm/atomic64_32.h +57 -24
94 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +44 -23
78 lines not on this page · raw message
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic/x86: Un-macro-ify atomic ops implementation
In reply to Dmitry Vyukovlocking/atomic/x86: Un-macro-ify atomic ops implementation
Commit-ID: ba1c9f83f6330a34cc77ef989e183f54c4fe732e Gitweb: http://git.kernel.org/tip/ba1c9f83f6330a34cc77ef989e183f54c4fe732e Author: Dmitry Vyukov <[email protected]> AuthorDate: Sat, 17 Jun 2017 11:15:27 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 28 Jun 2017 18:55:55 +0200
locking/atomic/x86: Un-macro-ify atomic ops implementation
CPP turns perfectly readable code into a much harder to read syntactic soup.
Ingo suggested to write them out as-is in C and ignore the higher linecount.
Do this.
(As a side effect, plain C functions will be easier to KASAN-instrument as well.)
[ Beautified the C code some more and twiddled the changelog
to mention the linecount increase and the KASAN benefit. ]
--- arch/x86/include/asm/atomic.h | 69 +++++++++++++++++++++----------- arch/x86/include/asm/atomic64_32.h | 81 +++++++++++++++++++++++++++----------- arch/x86/include/asm/atomic64_64.h | 67 ++++++++++++++++++++----------- 3 files changed, 147 insertions(+), 70 deletions(-)
arch/x86/include/asm/atomic.h +46 -23
@@ -197,35 +197,56 @@ static inline int atomic_xchg(atomic_t *v, int new)return xchg (&v->counter, new); } -#define ATOMIC_OP (op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - asm volatile(LOCK_PREFIX #op"l %1,%0" \ - : "+m" (v->counter) \ - : "ir" (i) \ - : "memory"); \ +static inline void atomic_and (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "andl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_and (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { }while (!atomic_try_cmpxchg (v, &val, val & i)); + +return val; } -#define ATOMIC_FETCH_OP (op, c_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - int val = atomic_read(v); \ - do { \ - } while (!atomic_try_cmpxchg(v, &val, val c_op i)); \ - return val; \ +static inline void atomic_or (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "orl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); } -#define ATOMIC_OPS (op, c_op) \ - ATOMIC_OP(op) \ - ATOMIC_FETCH_OP(op, c_op) +static inline int atomic_fetch_or (int i,atomic_t *v) +{ +int val =atomic_read (v); -ATOMIC_OPS(and, &) -ATOMIC_OPS(or , |) -ATOMIC_OPS(xor, ^) +do { }while (!atomic_try_cmpxchg (v, &val, val | i)); -#undef ATOMIC_OPS -#undef ATOMIC_FETCH_OP -#undef ATOMIC_OP +return val; +} + +static inline void atomic_xor (int i,atomic_t *v) +{ + asmvolatile (LOCK_PREFIX "xorl %1,%0" + :"+m" (v->counter) + :"ir" (i) + :"memory" ); +} + +static inline int atomic_fetch_xor (int i,atomic_t *v) +{ +int val =atomic_read (v); + +do { }while (!atomic_try_cmpxchg (v, &val, val ^ i)); + +return val; +}/** * __atomic_add_unless - add unless the number is already a given value
@@ -239,10 +260,12 @@ ATOMIC_OPS(xor, ^) static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) {int c =atomic_read (v); +do {if (unlikely (c == u))break ; }while (!atomic_try_cmpxchg (v, &c, c + a)); +return c; }
arch/x86/include/asm/atomic64_32.h +57 -24
94 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +44 -23
78 lines not on this page · raw message
Dmitry Vyukov
reviewerPATCH v4 2/7 x86: use s64* for old arg of atomic64_try_cmpxchg()
In reply to Dmitry Vyukovatomic64_try_cmpxchg() declares old argument as long*, this makes it impossible to use it in portable code. If caller passes long*, it becomes 32-bits on 32-bit arches. If caller passes s64*, it does not compile on x86_64.
Change type of old arg to s64*.
--- arch/x86/include/asm/atomic64_64.h | 12 ++++++------ arch/x86/include/asm/cmpxchg.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/atomic64_64.h +6 -6
@@ -177,7 +177,7 @@ static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) }#define atomic64_try_cmpxchg atomic64_try_cmpxchg -static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, long *old, long new) +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, long new) {return try_cmpxchg (&v->counter, old, new); }
@@ -198,7 +198,7 @@ static inline long atomic64_xchg(atomic64_t *v, long new)*/ static inline bool atomic64_add_unless (atomic64_t *v,long a,long u) { -long c =atomic64_read (v); +s64 c =atomic64_read (v); do { if (unlikely(c == u)) return false;
@@ -217,7 +217,7 @@ static inline bool atomic64_add_unless(atomic64_t *v, long a, long u)*/ static inline long atomic64_dec_if_positive (atomic64_t *v) { -long dec, c =atomic64_read (v); +s64 dec, c =atomic64_read (v); do { dec = c - 1; if (unlikely(dec < 0))
@@ -236,7 +236,7 @@ static inline void atomic64_and(long i, atomic64_t *v)static inline long atomic64_fetch_and (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val & i));
@@ -253,7 +253,7 @@ static inline void atomic64_or(long i, atomic64_t *v)static inline long atomic64_fetch_or (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val | i));
@@ -270,7 +270,7 @@ static inline void atomic64_xor(long i, atomic64_t *v)static inline long atomic64_fetch_xor (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val ^ i));
arch/x86/include/asm/cmpxchg.h +1 -1
@@ -157,7 +157,7 @@ extern void __add_wrong_size(void)#define __raw_try_cmpxchg (_ptr, _pold, _new, size, lock) \ ({ \ bool success; \ - __typeof__(_ptr) _old = (_pold); \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __new = (_new); \ switch (size) { \
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
locking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
Commit-ID: f6dda790094b0d658b59cf108c52805f1f7c11e6 Gitweb: http://git.kernel.org/tip/f6dda790094b0d658b59cf108c52805f1f7c11e6 Author: Dmitry Vyukov <[email protected]> AuthorDate: Sat, 17 Jun 2017 11:15:28 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 22 Jun 2017 10:19:56 +0200
locking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
atomic64_try_cmpxchg() declares old argument as 'long *', this makes it impossible to use it in portable code. If caller passes 'long *', it becomes 32-bits on 32-bit arches. If caller passes 's64 *', it does not compile on x86_64.
Change type of old argument to 's64 *' instead.
--- arch/x86/include/asm/atomic64_64.h | 12 ++++++------ arch/x86/include/asm/cmpxchg.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/atomic64_64.h +6 -6
@@ -177,7 +177,7 @@ static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) }#define atomic64_try_cmpxchg atomic64_try_cmpxchg -static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, long *old, long new) +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, long new) {return try_cmpxchg (&v->counter, old, new); }
@@ -198,7 +198,7 @@ static inline long atomic64_xchg(atomic64_t *v, long new)*/ static inline bool atomic64_add_unless (atomic64_t *v,long a,long u) { -long c =atomic64_read (v); +s64 c =atomic64_read (v); do { if (unlikely(c == u)) return false;
@@ -217,7 +217,7 @@ static inline bool atomic64_add_unless(atomic64_t *v, long a, long u)*/ static inline long atomic64_dec_if_positive (atomic64_t *v) { -long dec, c =atomic64_read (v); +s64 dec, c =atomic64_read (v); do { dec = c - 1; if (unlikely(dec < 0))
@@ -236,7 +236,7 @@ static inline void atomic64_and(long i, atomic64_t *v)static inline long atomic64_fetch_and (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val & i));
@@ -253,7 +253,7 @@ static inline void atomic64_or(long i, atomic64_t *v)static inline long atomic64_fetch_or (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val | i));
@@ -270,7 +270,7 @@ static inline void atomic64_xor(long i, atomic64_t *v)static inline long atomic64_fetch_xor (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val ^ i));
arch/x86/include/asm/cmpxchg.h +1 -1
@@ -157,7 +157,7 @@ extern void __add_wrong_size(void)#define __raw_try_cmpxchg (_ptr, _pold, _new, size, lock) \ ({ \ bool success; \ - __typeof__(_ptr) _old = (_pold); \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __new = (_new); \ switch (size) { \
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
In reply to Dmitry Vyukovlocking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
Commit-ID: 007d185b44620f6ffa58f52476bed6e6d7d69d3b Gitweb: http://git.kernel.org/tip/007d185b44620f6ffa58f52476bed6e6d7d69d3b Author: Dmitry Vyukov <[email protected]> AuthorDate: Sat, 17 Jun 2017 11:15:28 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 28 Jun 2017 18:55:55 +0200
locking/atomic/x86: Use 's64 *' for 'old' argument of atomic64_try_cmpxchg()
atomic64_try_cmpxchg() declares old argument as 'long *', this makes it impossible to use it in portable code. If caller passes 'long *', it becomes 32-bits on 32-bit arches. If caller passes 's64 *', it does not compile on x86_64.
Change type of old argument to 's64 *' instead.
--- arch/x86/include/asm/atomic64_64.h | 12 ++++++------ arch/x86/include/asm/cmpxchg.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-)
arch/x86/include/asm/atomic64_64.h +6 -6
@@ -177,7 +177,7 @@ static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new) }#define atomic64_try_cmpxchg atomic64_try_cmpxchg -static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, long *old, long new) +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, long new) {return try_cmpxchg (&v->counter, old, new); }
@@ -198,7 +198,7 @@ static inline long atomic64_xchg(atomic64_t *v, long new)*/ static inline bool atomic64_add_unless (atomic64_t *v,long a,long u) { -long c =atomic64_read (v); +s64 c =atomic64_read (v); do { if (unlikely(c == u)) return false;
@@ -217,7 +217,7 @@ static inline bool atomic64_add_unless(atomic64_t *v, long a, long u)*/ static inline long atomic64_dec_if_positive (atomic64_t *v) { -long dec, c =atomic64_read (v); +s64 dec, c =atomic64_read (v); do { dec = c - 1; if (unlikely(dec < 0))
@@ -236,7 +236,7 @@ static inline void atomic64_and(long i, atomic64_t *v)static inline long atomic64_fetch_and (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val & i));
@@ -253,7 +253,7 @@ static inline void atomic64_or(long i, atomic64_t *v)static inline long atomic64_fetch_or (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val | i));
@@ -270,7 +270,7 @@ static inline void atomic64_xor(long i, atomic64_t *v)static inline long atomic64_fetch_xor (long i,atomic64_t *v) { -long val =atomic64_read (v); +s64 val =atomic64_read (v);do { }while (!atomic64_try_cmpxchg (v, &val, val ^ i));
arch/x86/include/asm/cmpxchg.h +1 -1
@@ -157,7 +157,7 @@ extern void __add_wrong_size(void)#define __raw_try_cmpxchg (_ptr, _pold, _new, size, lock) \ ({ \ bool success; \ - __typeof__(_ptr) _old = (_pold); \ + __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ __typeof__(*(_ptr)) __old = *_old; \ __typeof__(*(_ptr)) __new = (_new); \ switch (size) { \
Dmitry Vyukov
reviewerPATCH v4 3/7 asm-generic: add atomic-instrumented.h
In reply to Dmitry VyukovThe new header allows to wrap per-arch atomic operations and add common functionality to all of them.
--- include/asm-generic/atomic-instrumented.h | 316 ++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+)
include/asm-generic/atomic-instrumented.h new file +316 -0
@@ -0,0 +1,316 @@ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H +#define _LINUX_ATOMIC_INSTRUMENTED_H + +static __always_inline int atomic_read(const atomic_t *v) +{ +return arch_atomic_read (v); +} + +static __always_inline s64 atomic64_read(const atomic64_t *v) +{ +return arch_atomic64_read (v); +} + +static __always_inline void atomic_set(atomic_t *v, int i) +{ +arch_atomic_set (v, i); +} + +static __always_inline void atomic64_set(atomic64_t *v, s64 i) +{ +arch_atomic64_set (v, i); +} + +static __always_inline int atomic_xchg(atomic_t *v, int i) +{ +return arch_atomic_xchg (v, i); +} + +static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) +{ +return arch_atomic64_xchg (v, i); +} + +static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ +return arch_atomic_cmpxchg (v, old, new); +} + +static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) +{ +return arch_atomic64_cmpxchg (v, old, new); +} + +#ifdef arch_atomic_try_cmpxchg +#define atomic_try_cmpxchg atomic_try_cmpxchg +static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ +return arch_atomic_try_cmpxchg (v, old, new); +} +#endif + +#ifdef arch_atomic64_try_cmpxchg +#define atomic64_try_cmpxchg atomic64_try_cmpxchg +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ +return arch_atomic64_try_cmpxchg (v, old, new); +} +#endif + +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +return __arch_atomic_add_unless (v, a, u); +} + + +static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) +{ +return arch_atomic64_add_unless (v, a, u); +} + +static __always_inline void atomic_inc(atomic_t *v) +{ +arch_atomic_inc (v); +} + +static __always_inline void atomic64_inc(atomic64_t *v) +{ +arch_atomic64_inc (v); +} + +static __always_inline void atomic_dec(atomic_t *v) +{ +arch_atomic_dec (v); +} + +static __always_inline void atomic64_dec(atomic64_t *v) +{ +arch_atomic64_dec (v); +} + +static __always_inline void atomic_add(int i, atomic_t *v) +{ +arch_atomic_add (i, v); +} + +static __always_inline void atomic64_add(s64 i, atomic64_t *v) +{ +arch_atomic64_add (i, v); +} + +static __always_inline void atomic_sub(int i, atomic_t *v) +{ +arch_atomic_sub (i, v); +} + +static __always_inline void atomic64_sub(s64 i, atomic64_t *v) +{ +arch_atomic64_sub (i, v); +} + +static __always_inline void atomic_and(int i, atomic_t *v) +{ +arch_atomic_and (i, v); +} + +static __always_inline void atomic64_and(s64 i, atomic64_t *v) +{ +arch_atomic64_and (i, v); +} + +static __always_inline void atomic_or(int i, atomic_t *v) +{ +arch_atomic_or (i, v); +} + +static __always_inline void atomic64_or(s64 i, atomic64_t *v) +{ +arch_atomic64_or (i, v); +} + +static __always_inline void atomic_xor(int i, atomic_t *v) +{ +arch_atomic_xor (i, v); +} + +static __always_inline void atomic64_xor(s64 i, atomic64_t *v) +{ +arch_atomic64_xor (i, v); +} + +static __always_inline int atomic_inc_return(atomic_t *v) +{ +return arch_atomic_inc_return (v); +} + +static __always_inline s64 atomic64_inc_return(atomic64_t *v) +{ +return arch_atomic64_inc_return (v); +} + +static __always_inline int atomic_dec_return(atomic_t *v) +{ +return arch_atomic_dec_return (v); +} + +static __always_inline s64 atomic64_dec_return(atomic64_t *v) +{ +return arch_atomic64_dec_return (v); +} + +static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) +{ +return arch_atomic64_inc_not_zero (v); +} + +static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) +{ +return arch_atomic64_dec_if_positive (v); +} + +static __always_inline bool atomic_dec_and_test(atomic_t *v) +{ +return arch_atomic_dec_and_test (v); +} + +static __always_inline bool atomic64_dec_and_test(atomic64_t *v) +{ +return arch_atomic64_dec_and_test (v); +} + +static __always_inline bool atomic_inc_and_test(atomic_t *v) +{ +return arch_atomic_inc_and_test (v); +} + +static __always_inline bool atomic64_inc_and_test(atomic64_t *v) +{ +return arch_atomic64_inc_and_test (v); +} + +static __always_inline int atomic_add_return(int i, atomic_t *v) +{ +return arch_atomic_add_return (i, v); +} + +static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_return (i, v); +} + +static __always_inline int atomic_sub_return(int i, atomic_t *v) +{ +return arch_atomic_sub_return (i, v); +} + +static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_return (i, v); +} + +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ +return arch_atomic_fetch_add (i, v); +} + +static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_add (i, v); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ +return arch_atomic_fetch_sub (i, v); +} + +static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_sub (i, v); +} + +static __always_inline int atomic_fetch_and(int i, atomic_t *v) +{ +return arch_atomic_fetch_and (i, v); +} + +static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_and (i, v); +} + +static __always_inline int atomic_fetch_or(int i, atomic_t *v) +{ +return arch_atomic_fetch_or (i, v); +} + +static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_or (i, v); +} + +static __always_inline int atomic_fetch_xor(int i, atomic_t *v) +{ +return arch_atomic_fetch_xor (i, v); +} + +static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_xor (i, v); +} + +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +{ +return arch_atomic_sub_and_test (i, v); +} + +static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_and_test (i, v); +} + +static __always_inline bool atomic_add_negative(int i, atomic_t *v) +{ +return arch_atomic_add_negative (i, v); +} + +static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_negative (i, v); +} + +#define cmpxchg (ptr, old, new) \ +({ \ + arch_cmpxchg((ptr), (old), (new)); \ +}) + +#define sync_cmpxchg (ptr, old, new) \ +({ \ + arch_sync_cmpxchg((ptr), (old), (new)); \ +}) + +#define cmpxchg_local (ptr, old, new) \ +({ \ + arch_cmpxchg_local((ptr), (old), (new)); \ +}) + +#define cmpxchg64 (ptr, old, new) \ +({ \ + arch_cmpxchg64((ptr), (old), (new)); \ +}) + +#define cmpxchg64_local (ptr, old, new) \ +({ \ + arch_cmpxchg64_local((ptr), (old), (new)); \ +}) + +#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double_local((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4 3/7] asm-generic: add atomic-instrumented.h
Quoted 14 lines · Dmitry Vyukov
The new header allows to wrap per-arch atomic operations and add common functionality to all of them.
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Will Deacon <[email protected]>Cc Andrew Morton <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Ingo Molnar <[email protected]>
Looks sane to me, and I can see how this can be extended to cover all the ordering vairants arm64 will require. I've pushed my WIP [1].
FWIW:
Mark.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git/log/?h=arm64/kasan-atomic
Quoted 329 lines
--- include/asm-generic/atomic-instrumented.h | 316 ++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+)include/asm-generic/atomic-instrumented.h new file +316
-0@@ -0,0 +1,316 @@ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H +#define _LINUX_ATOMIC_INSTRUMENTED_H + +static __always_inline int atomic_read(const atomic_t *v) +{ +return arch_atomic_read (v); +} + +static __always_inline s64 atomic64_read(const atomic64_t *v) +{ +return arch_atomic64_read (v); +} + +static __always_inline void atomic_set(atomic_t *v, int i) +{ +arch_atomic_set (v, i); +} + +static __always_inline void atomic64_set(atomic64_t *v, s64 i) +{ +arch_atomic64_set (v, i); +} + +static __always_inline int atomic_xchg(atomic_t *v, int i) +{ +return arch_atomic_xchg (v, i); +} + +static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) +{ +return arch_atomic64_xchg (v, i); +} + +static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ +return arch_atomic_cmpxchg (v, old, new); +} + +static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) +{ +return arch_atomic64_cmpxchg (v, old, new); +} + +#ifdef arch_atomic_try_cmpxchg +#define atomic_try_cmpxchg atomic_try_cmpxchg +static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ +return arch_atomic_try_cmpxchg (v, old, new); +} +#endif + +#ifdef arch_atomic64_try_cmpxchg +#define atomic64_try_cmpxchg atomic64_try_cmpxchg +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ +return arch_atomic64_try_cmpxchg (v, old, new); +} +#endif + +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +return __arch_atomic_add_unless (v, a, u); +} + + +static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) +{ +return arch_atomic64_add_unless (v, a, u); +} + +static __always_inline void atomic_inc(atomic_t *v) +{ +arch_atomic_inc (v); +} + +static __always_inline void atomic64_inc(atomic64_t *v) +{ +arch_atomic64_inc (v); +} + +static __always_inline void atomic_dec(atomic_t *v) +{ +arch_atomic_dec (v); +} + +static __always_inline void atomic64_dec(atomic64_t *v) +{ +arch_atomic64_dec (v); +} + +static __always_inline void atomic_add(int i, atomic_t *v) +{ +arch_atomic_add (i, v); +} + +static __always_inline void atomic64_add(s64 i, atomic64_t *v) +{ +arch_atomic64_add (i, v); +} + +static __always_inline void atomic_sub(int i, atomic_t *v) +{ +arch_atomic_sub (i, v); +} + +static __always_inline void atomic64_sub(s64 i, atomic64_t *v) +{ +arch_atomic64_sub (i, v); +} + +static __always_inline void atomic_and(int i, atomic_t *v) +{ +arch_atomic_and (i, v); +} + +static __always_inline void atomic64_and(s64 i, atomic64_t *v) +{ +arch_atomic64_and (i, v); +} + +static __always_inline void atomic_or(int i, atomic_t *v) +{ +arch_atomic_or (i, v); +} + +static __always_inline void atomic64_or(s64 i, atomic64_t *v) +{ +arch_atomic64_or (i, v); +} + +static __always_inline void atomic_xor(int i, atomic_t *v) +{ +arch_atomic_xor (i, v); +} + +static __always_inline void atomic64_xor(s64 i, atomic64_t *v) +{ +arch_atomic64_xor (i, v); +} + +static __always_inline int atomic_inc_return(atomic_t *v) +{ +return arch_atomic_inc_return (v); +} + +static __always_inline s64 atomic64_inc_return(atomic64_t *v) +{ +return arch_atomic64_inc_return (v); +} + +static __always_inline int atomic_dec_return(atomic_t *v) +{ +return arch_atomic_dec_return (v); +} + +static __always_inline s64 atomic64_dec_return(atomic64_t *v) +{ +return arch_atomic64_dec_return (v); +} + +static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) +{ +return arch_atomic64_inc_not_zero (v); +} + +static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) +{ +return arch_atomic64_dec_if_positive (v); +} + +static __always_inline bool atomic_dec_and_test(atomic_t *v) +{ +return arch_atomic_dec_and_test (v); +} + +static __always_inline bool atomic64_dec_and_test(atomic64_t *v) +{ +return arch_atomic64_dec_and_test (v); +} + +static __always_inline bool atomic_inc_and_test(atomic_t *v) +{ +return arch_atomic_inc_and_test (v); +} + +static __always_inline bool atomic64_inc_and_test(atomic64_t *v) +{ +return arch_atomic64_inc_and_test (v); +} + +static __always_inline int atomic_add_return(int i, atomic_t *v) +{ +return arch_atomic_add_return (i, v); +} + +static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_return (i, v); +} + +static __always_inline int atomic_sub_return(int i, atomic_t *v) +{ +return arch_atomic_sub_return (i, v); +} + +static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_return (i, v); +} + +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ +return arch_atomic_fetch_add (i, v); +} + +static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_add (i, v); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ +return arch_atomic_fetch_sub (i, v); +} + +static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_sub (i, v); +} + +static __always_inline int atomic_fetch_and(int i, atomic_t *v) +{ +return arch_atomic_fetch_and (i, v); +} + +static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_and (i, v); +} + +static __always_inline int atomic_fetch_or(int i, atomic_t *v) +{ +return arch_atomic_fetch_or (i, v); +} + +static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_or (i, v); +} + +static __always_inline int atomic_fetch_xor(int i, atomic_t *v) +{ +return arch_atomic_fetch_xor (i, v); +} + +static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_xor (i, v); +} + +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +{ +return arch_atomic_sub_and_test (i, v); +} + +static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_and_test (i, v); +} + +static __always_inline bool atomic_add_negative(int i, atomic_t *v) +{ +return arch_atomic_add_negative (i, v); +} + +static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_negative (i, v); +} + +#define cmpxchg (ptr, old, new) \ +({ \ + arch_cmpxchg((ptr), (old), (new)); \ +}) + +#define sync_cmpxchg (ptr, old, new) \ +({ \ + arch_sync_cmpxchg((ptr), (old), (new)); \ +}) + +#define cmpxchg_local (ptr, old, new) \ +({ \ + arch_cmpxchg_local((ptr), (old), (new)); \ +}) + +#define cmpxchg64 (ptr, old, new) \ +({ \ + arch_cmpxchg64((ptr), (old), (new)); \ +}) + +#define cmpxchg64_local (ptr, old, new) \ +({ \ + arch_cmpxchg64_local((ptr), (old), (new)); \ +}) + +#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double_local((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */ Signature · 1 line
2.13.1.518.g3df882009-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic: Add asm-generic/atomic-instrumented.h
In reply to Dmitry Vyukovlocking/atomic: Add asm-generic/atomic-instrumented.h
Commit-ID: ff5060d9b2a73917dbf52654e29b08018e22a1f9 Gitweb: http://git.kernel.org/tip/ff5060d9b2a73917dbf52654e29b08018e22a1f9 Author: Dmitry Vyukov <[email protected]> AuthorDate: Sat, 17 Jun 2017 11:15:29 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 22 Jun 2017 10:20:12 +0200
locking/atomic: Add asm-generic/atomic-instrumented.h
The new header allows to wrap per-arch atomic operations and add common functionality to all of them.
--- include/asm-generic/atomic-instrumented.h | 316 ++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+)
include/asm-generic/atomic-instrumented.h new file +316 -0
@@ -0,0 +1,316 @@ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H +#define _LINUX_ATOMIC_INSTRUMENTED_H + +static __always_inline int atomic_read(const atomic_t *v) +{ +return arch_atomic_read (v); +} + +static __always_inline s64 atomic64_read(const atomic64_t *v) +{ +return arch_atomic64_read (v); +} + +static __always_inline void atomic_set(atomic_t *v, int i) +{ +arch_atomic_set (v, i); +} + +static __always_inline void atomic64_set(atomic64_t *v, s64 i) +{ +arch_atomic64_set (v, i); +} + +static __always_inline int atomic_xchg(atomic_t *v, int i) +{ +return arch_atomic_xchg (v, i); +} + +static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) +{ +return arch_atomic64_xchg (v, i); +} + +static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ +return arch_atomic_cmpxchg (v, old, new); +} + +static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) +{ +return arch_atomic64_cmpxchg (v, old, new); +} + +#ifdef arch_atomic_try_cmpxchg +#define atomic_try_cmpxchg atomic_try_cmpxchg +static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ +return arch_atomic_try_cmpxchg (v, old, new); +} +#endif + +#ifdef arch_atomic64_try_cmpxchg +#define atomic64_try_cmpxchg atomic64_try_cmpxchg +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ +return arch_atomic64_try_cmpxchg (v, old, new); +} +#endif + +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +return __arch_atomic_add_unless (v, a, u); +} + + +static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) +{ +return arch_atomic64_add_unless (v, a, u); +} + +static __always_inline void atomic_inc(atomic_t *v) +{ +arch_atomic_inc (v); +} + +static __always_inline void atomic64_inc(atomic64_t *v) +{ +arch_atomic64_inc (v); +} + +static __always_inline void atomic_dec(atomic_t *v) +{ +arch_atomic_dec (v); +} + +static __always_inline void atomic64_dec(atomic64_t *v) +{ +arch_atomic64_dec (v); +} + +static __always_inline void atomic_add(int i, atomic_t *v) +{ +arch_atomic_add (i, v); +} + +static __always_inline void atomic64_add(s64 i, atomic64_t *v) +{ +arch_atomic64_add (i, v); +} + +static __always_inline void atomic_sub(int i, atomic_t *v) +{ +arch_atomic_sub (i, v); +} + +static __always_inline void atomic64_sub(s64 i, atomic64_t *v) +{ +arch_atomic64_sub (i, v); +} + +static __always_inline void atomic_and(int i, atomic_t *v) +{ +arch_atomic_and (i, v); +} + +static __always_inline void atomic64_and(s64 i, atomic64_t *v) +{ +arch_atomic64_and (i, v); +} + +static __always_inline void atomic_or(int i, atomic_t *v) +{ +arch_atomic_or (i, v); +} + +static __always_inline void atomic64_or(s64 i, atomic64_t *v) +{ +arch_atomic64_or (i, v); +} + +static __always_inline void atomic_xor(int i, atomic_t *v) +{ +arch_atomic_xor (i, v); +} + +static __always_inline void atomic64_xor(s64 i, atomic64_t *v) +{ +arch_atomic64_xor (i, v); +} + +static __always_inline int atomic_inc_return(atomic_t *v) +{ +return arch_atomic_inc_return (v); +} + +static __always_inline s64 atomic64_inc_return(atomic64_t *v) +{ +return arch_atomic64_inc_return (v); +} + +static __always_inline int atomic_dec_return(atomic_t *v) +{ +return arch_atomic_dec_return (v); +} + +static __always_inline s64 atomic64_dec_return(atomic64_t *v) +{ +return arch_atomic64_dec_return (v); +} + +static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) +{ +return arch_atomic64_inc_not_zero (v); +} + +static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) +{ +return arch_atomic64_dec_if_positive (v); +} + +static __always_inline bool atomic_dec_and_test(atomic_t *v) +{ +return arch_atomic_dec_and_test (v); +} + +static __always_inline bool atomic64_dec_and_test(atomic64_t *v) +{ +return arch_atomic64_dec_and_test (v); +} + +static __always_inline bool atomic_inc_and_test(atomic_t *v) +{ +return arch_atomic_inc_and_test (v); +} + +static __always_inline bool atomic64_inc_and_test(atomic64_t *v) +{ +return arch_atomic64_inc_and_test (v); +} + +static __always_inline int atomic_add_return(int i, atomic_t *v) +{ +return arch_atomic_add_return (i, v); +} + +static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_return (i, v); +} + +static __always_inline int atomic_sub_return(int i, atomic_t *v) +{ +return arch_atomic_sub_return (i, v); +} + +static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_return (i, v); +} + +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ +return arch_atomic_fetch_add (i, v); +} + +static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_add (i, v); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ +return arch_atomic_fetch_sub (i, v); +} + +static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_sub (i, v); +} + +static __always_inline int atomic_fetch_and(int i, atomic_t *v) +{ +return arch_atomic_fetch_and (i, v); +} + +static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_and (i, v); +} + +static __always_inline int atomic_fetch_or(int i, atomic_t *v) +{ +return arch_atomic_fetch_or (i, v); +} + +static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_or (i, v); +} + +static __always_inline int atomic_fetch_xor(int i, atomic_t *v) +{ +return arch_atomic_fetch_xor (i, v); +} + +static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_xor (i, v); +} + +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +{ +return arch_atomic_sub_and_test (i, v); +} + +static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_and_test (i, v); +} + +static __always_inline bool atomic_add_negative(int i, atomic_t *v) +{ +return arch_atomic_add_negative (i, v); +} + +static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_negative (i, v); +} + +#define cmpxchg (ptr, old, new) \ +({ \ + arch_cmpxchg((ptr), (old), (new)); \ +}) + +#define sync_cmpxchg (ptr, old, new) \ +({ \ + arch_sync_cmpxchg((ptr), (old), (new)); \ +}) + +#define cmpxchg_local (ptr, old, new) \ +({ \ + arch_cmpxchg_local((ptr), (old), (new)); \ +}) + +#define cmpxchg64 (ptr, old, new) \ +({ \ + arch_cmpxchg64((ptr), (old), (new)); \ +}) + +#define cmpxchg64_local (ptr, old, new) \ +({ \ + arch_cmpxchg64_local((ptr), (old), (new)); \ +}) + +#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double_local((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic, asm-generic: Add asm-generic/atomic-instrumented.h
In reply to Dmitry Vyukovlocking/atomic, asm-generic: Add asm-generic/atomic-instrumented.h
Commit-ID: b06ed71a624ba088a3e3e3ac7d4185f48c7c1660 Gitweb: https://git.kernel.org/tip/b06ed71a624ba088a3e3e3ac7d4185f48c7c1660 Author: Dmitry Vyukov <[email protected]> AuthorDate: Mon, 29 Jan 2018 18:26:04 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 12 Mar 2018 12:15:27 +0100
locking/atomic, asm-generic: Add asm-generic/atomic-instrumented.h
The new header allows to wrap per-arch atomic operations and add common functionality to all of them.
--- include/asm-generic/atomic-instrumented.h | 393 ++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+)
include/asm-generic/atomic-instrumented.h new file +393 -0
@@ -0,0 +1,393 @@ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H +#define _LINUX_ATOMIC_INSTRUMENTED_H + +#include <linux/build_bug.h> + +static __always_inline int atomic_read(const atomic_t *v) +{ +return arch_atomic_read (v); +} + +static __always_inline s64 atomic64_read(const atomic64_t *v) +{ +return arch_atomic64_read (v); +} + +static __always_inline void atomic_set(atomic_t *v, int i) +{ +arch_atomic_set (v, i); +} + +static __always_inline void atomic64_set(atomic64_t *v, s64 i) +{ +arch_atomic64_set (v, i); +} + +static __always_inline int atomic_xchg(atomic_t *v, int i) +{ +return arch_atomic_xchg (v, i); +} + +static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) +{ +return arch_atomic64_xchg (v, i); +} + +static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ +return arch_atomic_cmpxchg (v, old, new); +} + +static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) +{ +return arch_atomic64_cmpxchg (v, old, new); +} + +#ifdef arch_atomic_try_cmpxchg +#define atomic_try_cmpxchg atomic_try_cmpxchg +static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ +return arch_atomic_try_cmpxchg (v, old, new); +} +#endif + +#ifdef arch_atomic64_try_cmpxchg +#define atomic64_try_cmpxchg atomic64_try_cmpxchg +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ +return arch_atomic64_try_cmpxchg (v, old, new); +} +#endif + +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +return __arch_atomic_add_unless (v, a, u); +} + + +static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) +{ +return arch_atomic64_add_unless (v, a, u); +} + +static __always_inline void atomic_inc(atomic_t *v) +{ +arch_atomic_inc (v); +} + +static __always_inline void atomic64_inc(atomic64_t *v) +{ +arch_atomic64_inc (v); +} + +static __always_inline void atomic_dec(atomic_t *v) +{ +arch_atomic_dec (v); +} + +static __always_inline void atomic64_dec(atomic64_t *v) +{ +arch_atomic64_dec (v); +} + +static __always_inline void atomic_add(int i, atomic_t *v) +{ +arch_atomic_add (i, v); +} + +static __always_inline void atomic64_add(s64 i, atomic64_t *v) +{ +arch_atomic64_add (i, v); +} + +static __always_inline void atomic_sub(int i, atomic_t *v) +{ +arch_atomic_sub (i, v); +} + +static __always_inline void atomic64_sub(s64 i, atomic64_t *v) +{ +arch_atomic64_sub (i, v); +} + +static __always_inline void atomic_and(int i, atomic_t *v) +{ +arch_atomic_and (i, v); +} + +static __always_inline void atomic64_and(s64 i, atomic64_t *v) +{ +arch_atomic64_and (i, v); +} + +static __always_inline void atomic_or(int i, atomic_t *v) +{ +arch_atomic_or (i, v); +} + +static __always_inline void atomic64_or(s64 i, atomic64_t *v) +{ +arch_atomic64_or (i, v); +} + +static __always_inline void atomic_xor(int i, atomic_t *v) +{ +arch_atomic_xor (i, v); +} + +static __always_inline void atomic64_xor(s64 i, atomic64_t *v) +{ +arch_atomic64_xor (i, v); +} + +static __always_inline int atomic_inc_return(atomic_t *v) +{ +return arch_atomic_inc_return (v); +} + +static __always_inline s64 atomic64_inc_return(atomic64_t *v) +{ +return arch_atomic64_inc_return (v); +} + +static __always_inline int atomic_dec_return(atomic_t *v) +{ +return arch_atomic_dec_return (v); +} + +static __always_inline s64 atomic64_dec_return(atomic64_t *v) +{ +return arch_atomic64_dec_return (v); +} + +static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) +{ +return arch_atomic64_inc_not_zero (v); +} + +static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) +{ +return arch_atomic64_dec_if_positive (v); +} + +static __always_inline bool atomic_dec_and_test(atomic_t *v) +{ +return arch_atomic_dec_and_test (v); +} + +static __always_inline bool atomic64_dec_and_test(atomic64_t *v) +{ +return arch_atomic64_dec_and_test (v); +} + +static __always_inline bool atomic_inc_and_test(atomic_t *v) +{ +return arch_atomic_inc_and_test (v); +} + +static __always_inline bool atomic64_inc_and_test(atomic64_t *v) +{ +return arch_atomic64_inc_and_test (v); +} + +static __always_inline int atomic_add_return(int i, atomic_t *v) +{ +return arch_atomic_add_return (i, v); +} + +static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_return (i, v); +} + +static __always_inline int atomic_sub_return(int i, atomic_t *v) +{ +return arch_atomic_sub_return (i, v); +} + +static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_return (i, v); +} + +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ +return arch_atomic_fetch_add (i, v); +} + +static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_add (i, v); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ +return arch_atomic_fetch_sub (i, v); +} + +static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_sub (i, v); +} + +static __always_inline int atomic_fetch_and(int i, atomic_t *v) +{ +return arch_atomic_fetch_and (i, v); +} + +static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_and (i, v); +} + +static __always_inline int atomic_fetch_or(int i, atomic_t *v) +{ +return arch_atomic_fetch_or (i, v); +} + +static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_or (i, v); +} + +static __always_inline int atomic_fetch_xor(int i, atomic_t *v) +{ +return arch_atomic_fetch_xor (i, v); +} + +static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_xor (i, v); +} + +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +{ +return arch_atomic_sub_and_test (i, v); +} + +static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_and_test (i, v); +} + +static __always_inline bool atomic_add_negative(int i, atomic_t *v) +{ +return arch_atomic_add_negative (i, v); +} + +static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_negative (i, v); +} + +static __always_inline unsigned long +cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new,int size) +{ +switch (size) { +case 1 : +return arch_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_cmpxchg ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_cmpxchg ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_cmpxchg ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define cmpxchg (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg_size((ptr), (unsigned long)(old), \ + (unsigned long)(new), sizeof(*(ptr)))); \ +}) + +static __always_inline unsigned long +sync_cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new, +int size) +{ +switch (size) { +case 1 : +return arch_sync_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_sync_cmpxchg ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_sync_cmpxchg ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_sync_cmpxchg ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define sync_cmpxchg (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))sync_cmpxchg_size((ptr), \ + (unsigned long)(old), (unsigned long)(new), \ + sizeof(*(ptr)))); \ +}) + +static __always_inline unsigned long +cmpxchg_local_size (volatile void *ptr,unsigned long old,unsigned long new, +int size) +{ +switch (size) { +case 1 : +return arch_cmpxchg_local ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_cmpxchg_local ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_cmpxchg_local ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_cmpxchg_local ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define cmpxchg_local (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg_local_size((ptr), \ + (unsigned long)(old), (unsigned long)(new), \ + sizeof(*(ptr)))); \ +}) + +static __always_inline u64 +cmpxchg64_size (volatile u64 *ptr,u64 old,u64 new) +{ +return arch_cmpxchg64 (ptr, old, new); +} + +#define cmpxchg64 (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg64_size((ptr), (u64)(old), \ + (u64)(new))); \ +}) + +static __always_inline u64 +cmpxchg64_local_size (volatile u64 *ptr,u64 old,u64 new) +{ +return arch_cmpxchg64_local (ptr, old, new); +} + +#define cmpxchg64_local (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg64_local_size((ptr), (u64)(old), \ + (u64)(new))); \ +}) + +#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double_local((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
Dmitry Vyukov
reviewerPATCH v4 4/7 x86: switch atomic.h to use atomic-instrumented.h
In reply to Dmitry VyukovAdd arch_ prefix to all atomic operations and include <asm-generic/atomic-instrumented.h>. This will allow to add KASAN instrumentation to all atomic ops.
---
Changes since v1:
- reverted unnecessary change in __raw_try_cmpxchg()
- reverted s/try_cmpxchg/arch_try_cmpxchg/ change try_cmpxchg is x86 implementation detail
Changes since v3:
- drop comment in arch_atomic_set()
--- arch/x86/include/asm/atomic.h | 102 ++++++++++++++++++----------------- arch/x86/include/asm/atomic64_32.h | 106 ++++++++++++++++++------------------ arch/x86/include/asm/atomic64_64.h | 108 ++++++++++++++++++------------------- arch/x86/include/asm/cmpxchg.h | 12 ++--- arch/x86/include/asm/cmpxchg_32.h | 8 +-- arch/x86/include/asm/cmpxchg_64.h | 4 +- 6 files changed, 172 insertions(+), 168 deletions(-)
arch/x86/include/asm/atomic.h +52 -50
@@ -16,36 +16,36 @@#define ATOMIC_INIT (i) { (i) }/** -* atomic_read - read atomic variable +* arch_atomic_read - read atomic variable * @v: pointer of type atomic_t * * Atomically reads the value of @v. */ -static __always_inline int atomic_read(const atomic_t *v) +static __always_inline int arch_atomic_read(const atomic_t *v) {return READ_ONCE ((v)->counter); }/** -* atomic_set - set atomic variable +* arch_atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value * * Atomically sets the value of @v to @i. */ -static __always_inline void atomic_set(atomic_t *v, int i) +static __always_inline void arch_atomic_set(atomic_t *v, int i) {WRITE_ONCE (v->counter, i); }/** -* atomic_add - add integer to atomic variable +* arch_atomic_add - add integer to atomic variable * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v. */ -static __always_inline void atomic_add(int i, atomic_t *v) +static __always_inline void arch_atomic_add(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "addl %1,%0" : "+m" (v->counter)
@@ -53,13 +53,13 @@ static __always_inline void atomic_add(int i, atomic_t *v) }/** -* atomic_sub - subtract integer from atomic variable +* arch_atomic_sub - subtract integer from atomic variable * @i: integer value to subtract * @v: pointer of type atomic_t * * Atomically subtracts @i from @v. */ -static __always_inline void atomic_sub(int i, atomic_t *v) +static __always_inline void arch_atomic_sub(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "subl %1,%0" : "+m" (v->counter)
@@ -67,7 +67,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) }/** -* atomic_sub_and_test - subtract value from variable and test result +* arch_atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract * @v: pointer of type atomic_t *
@@ -75,63 +75,63 @@ static __always_inline void atomic_sub(int i, atomic_t *v)* true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "subl" , v->counter,"er" , i,"%0" , e); }/** -* atomic_inc - increment atomic variable +* arch_atomic_inc - increment atomic variable * @v: pointer of type atomic_t * * Atomically increments @v by 1. */ -static __always_inline void atomic_inc(atomic_t *v) +static __always_inline void arch_atomic_inc(atomic_t *v) { asmvolatile (LOCK_PREFIX "incl %0" :"+m" (v->counter)); }/** -* atomic_dec - decrement atomic variable +* arch_atomic_dec - decrement atomic variable * @v: pointer of type atomic_t * * Atomically decrements @v by 1. */ -static __always_inline void atomic_dec(atomic_t *v) +static __always_inline void arch_atomic_dec(atomic_t *v) { asmvolatile (LOCK_PREFIX "decl %0" :"+m" (v->counter)); }/** -* atomic_dec_and_test - decrement and test +* arch_atomic_dec_and_test - decrement and test * @v: pointer of type atomic_t * * Atomically decrements @v by 1 and * returns true if the result is 0, or false for all other * cases. */ -static __always_inline bool atomic_dec_and_test(atomic_t *v) +static __always_inline bool arch_atomic_dec_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "decl" , v->counter,"%0" , e); }/** -* atomic_inc_and_test - increment and test +* arch_atomic_inc_and_test - increment and test * @v: pointer of type atomic_t * * Atomically increments @v by 1 * and returns true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_inc_and_test(atomic_t *v) +static __always_inline bool arch_atomic_inc_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "incl" , v->counter,"%0" , e); }/** -* atomic_add_negative - add and test if negative +* arch_atomic_add_negative - add and test if negative * @i: integer value to add * @v: pointer of type atomic_t *
@@ -139,65 +139,65 @@ static __always_inline bool atomic_inc_and_test(atomic_t *v)* if the result is negative, or false when * result is greater than or equal to zero. */ -static __always_inline bool atomic_add_negative(int i, atomic_t *v) +static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "addl" , v->counter,"er" , i,"%0" , s); }/** -* atomic_add_return - add integer and return +* arch_atomic_add_return - add integer and return * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns @i + @v */ -static __always_inline int atomic_add_return(int i, atomic_t *v) +static __always_inline int arch_atomic_add_return(int i, atomic_t *v) {return i +xadd (&v->counter, i); }/** -* atomic_sub_return - subtract integer and return +* arch_atomic_sub_return - subtract integer and return * @v: pointer of type atomic_t * @i: integer value to subtract * * Atomically subtracts @i from @v and returns @v - @i */ -static __always_inline int atomic_sub_return(int i, atomic_t *v) +static __always_inline int arch_atomic_sub_return(int i, atomic_t *v) { -return atomic_add_return (-i, v); +return arch_atomic_add_return (-i, v); } -#define atomic_inc_return (v) (atomic_add_return(1, v)) -#define atomic_dec_return (v) (atomic_sub_return(1, v)) +#define arch_atomic_inc_return (v) (arch_atomic_add_return(1, v)) +#define arch_atomic_dec_return (v) (arch_atomic_sub_return(1, v)) -static __always_inline int atomic_fetch_add(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v) {return xadd (&v->counter, i); } -static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_sub(int i, atomic_t *v) {return xadd (&v->counter, -i); } -static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) { -return cmpxchg (&v->counter, old, new); +return arch_cmpxchg (&v->counter, old, new); } -#define atomic_try_cmpxchg atomic_try_cmpxchg -static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg +static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new) {return try_cmpxchg (&v->counter, old, new); } -static inline int atomic_xchg (atomic_t *v,int new) +static inline int arch_atomic_xchg (atomic_t *v,int new) {return xchg (&v->counter, new); } -static inline void atomic_and (int i,atomic_t *v) +static inline void arch_atomic_and (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "andl %1,%0" : "+m" (v->counter)
@@ -205,16 +205,16 @@ static inline void atomic_and(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_and (int i,atomic_t *v) +static inline int arch_atomic_fetch_and (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v);do { - }while (!atomic_try_cmpxchg (v, &val, val & i)); + }while (!arch_atomic_try_cmpxchg (v, &val, val & i));return val; } -static inline void atomic_or (int i,atomic_t *v) +static inline void arch_atomic_or (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "orl %1,%0" : "+m" (v->counter)
@@ -222,17 +222,17 @@ static inline void atomic_or(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_or (int i,atomic_t *v) +static inline int arch_atomic_fetch_or (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v);do { - }while (!atomic_try_cmpxchg (v, &val, val | i)); + }while (!arch_atomic_try_cmpxchg (v, &val, val | i));return val; } -static inline void atomic_xor (int i,atomic_t *v) +static inline void arch_atomic_xor (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "xorl %1,%0" : "+m" (v->counter)
@@ -240,17 +240,17 @@ static inline void atomic_xor(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_xor (int i,atomic_t *v) +static inline int arch_atomic_fetch_xor (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v);do { - }while (!atomic_try_cmpxchg (v, &val, val ^ i)); + }while (!arch_atomic_try_cmpxchg (v, &val, val ^ i));return val; }/** -* __atomic_add_unless - add unless the number is already a given value +* __arch_atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t * @a: the amount to add to v... * @u: ...unless v is equal to u.
@@ -258,13 +258,13 @@ static inline int atomic_fetch_xor(int i, atomic_t *v)* Atomically adds @a to @v, so long as @v was not already @u. * Returns the old value of @v. */ -static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +static __always_inline int __arch_atomic_add_unless(atomic_t *v, int a, int u) { -int c =atomic_read (v); +int c =arch_atomic_read (v);do {if (unlikely (c == u))break ; - }while (!atomic_try_cmpxchg (v, &c, c + a)); + }while (!arch_atomic_try_cmpxchg (v, &c, c + a));return c; }
@@ -274,4 +274,6 @@ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)# include <asm/atomic64_64.h> #endif +#include <asm-generic/atomic-instrumented.h> +#endif /* _ASM_X86_ATOMIC_H */
arch/x86/include/asm/atomic64_32.h +54 -52
332 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +54 -54
314 lines not on this page · raw message
arch/x86/include/asm/cmpxchg.h +6 -6
@@ -144,13 +144,13 @@ extern void __add_wrong_size(void)# include <asm/cmpxchg_64.h> #endif -#define cmpxchg (ptr, old, new) \ +#define arch_cmpxchg (ptr, old, new) \ __cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define sync_cmpxchg (ptr, old, new) \ +#define arch_sync_cmpxchg (ptr, old, new) \ __sync_cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define cmpxchg_local (ptr, old, new) \ +#define arch_cmpxchg_local (ptr, old, new) \ __cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
@@ -220,7 +220,7 @@ extern void __add_wrong_size(void)#define __try_cmpxchg (ptr, pold, new, size) \ __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) -#define try_cmpxchg (ptr, pold, new) \ +#define try_cmpxchg (ptr, pold, new) \ __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))/*
@@ -249,10 +249,10 @@ extern void __add_wrong_size(void) __ret; \ }) -#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2) -#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(, p1, p2, o1, o2, n1, n2)#endif /* ASM_X86_CMPXCHG_H */
arch/x86/include/asm/cmpxchg_32.h +4 -4
@@ -35,10 +35,10 @@ static inline void set_64bit(volatile u64 *ptr, u64 value) }#ifdef CONFIG_X86_CMPXCHG64 -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ (unsigned long long)(n))) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ (unsigned long long)(n)))#endif
@@ -75,7 +75,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)* to simulate the cmpxchg8b on the 80386 and 80486 CPU. */ -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
@@ -92,7 +92,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new) __ret; }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
arch/x86/include/asm/cmpxchg_64.h +2 -2
@@ -6,13 +6,13 @@ static inline void set_64bit(volatile u64 *ptr, u64 val) *ptr = val; } -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg((ptr), (o), (n)); \ }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Dmitry Vyukov
reviewerPATCH v4 5/7 kasan: allow kasan_check_read/write() to accept pointers to volatiles
In reply to Dmitry VyukovCurrently kasan_check_read/write() accept 'const void*', make them accept 'const volatile void*'. This is required for instrumentation of atomic operations and there is just no reason to not allow that.
--- include/linux/kasan-checks.h | 10 ++++++---- mm/kasan/kasan.c | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-)
include/linux/kasan-checks.h +6 -4
@@ -2,11 +2,13 @@#define _LINUX_KASAN_CHECKS_H#ifdef CONFIG_KASAN -void kasan_check_read (const void *p,unsigned int size); -void kasan_check_write (const void *p,unsigned int size); +void kasan_check_read (const volatile void *p,unsigned int size); +void kasan_check_write (const volatile void *p,unsigned int size);#else -static inline void kasan_check_read (const void *p,unsigned int size) { } -static inline void kasan_check_write (const void *p,unsigned int size) { } +static inline void kasan_check_read (const volatile void *p,unsigned int size) +{ } +static inline void kasan_check_write (const volatile void *p,unsigned int size) +{ }#endif #endif
mm/kasan/kasan.c +2 -2
@@ -333,13 +333,13 @@ static void check_memory_region(unsigned long addr,check_memory_region_inline (addr, size, write, ret_ip); } -void kasan_check_read (const void *p,unsigned int size) +void kasan_check_read (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, false, _RET_IP_); }EXPORT_SYMBOL (kasan_check_read); -void kasan_check_write (const void *p,unsigned int size) +void kasan_check_write (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, true, _RET_IP_); }
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4 5/7] kasan: allow kasan_check_read/write() to accept pointers to volatiles
Quoted 4 lines · Dmitry Vyukov
Currently kasan_check_read/write() accept 'const void*', make them accept 'const volatile void*'. This is required for instrumentation of atomic operations and there is just no reason to not allow that.
Quoted 11 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Thomas Gleixner <[email protected]>Cc "H. Peter Anvin" <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Andrew Morton <[email protected]>
Looks sane to me, and I can confirm this doesn't advervsely affect arm64. FWIW:
Mark.
Quoted 50 lines
--- include/linux/kasan-checks.h | 10 ++++++---- mm/kasan/kasan.c | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-)include/linux/kasan-checks.h +6
-4@@ -2,11 +2,13 @@#define _LINUX_KASAN_CHECKS_H#ifdef CONFIG_KASAN -void kasan_check_read (const void *p,unsigned int size); -void kasan_check_write (const void *p,unsigned int size); +void kasan_check_read (const volatile void *p,unsigned int size); +void kasan_check_write (const volatile void *p,unsigned int size);#else -static inline void kasan_check_read (const void *p,unsigned int size) { } -static inline void kasan_check_write (const void *p,unsigned int size) { } +static inline void kasan_check_read (const volatile void *p,unsigned int size) +{ } +static inline void kasan_check_write (const volatile void *p,unsigned int size) +{ }#endif #endif mm/kasan/kasan.c +2
-2@@ -333,13 +333,13 @@ static void check_memory_region(unsigned long addr,check_memory_region_inline (addr, size, write, ret_ip); } -void kasan_check_read (const void *p,unsigned int size) +void kasan_check_read (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, false, _RET_IP_); }EXPORT_SYMBOL (kasan_check_read); -void kasan_check_write (const void *p,unsigned int size) +void kasan_check_write (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, true, _RET_IP_); }Signature · 1 line
2.13.1.518.g3df882009-goog
Dmitry Vyukov
reviewerRe: [PATCH v4 5/7] kasan: allow kasan_check_read/write() to accept pointers to volatiles
Quoted 17 lines · Mark Rutland
Quoted 4 lines · Dmitry Vyukov
Currently kasan_check_read/write() accept 'const void*', make them accept 'const volatile void*'. This is required for instrumentation of atomic operations and there is just no reason to not allow that.
Quoted 11 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Thomas Gleixner <[email protected]>Cc "H. Peter Anvin" <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Andrew Morton <[email protected]>
Quoted 6 lines
Looks sane to me, and I can confirm this doesn't advervsely affect arm64. FWIW:
Acked-by Mark Rutland <[email protected]>Mark.
Great! Thanks for testing.
Ingo, what are your thoughts? Are you taking this to locking tree? When?
Quoted 42 lines
Quoted 42 lines
--- include/linux/kasan-checks.h | 10 ++++++---- mm/kasan/kasan.c | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-)include/linux/kasan-checks.h +6
-4@@ -2,11 +2,13 @@#define _LINUX_KASAN_CHECKS_H#ifdef CONFIG_KASAN -void kasan_check_read (const void *p,unsigned int size); -void kasan_check_write (const void *p,unsigned int size); +void kasan_check_read (const volatile void *p,unsigned int size); +void kasan_check_write (const volatile void *p,unsigned int size);#else -static inline void kasan_check_read (const void *p,unsigned int size) { } -static inline void kasan_check_write (const void *p,unsigned int size) { } +static inline void kasan_check_read (const volatile void *p,unsigned int size) +{ } +static inline void kasan_check_write (const volatile void *p,unsigned int size) +{ }#endif #endif mm/kasan/kasan.c +1
-1@@ -333,13 +333,13 @@ static void check_memory_region(unsigned long addr,check_memory_region_inline (addr, size, write, ret_ip); } -void kasan_check_read (const void *p,unsigned int size) +void kasan_check_read (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, false, _RET_IP_); }EXPORT_SYMBOL (kasan_check_read);
Quoted 8 lines
Quoted 8 lines
mm/kasan/kasan.c +1
-2-void kasan_check_write (const void *p,unsigned int size) +void kasan_check_write (const volatile void *p,unsigned int size) {check_memory_region ((unsigned long )p, size, true, _RET_IP_); } --2.13.1.518.g3df882009-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4 5/7] kasan: allow kasan_check_read/write() to accept pointers to volatiles
Quoted 21 lines · Dmitry Vyukov
Quoted 20 lines · Mark Rutland
Quoted 4 lines · Dmitry Vyukov
Currently kasan_check_read/write() accept 'const void*', make them accept 'const volatile void*'. This is required for instrumentation of atomic operations and there is just no reason to not allow that.
Quoted 11 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Thomas Gleixner <[email protected]>Cc "H. Peter Anvin" <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Andrew Morton <[email protected]>Looks sane to me, and I can confirm this doesn't advervsely affect arm64. FWIW:
Quoted 8 lines
Quoted 3 lines
Acked-by Mark Rutland <[email protected]>Mark.
Great! Thanks for testing.
Ingo, what are your thoughts? Are you taking this to locking tree? When?
Yeah, it all looks pretty clean to me too. I've applied the first three patches to the locking tree, but did some minor stylistic cleanups to the first patch to harmonize the style of the code - which made the later patches not apply cleanly.
Mind sending the remaining patches against the locking tree, tip:locking/core? (Please also add in all the acks you got.)
This should also give people (Peter, Linus?) a last minute chance to object to my suggestion of increasing the linecount in patch #1:
0f2376eb0ff8: locking/atomic/x86: Un-macro-ify atomic ops implementation
arch/x86/include/asm/atomic.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++----------------------- arch/x86/include/asm/atomic64_32.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ arch/x86/include/asm/atomic64_64.h | 67 ++++++++++++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 147 insertions(+), 70 deletions(-)
... to me the end result looks much more readable despite the +70 lines of code, but if anyone feels strongly about this please holler!
Thanks,
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Dmitry Vyukov
reviewerRe: [PATCH v4 5/7] kasan: allow kasan_check_read/write() to accept pointers to volatiles
Quoted 31 lines · Ingo Molnar
Quoted 28 lines · Dmitry Vyukov
Quoted 17 lines · Mark Rutland
Quoted 4 lines · Dmitry Vyukov
Currently kasan_check_read/write() accept 'const void*', make them accept 'const volatile void*'. This is required for instrumentation of atomic operations and there is just no reason to not allow that.
Quoted 11 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Thomas Gleixner <[email protected]>Cc "H. Peter Anvin" <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Andrew Morton <[email protected]>Quoted 6 lines
Looks sane to me, and I can confirm this doesn't advervsely affect arm64. FWIW:
Acked-by Mark Rutland <[email protected]>Mark.
Great! Thanks for testing.
Quoted 8 lines
Quoted 1 line
Ingo, what are your thoughts? Are you taking this to locking tree? When?
Yeah, it all looks pretty clean to me too. I've applied the first three patches to the locking tree, but did some minor stylistic cleanups to the first patch to harmonize the style of the code - which made the later patches not apply cleanly.
Mind sending the remaining patches against the locking tree, tip:locking/core? (Please also add in all the acks you got.)
Mailed v5 rebased on tip:locking/core (now only 4 patches). Added Acked/Reviewed-By that I got.
Quoted 10 lines
This should also give people (Peter, Linus?) a last minute chance to object to my suggestion of increasing the linecount in patch #1:
0f2376eb0ff8: locking/atomic/x86: Un-macro-ify atomic ops implementationarch/x86/include/asm/atomic.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++----------------------- arch/x86/include/asm/atomic64_32.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ arch/x86/include/asm/atomic64_64.h | 67 ++++++++++++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 147 insertions(+), 70 deletions(-)
Quoted 6 lines
... to me the end result looks much more readable despite the +70 lines of code, but if anyone feels strongly about this please holler!
Thanks,
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Dmitry Vyukov
reviewerPATCH v4 6/7 asm-generic: add KASAN instrumentation to atomic operations
In reply to Dmitry VyukovKASAN 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.
--- include/asm-generic/atomic-instrumented.h | 76 +++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)
include/asm-generic/atomic-instrumented.h +72 -4
@@ -1,43 +1,53 @@#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H +#include <linux/kasan-checks.h> + static __always_inline int atomic_read(const atomic_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic_read (v); } static __always_inline s64 atomic64_read(const atomic64_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic64_read (v); } static __always_inline void atomic_set(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));arch_atomic_set (v, i); } static __always_inline void atomic64_set(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));arch_atomic64_set (v, i); } static __always_inline int atomic_xchg(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));return arch_atomic_xchg (v, i); } static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_xchg (v, i); } static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { +kasan_check_write (v,sizeof (*v));return arch_atomic_cmpxchg (v, old, new); } static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_cmpxchg (v, old, new); }
@@ -45,6 +55,8 @@ static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)#define atomic_try_cmpxchg atomic_try_cmpxchg static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic_try_cmpxchg (v, old, new); }#endif
@@ -53,254 +65,310 @@ static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new)#define atomic64_try_cmpxchg atomic64_try_cmpxchg static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic64_try_cmpxchg (v, old, new); }#endif static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) { +kasan_check_write (v,sizeof (*v));return __arch_atomic_add_unless (v, a, u); } static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_unless (v, a, u); } static __always_inline void atomic_inc(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_inc (v); } static __always_inline void atomic64_inc(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_inc (v); } static __always_inline void atomic_dec(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_dec (v); } static __always_inline void atomic64_dec(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_dec (v); } static __always_inline void atomic_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_add (i, v); } static __always_inline void atomic64_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_add (i, v); } static __always_inline void atomic_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_sub (i, v); } static __always_inline void atomic64_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_sub (i, v); } static __always_inline void atomic_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_and (i, v); } static __always_inline void atomic64_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_and (i, v); } static __always_inline void atomic_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_or (i, v); } static __always_inline void atomic64_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_or (i, v); } static __always_inline void atomic_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_xor (i, v); } static __always_inline void atomic64_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_xor (i, v); } static __always_inline int atomic_inc_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_return (v); } static __always_inline s64 atomic64_inc_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_return (v); } static __always_inline int atomic_dec_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_return (v); } static __always_inline s64 atomic64_dec_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_return (v); } static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_not_zero (v); } static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_if_positive (v); } static __always_inline bool atomic_dec_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_and_test (v); } static __always_inline bool atomic64_dec_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_and_test (v); } static __always_inline bool atomic_inc_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_and_test (v); } static __always_inline bool atomic64_inc_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_and_test (v); } static __always_inline int atomic_add_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_return (i, v); } static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_return (i, v); } static __always_inline int atomic_sub_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_return (i, v); } static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_return (i, v); } static __always_inline int atomic_fetch_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_add (i, v); } static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_add (i, v); } static __always_inline int atomic_fetch_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_sub (i, v); } static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_sub (i, v); } static __always_inline int atomic_fetch_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_and (i, v); } static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_and (i, v); } static __always_inline int atomic_fetch_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_or (i, v); } static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_or (i, v); } static __always_inline int atomic_fetch_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_xor (i, v); } static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_xor (i, v); } static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_and_test (i, v); } static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_and_test (i, v); } static __always_inline bool atomic_add_negative(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_negative (i, v); } static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_negative (i, v); }#define cmpxchg (ptr, old, new) \ ({ \ + __typeof__(ptr) ___ptr = (ptr); \ + kasan_check_write(___ptr, sizeof(*___ptr)); \ arch_cmpxchg((ptr), (old), (new)); \ })#define sync_cmpxchg (ptr, old, new) \ ({ \ - arch_sync_cmpxchg((ptr), (old), (new)); \ + __typeof__(ptr) ___ptr = (ptr); \ + kasan_check_write(___ptr, sizeof(*___ptr)); \ + arch_sync_cmpxchg(___ptr, (old), (new)); \ })#define cmpxchg_local (ptr, old, new) \ ({ \ - arch_cmpxchg_local((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg_local(____ptr, (old), (new)); \ })#define cmpxchg64 (ptr, old, new) \ ({ \ - arch_cmpxchg64((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg64(____ptr, (old), (new)); \ })#define cmpxchg64_local (ptr, old, new) \ ({ \ - arch_cmpxchg64_local((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg64_local(____ptr, (old), (new)); \ })#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4 6/7] asm-generic: add KASAN instrumentation to atomic operations
Quoted 8 lines · Dmitry Vyukov
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.
Quoted 11 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Will Deacon <[email protected]>,Cc Andrew Morton <[email protected]>,Cc Andrey Ryabinin <[email protected]>,Cc Ingo Molnar <[email protected]>,
FWIW:
Mark.
Quoted 389 lines
--- include/asm-generic/atomic-instrumented.h | 76 +++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)include/asm-generic/atomic-instrumented.h +72
-4@@ -1,43 +1,53 @@#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H +#include <linux/kasan-checks.h> + static __always_inline int atomic_read(const atomic_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic_read (v); } static __always_inline s64 atomic64_read(const atomic64_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic64_read (v); } static __always_inline void atomic_set(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));arch_atomic_set (v, i); } static __always_inline void atomic64_set(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));arch_atomic64_set (v, i); } static __always_inline int atomic_xchg(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));return arch_atomic_xchg (v, i); } static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_xchg (v, i); } static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { +kasan_check_write (v,sizeof (*v));return arch_atomic_cmpxchg (v, old, new); } static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_cmpxchg (v, old, new); }@@ -45,6 +55,8 @@ static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)#define atomic_try_cmpxchg atomic_try_cmpxchg static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic_try_cmpxchg (v, old, new); }#endif @@ -53,254 +65,310 @@ static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new)#define atomic64_try_cmpxchg atomic64_try_cmpxchg static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic64_try_cmpxchg (v, old, new); }#endif static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) { +kasan_check_write (v,sizeof (*v));return __arch_atomic_add_unless (v, a, u); } static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_unless (v, a, u); } static __always_inline void atomic_inc(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_inc (v); } static __always_inline void atomic64_inc(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_inc (v); } static __always_inline void atomic_dec(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_dec (v); } static __always_inline void atomic64_dec(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_dec (v); } static __always_inline void atomic_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_add (i, v); } static __always_inline void atomic64_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_add (i, v); } static __always_inline void atomic_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_sub (i, v); } static __always_inline void atomic64_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_sub (i, v); } static __always_inline void atomic_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_and (i, v); } static __always_inline void atomic64_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_and (i, v); } static __always_inline void atomic_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_or (i, v); } static __always_inline void atomic64_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_or (i, v); } static __always_inline void atomic_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_xor (i, v); } static __always_inline void atomic64_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_xor (i, v); } static __always_inline int atomic_inc_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_return (v); } static __always_inline s64 atomic64_inc_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_return (v); } static __always_inline int atomic_dec_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_return (v); } static __always_inline s64 atomic64_dec_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_return (v); } static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_not_zero (v); } static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_if_positive (v); } static __always_inline bool atomic_dec_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_and_test (v); } static __always_inline bool atomic64_dec_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_and_test (v); } static __always_inline bool atomic_inc_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_and_test (v); } static __always_inline bool atomic64_inc_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_and_test (v); } static __always_inline int atomic_add_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_return (i, v); } static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_return (i, v); } static __always_inline int atomic_sub_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_return (i, v); } static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_return (i, v); } static __always_inline int atomic_fetch_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_add (i, v); } static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_add (i, v); } static __always_inline int atomic_fetch_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_sub (i, v); } static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_sub (i, v); } static __always_inline int atomic_fetch_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_and (i, v); } static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_and (i, v); } static __always_inline int atomic_fetch_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_or (i, v); } static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_or (i, v); } static __always_inline int atomic_fetch_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_xor (i, v); } static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_xor (i, v); } static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_and_test (i, v); } static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_and_test (i, v); } static __always_inline bool atomic_add_negative(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_negative (i, v); } static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_negative (i, v); }#define cmpxchg (ptr, old, new) \ ({ \ + __typeof__(ptr) ___ptr = (ptr); \ + kasan_check_write(___ptr, sizeof(*___ptr)); \ arch_cmpxchg((ptr), (old), (new)); \ })#define sync_cmpxchg (ptr, old, new) \ ({ \ - arch_sync_cmpxchg((ptr), (old), (new)); \ + __typeof__(ptr) ___ptr = (ptr); \ + kasan_check_write(___ptr, sizeof(*___ptr)); \ + arch_sync_cmpxchg(___ptr, (old), (new)); \ })#define cmpxchg_local (ptr, old, new) \ ({ \ - arch_cmpxchg_local((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg_local(____ptr, (old), (new)); \ })#define cmpxchg64 (ptr, old, new) \ ({ \ - arch_cmpxchg64((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg64(____ptr, (old), (new)); \ })#define cmpxchg64_local (ptr, old, new) \ ({ \ - arch_cmpxchg64_local((ptr), (old), (new)); \ + __typeof__(ptr) ____ptr = (ptr); \ + kasan_check_write(____ptr, sizeof(*____ptr)); \ + arch_cmpxchg64_local(____ptr, (old), (new)); \ })#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \Signature · 1 line
2.13.1.518.g3df882009-goog
Dmitry Vyukov
reviewerPATCH v4 7/7 asm-generic, x86: add comments for atomic instrumentation
In reply to Dmitry VyukovThe comments are factored out from the code changes to make them easier to read. Add them separately to explain some non-obvious aspects.
---
Changes since v3:
- rephrase comment in arch_atomic_read()
--- arch/x86/include/asm/atomic.h | 4 ++++ include/asm-generic/atomic-instrumented.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
arch/x86/include/asm/atomic.h +4 -0
@@ -23,6 +23,10 @@*/ static __always_inline int arch_atomic_read(const atomic_t *v) { +/* +* Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here, +* it's non-inlined function that increases binary size and stack usage. +*/ return READ_ONCE ((v)->counter); }
include/asm-generic/atomic-instrumented.h +30 -0
@@ -1,3 +1,15 @@ +/* +* This file provides wrappers with KASAN instrumentation for atomic operations. +* To use this functionality an arch's atomic.h file needs to define all +* atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include +* this file at the end. This file provides atomic_read() that forwards to +* arch_atomic_read() for actual atomic operation. +* Note: if an arch atomic operation is implemented by means of other atomic +* operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use +* arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid +* double instrumentation. +*/ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H
@@ -336,6 +348,15 @@ static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v)return arch_atomic64_add_negative (i, v); } +/* +* In the following macros we need to be careful to not clash with arch_ macros. +* arch_xchg() can be defined as an extended statement expression as well, +* if we define a __ptr variable, and arch_xchg() also defines __ptr variable, +* and we pass __ptr as an argument to arch_xchg(), it will use own __ptr +* instead of ours. This leads to unpleasant crashes. To avoid the problem +* the following macros declare variables with lots of underscores. +*/ +#define cmpxchg (ptr, old, new) \ ({ \ __typeof__(ptr) ___ptr = (ptr); \
@@ -371,6 +392,15 @@ static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v)arch_cmpxchg64_local (____ptr, (old), (new)); \ }) +/* +* Originally we had the following code here: +* __typeof__(p1) ____p1 = (p1); +* kasan_check_write(____p1, 2 * sizeof(*____p1)); +* arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); +* But it leads to compilation failures (see gcc issue 72873). +* So for now it's left non-instrumented. +* There are few callers of cmpxchg_double(), so it's not critical. +*/ #define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ ({ \ arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \
Signature · 7 lines
2.13.1.518.g3df882009-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4 7/7] asm-generic, x86: add comments for atomic instrumentation
Quoted 4 lines · Dmitry Vyukov
The comments are factored out from the code changes to make them easier to read. Add them separately to explain some non-obvious aspects.
Quoted 12 lines
Signed-off-by Dmitry Vyukov <[email protected]>Cc Mark Rutland <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Will Deacon <[email protected]>Cc Andrew Morton <[email protected]>Cc Andrey Ryabinin <[email protected]>Cc Ingo Molnar <[email protected]>
The comments look sane to me.
When arm64 support comes round, it would be nice to instrument cmpxchg_double(), since I think we're not affected by the compiler issue. We can solve that as and when.
FWIW:
Mark.
Quoted 79 lines
---
Changes since v3:
- rephrase comment inarch_atomic_read()--- arch/x86/include/asm/atomic.h | 4 ++++ include/asm-generic/atomic-instrumented.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)arch/x86/include/asm/atomic.h +4
-0@@ -23,6 +23,10 @@*/ static __always_inline int arch_atomic_read(const atomic_t *v) { +/* +* Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here, +* it's non-inlined function that increases binary size and stack usage. +*/ return READ_ONCE ((v)->counter); }include/asm-generic/atomic-instrumented.h +30
-0@@ -1,3 +1,15 @@ +/* +* This file provides wrappers with KASAN instrumentation for atomic operations. +* To use this functionality an arch's atomic.h file needs to define all +* atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include +* this file at the end. This file provides atomic_read() that forwards to +* arch_atomic_read() for actual atomic operation. +* Note: if an arch atomic operation is implemented by means of other atomic +* operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use +* arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid +* double instrumentation. +*/ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H@@ -336,6 +348,15 @@ static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v)return arch_atomic64_add_negative (i, v); } +/* +* In the following macros we need to be careful to not clash with arch_ macros. +* arch_xchg() can be defined as an extended statement expression as well, +* if we define a __ptr variable, and arch_xchg() also defines __ptr variable, +* and we pass __ptr as an argument to arch_xchg(), it will use own __ptr +* instead of ours. This leads to unpleasant crashes. To avoid the problem +* the following macros declare variables with lots of underscores. +*/ +#define cmpxchg (ptr, old, new) \ ({ \ __typeof__(ptr) ___ptr = (ptr); \@@ -371,6 +392,15 @@ static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v)arch_cmpxchg64_local (____ptr, (old), (new)); \ }) +/* +* Originally we had the following code here: +* __typeof__(p1) ____p1 = (p1); +* kasan_check_write(____p1, 2 * sizeof(*____p1)); +* arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); +* But it leads to compilation failures (see gcc issue 72873). +* So for now it's left non-instrumented. +* There are few callers of cmpxchg_double(), so it's not critical. +*/ #define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ ({ \ arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \Signature · 1 line
2.13.1.518.g3df882009-goog
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Dmitry Vyukov
reviewerv6 cover x86, kasan: add KASAN checks to atomic operations
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
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 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: 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 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 __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
Changes since v1:
- dropped "x86: remove unused atomic_inc_short()" patch it is mailed separately
- rebased on top of tip/locking/core head
- other changes noted within individual patches
Changes since v2:
- rebased on top of tip/locking/core head
- dropped a pervasive "x86: use long long for 64-bit atomic ops" commit, instead use s64 type in wrappers
- added "x86: use s64* for old arg of atomic64_try_cmpxchg()" commit
Changes since v3 are noted in individual commits.
Changes since v4:
- rebased on tip/locking/core HEAD
Changes since v5:
- rework cmpxchg* implementations so that we have less code in macros and more code in functions
Tested:
- build/boot x86_64 defconfig
- build/boot x86_64 defconfig+KASAN
- build i686/powerpc defconfig
Dmitry Vyukov (4):
locking/atomic: Add asm-generic/atomic-instrumented.h
x86: switch atomic.h to use atomic-instrumented.h
asm-generic: add KASAN instrumentation to atomic operations asm-generic, x86: add comments for atomic instrumentation
arch/x86/include/asm/atomic.h | 106 +++---- arch/x86/include/asm/atomic64_32.h | 106 +++---- arch/x86/include/asm/atomic64_64.h | 108 +++---- arch/x86/include/asm/cmpxchg.h | 12 +- arch/x86/include/asm/cmpxchg_32.h | 8 +- arch/x86/include/asm/cmpxchg_64.h | 4 +- include/asm-generic/atomic-instrumented.h | 476 ++++++++++++++++++++++++++++++ 7 files changed, 652 insertions(+), 168 deletions(-) create mode 100644 include/asm-generic/atomic-instrumented.h
Signature · 1 line
2.16.0.rc1.238.g530d649a79-goog
Dmitry Vyukov
reviewerPATCH v6 1/4 locking/atomic: Add asm-generic/atomic-instrumented.h
The new header allows to wrap per-arch atomic operations and add common functionality to all of them.
---
Changes since v5:
- rework cmpxchg* implementations so that we have less code in macros and more code in functions.
--- include/asm-generic/atomic-instrumented.h | 393 ++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+)
include/asm-generic/atomic-instrumented.h new file +393 -0
@@ -0,0 +1,393 @@ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H +#define _LINUX_ATOMIC_INSTRUMENTED_H + +#include <linux/build_bug.h> + +static __always_inline int atomic_read(const atomic_t *v) +{ +return arch_atomic_read (v); +} + +static __always_inline s64 atomic64_read(const atomic64_t *v) +{ +return arch_atomic64_read (v); +} + +static __always_inline void atomic_set(atomic_t *v, int i) +{ +arch_atomic_set (v, i); +} + +static __always_inline void atomic64_set(atomic64_t *v, s64 i) +{ +arch_atomic64_set (v, i); +} + +static __always_inline int atomic_xchg(atomic_t *v, int i) +{ +return arch_atomic_xchg (v, i); +} + +static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) +{ +return arch_atomic64_xchg (v, i); +} + +static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +{ +return arch_atomic_cmpxchg (v, old, new); +} + +static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) +{ +return arch_atomic64_cmpxchg (v, old, new); +} + +#ifdef arch_atomic_try_cmpxchg +#define atomic_try_cmpxchg atomic_try_cmpxchg +static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ +return arch_atomic_try_cmpxchg (v, old, new); +} +#endif + +#ifdef arch_atomic64_try_cmpxchg +#define atomic64_try_cmpxchg atomic64_try_cmpxchg +static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ +return arch_atomic64_try_cmpxchg (v, old, new); +} +#endif + +static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ +return __arch_atomic_add_unless (v, a, u); +} + + +static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) +{ +return arch_atomic64_add_unless (v, a, u); +} + +static __always_inline void atomic_inc(atomic_t *v) +{ +arch_atomic_inc (v); +} + +static __always_inline void atomic64_inc(atomic64_t *v) +{ +arch_atomic64_inc (v); +} + +static __always_inline void atomic_dec(atomic_t *v) +{ +arch_atomic_dec (v); +} + +static __always_inline void atomic64_dec(atomic64_t *v) +{ +arch_atomic64_dec (v); +} + +static __always_inline void atomic_add(int i, atomic_t *v) +{ +arch_atomic_add (i, v); +} + +static __always_inline void atomic64_add(s64 i, atomic64_t *v) +{ +arch_atomic64_add (i, v); +} + +static __always_inline void atomic_sub(int i, atomic_t *v) +{ +arch_atomic_sub (i, v); +} + +static __always_inline void atomic64_sub(s64 i, atomic64_t *v) +{ +arch_atomic64_sub (i, v); +} + +static __always_inline void atomic_and(int i, atomic_t *v) +{ +arch_atomic_and (i, v); +} + +static __always_inline void atomic64_and(s64 i, atomic64_t *v) +{ +arch_atomic64_and (i, v); +} + +static __always_inline void atomic_or(int i, atomic_t *v) +{ +arch_atomic_or (i, v); +} + +static __always_inline void atomic64_or(s64 i, atomic64_t *v) +{ +arch_atomic64_or (i, v); +} + +static __always_inline void atomic_xor(int i, atomic_t *v) +{ +arch_atomic_xor (i, v); +} + +static __always_inline void atomic64_xor(s64 i, atomic64_t *v) +{ +arch_atomic64_xor (i, v); +} + +static __always_inline int atomic_inc_return(atomic_t *v) +{ +return arch_atomic_inc_return (v); +} + +static __always_inline s64 atomic64_inc_return(atomic64_t *v) +{ +return arch_atomic64_inc_return (v); +} + +static __always_inline int atomic_dec_return(atomic_t *v) +{ +return arch_atomic_dec_return (v); +} + +static __always_inline s64 atomic64_dec_return(atomic64_t *v) +{ +return arch_atomic64_dec_return (v); +} + +static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) +{ +return arch_atomic64_inc_not_zero (v); +} + +static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) +{ +return arch_atomic64_dec_if_positive (v); +} + +static __always_inline bool atomic_dec_and_test(atomic_t *v) +{ +return arch_atomic_dec_and_test (v); +} + +static __always_inline bool atomic64_dec_and_test(atomic64_t *v) +{ +return arch_atomic64_dec_and_test (v); +} + +static __always_inline bool atomic_inc_and_test(atomic_t *v) +{ +return arch_atomic_inc_and_test (v); +} + +static __always_inline bool atomic64_inc_and_test(atomic64_t *v) +{ +return arch_atomic64_inc_and_test (v); +} + +static __always_inline int atomic_add_return(int i, atomic_t *v) +{ +return arch_atomic_add_return (i, v); +} + +static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_return (i, v); +} + +static __always_inline int atomic_sub_return(int i, atomic_t *v) +{ +return arch_atomic_sub_return (i, v); +} + +static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_return (i, v); +} + +static __always_inline int atomic_fetch_add(int i, atomic_t *v) +{ +return arch_atomic_fetch_add (i, v); +} + +static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_add (i, v); +} + +static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +{ +return arch_atomic_fetch_sub (i, v); +} + +static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_sub (i, v); +} + +static __always_inline int atomic_fetch_and(int i, atomic_t *v) +{ +return arch_atomic_fetch_and (i, v); +} + +static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_and (i, v); +} + +static __always_inline int atomic_fetch_or(int i, atomic_t *v) +{ +return arch_atomic_fetch_or (i, v); +} + +static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_or (i, v); +} + +static __always_inline int atomic_fetch_xor(int i, atomic_t *v) +{ +return arch_atomic_fetch_xor (i, v); +} + +static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) +{ +return arch_atomic64_fetch_xor (i, v); +} + +static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +{ +return arch_atomic_sub_and_test (i, v); +} + +static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) +{ +return arch_atomic64_sub_and_test (i, v); +} + +static __always_inline bool atomic_add_negative(int i, atomic_t *v) +{ +return arch_atomic_add_negative (i, v); +} + +static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) +{ +return arch_atomic64_add_negative (i, v); +} + +static __always_inline unsigned long +cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new,int size) +{ +switch (size) { +case 1 : +return arch_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_cmpxchg ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_cmpxchg ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_cmpxchg ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define cmpxchg (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg_size((ptr), (unsigned long)(old), \ + (unsigned long)(new), sizeof(*(ptr)))); \ +}) + +static __always_inline unsigned long +sync_cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new, +int size) +{ +switch (size) { +case 1 : +return arch_sync_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_sync_cmpxchg ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_sync_cmpxchg ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_sync_cmpxchg ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define sync_cmpxchg (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))sync_cmpxchg_size((ptr), \ + (unsigned long)(old), (unsigned long)(new), \ + sizeof(*(ptr)))); \ +}) + +static __always_inline unsigned long +cmpxchg_local_size (volatile void *ptr,unsigned long old,unsigned long new, +int size) +{ +switch (size) { +case 1 : +return arch_cmpxchg_local ((u8 *)ptr, (u8 )old, (u8 )new); +case 2 : +return arch_cmpxchg_local ((u16 *)ptr, (u16 )old, (u16 )new); +case 4 : +return arch_cmpxchg_local ((u32 *)ptr, (u32 )old, (u32 )new); +case 8 : +BUILD_BUG_ON (sizeof (unsigned long ) !=8 ); +return arch_cmpxchg_local ((u64 *)ptr, (u64 )old, (u64 )new); + } +BUILD_BUG (); +return 0 ; +} + +#define cmpxchg_local (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg_local_size((ptr), \ + (unsigned long)(old), (unsigned long)(new), \ + sizeof(*(ptr)))); \ +}) + +static __always_inline u64 +cmpxchg64_size (volatile u64 *ptr,u64 old,u64 new) +{ +return arch_cmpxchg64 (ptr, old, new); +} + +#define cmpxchg64 (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg64_size((ptr), (u64)(old), \ + (u64)(new))); \ +}) + +static __always_inline u64 +cmpxchg64_local_size (volatile u64 *ptr,u64 old,u64 new) +{ +return arch_cmpxchg64_local (ptr, old, new); +} + +#define cmpxchg64_local (ptr, old, new) \ +({ \ + ((__typeof__(*(ptr)))cmpxchg64_local_size((ptr), (u64)(old), \ + (u64)(new))); \ +}) + +#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +({ \ + arch_cmpxchg_double_local((p1), (p2), (o1), (o2), (n1), (n2)); \ +}) + +#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
Signature · 7 lines
2.16.0.rc1.238.g530d649a79-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Dmitry Vyukov
reviewerPATCH v6 2/4 x86: switch atomic.h to use atomic-instrumented.h
In reply to Dmitry VyukovAdd arch_ prefix to all atomic operations and include <asm-generic/atomic-instrumented.h>. This will allow to add KASAN instrumentation to all atomic ops.
---
Changes since v1:
- reverted unnecessary change in __raw_try_cmpxchg()
- reverted s/try_cmpxchg/arch_try_cmpxchg/ change try_cmpxchg is x86 implementation detail
Changes since v3:
- drop comment in arch_atomic_set()
--- arch/x86/include/asm/atomic.h | 102 ++++++++++++++++++----------------- arch/x86/include/asm/atomic64_32.h | 106 ++++++++++++++++++------------------ arch/x86/include/asm/atomic64_64.h | 108 ++++++++++++++++++------------------- arch/x86/include/asm/cmpxchg.h | 12 ++--- arch/x86/include/asm/cmpxchg_32.h | 8 +-- arch/x86/include/asm/cmpxchg_64.h | 4 +- 6 files changed, 172 insertions(+), 168 deletions(-)
arch/x86/include/asm/atomic.h +52 -50
@@ -17,36 +17,36 @@#define ATOMIC_INIT (i) { (i) }/** -* atomic_read - read atomic variable +* arch_atomic_read - read atomic variable * @v: pointer of type atomic_t * * Atomically reads the value of @v. */ -static __always_inline int atomic_read(const atomic_t *v) +static __always_inline int arch_atomic_read(const atomic_t *v) {return READ_ONCE ((v)->counter); }/** -* atomic_set - set atomic variable +* arch_atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value * * Atomically sets the value of @v to @i. */ -static __always_inline void atomic_set(atomic_t *v, int i) +static __always_inline void arch_atomic_set(atomic_t *v, int i) {WRITE_ONCE (v->counter, i); }/** -* atomic_add - add integer to atomic variable +* arch_atomic_add - add integer to atomic variable * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v. */ -static __always_inline void atomic_add(int i, atomic_t *v) +static __always_inline void arch_atomic_add(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "addl %1,%0" : "+m" (v->counter)
@@ -54,13 +54,13 @@ static __always_inline void atomic_add(int i, atomic_t *v) }/** -* atomic_sub - subtract integer from atomic variable +* arch_atomic_sub - subtract integer from atomic variable * @i: integer value to subtract * @v: pointer of type atomic_t * * Atomically subtracts @i from @v. */ -static __always_inline void atomic_sub(int i, atomic_t *v) +static __always_inline void arch_atomic_sub(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "subl %1,%0" : "+m" (v->counter)
@@ -68,7 +68,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) }/** -* atomic_sub_and_test - subtract value from variable and test result +* arch_atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract * @v: pointer of type atomic_t *
@@ -76,63 +76,63 @@ static __always_inline void atomic_sub(int i, atomic_t *v)* true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "subl" , v->counter,"er" , i,"%0" , e); }/** -* atomic_inc - increment atomic variable +* arch_atomic_inc - increment atomic variable * @v: pointer of type atomic_t * * Atomically increments @v by 1. */ -static __always_inline void atomic_inc(atomic_t *v) +static __always_inline void arch_atomic_inc(atomic_t *v) { asmvolatile (LOCK_PREFIX "incl %0" :"+m" (v->counter)); }/** -* atomic_dec - decrement atomic variable +* arch_atomic_dec - decrement atomic variable * @v: pointer of type atomic_t * * Atomically decrements @v by 1. */ -static __always_inline void atomic_dec(atomic_t *v) +static __always_inline void arch_atomic_dec(atomic_t *v) { asmvolatile (LOCK_PREFIX "decl %0" :"+m" (v->counter)); }/** -* atomic_dec_and_test - decrement and test +* arch_atomic_dec_and_test - decrement and test * @v: pointer of type atomic_t * * Atomically decrements @v by 1 and * returns true if the result is 0, or false for all other * cases. */ -static __always_inline bool atomic_dec_and_test(atomic_t *v) +static __always_inline bool arch_atomic_dec_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "decl" , v->counter,"%0" , e); }/** -* atomic_inc_and_test - increment and test +* arch_atomic_inc_and_test - increment and test * @v: pointer of type atomic_t * * Atomically increments @v by 1 * and returns true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_inc_and_test(atomic_t *v) +static __always_inline bool arch_atomic_inc_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "incl" , v->counter,"%0" , e); }/** -* atomic_add_negative - add and test if negative +* arch_atomic_add_negative - add and test if negative * @i: integer value to add * @v: pointer of type atomic_t *
@@ -140,65 +140,65 @@ static __always_inline bool atomic_inc_and_test(atomic_t *v)* if the result is negative, or false when * result is greater than or equal to zero. */ -static __always_inline bool atomic_add_negative(int i, atomic_t *v) +static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "addl" , v->counter,"er" , i,"%0" , s); }/** -* atomic_add_return - add integer and return +* arch_atomic_add_return - add integer and return * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns @i + @v */ -static __always_inline int atomic_add_return(int i, atomic_t *v) +static __always_inline int arch_atomic_add_return(int i, atomic_t *v) {return i +xadd (&v->counter, i); }/** -* atomic_sub_return - subtract integer and return +* arch_atomic_sub_return - subtract integer and return * @v: pointer of type atomic_t * @i: integer value to subtract * * Atomically subtracts @i from @v and returns @v - @i */ -static __always_inline int atomic_sub_return(int i, atomic_t *v) +static __always_inline int arch_atomic_sub_return(int i, atomic_t *v) { -return atomic_add_return (-i, v); +return arch_atomic_add_return (-i, v); } -#define atomic_inc_return (v) (atomic_add_return(1, v)) -#define atomic_dec_return (v) (atomic_sub_return(1, v)) +#define arch_atomic_inc_return (v) (arch_atomic_add_return(1, v)) +#define arch_atomic_dec_return (v) (arch_atomic_sub_return(1, v)) -static __always_inline int atomic_fetch_add(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v) {return xadd (&v->counter, i); } -static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_sub(int i, atomic_t *v) {return xadd (&v->counter, -i); } -static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) { -return cmpxchg (&v->counter, old, new); +return arch_cmpxchg (&v->counter, old, new); } -#define atomic_try_cmpxchg atomic_try_cmpxchg -static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg +static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new) {return try_cmpxchg (&v->counter, old, new); } -static inline int atomic_xchg (atomic_t *v,int new) +static inline int arch_atomic_xchg (atomic_t *v,int new) {return xchg (&v->counter, new); } -static inline void atomic_and (int i,atomic_t *v) +static inline void arch_atomic_and (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "andl %1,%0" : "+m" (v->counter)
@@ -206,16 +206,16 @@ static inline void atomic_and(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_and (int i,atomic_t *v) +static inline int arch_atomic_fetch_and (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val & i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val & i));return val; } -static inline void atomic_or (int i,atomic_t *v) +static inline void arch_atomic_or (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "orl %1,%0" : "+m" (v->counter)
@@ -223,16 +223,16 @@ static inline void atomic_or(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_or (int i,atomic_t *v) +static inline int arch_atomic_fetch_or (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val | i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val | i));return val; } -static inline void atomic_xor (int i,atomic_t *v) +static inline void arch_atomic_xor (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "xorl %1,%0" : "+m" (v->counter)
@@ -240,17 +240,17 @@ static inline void atomic_xor(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_xor (int i,atomic_t *v) +static inline int arch_atomic_fetch_xor (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val ^ i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val ^ i));return val; }/** -* __atomic_add_unless - add unless the number is already a given value +* __arch_atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t * @a: the amount to add to v... * @u: ...unless v is equal to u.
@@ -258,14 +258,14 @@ static inline int atomic_fetch_xor(int i, atomic_t *v)* Atomically adds @a to @v, so long as @v was not already @u. * Returns the old value of @v. */ -static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +static __always_inline int __arch_atomic_add_unless(atomic_t *v, int a, int u) { -int c =atomic_read (v); +int c =arch_atomic_read (v);do {if (unlikely (c == u))break ; - }while (!atomic_try_cmpxchg (v, &c, c + a)); + }while (!arch_atomic_try_cmpxchg (v, &c, c + a));return c; }
@@ -276,4 +276,6 @@ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)# include <asm/atomic64_64.h> #endif +#include <asm-generic/atomic-instrumented.h> +#endif /* _ASM_X86_ATOMIC_H */
arch/x86/include/asm/atomic64_32.h +54 -52
336 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +54 -54
314 lines not on this page · raw message
arch/x86/include/asm/cmpxchg.h +6 -6
@@ -145,13 +145,13 @@ extern void __add_wrong_size(void)# include <asm/cmpxchg_64.h> #endif -#define cmpxchg (ptr, old, new) \ +#define arch_cmpxchg (ptr, old, new) \ __cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define sync_cmpxchg (ptr, old, new) \ +#define arch_sync_cmpxchg (ptr, old, new) \ __sync_cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define cmpxchg_local (ptr, old, new) \ +#define arch_cmpxchg_local (ptr, old, new) \ __cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
@@ -221,7 +221,7 @@ extern void __add_wrong_size(void)#define __try_cmpxchg (ptr, pold, new, size) \ __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) -#define try_cmpxchg (ptr, pold, new) \ +#define try_cmpxchg (ptr, pold, new) \ __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))/*
@@ -250,10 +250,10 @@ extern void __add_wrong_size(void) __ret; \ }) -#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2) -#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(, p1, p2, o1, o2, n1, n2)#endif /* ASM_X86_CMPXCHG_H */
arch/x86/include/asm/cmpxchg_32.h +4 -4
@@ -36,10 +36,10 @@ static inline void set_64bit(volatile u64 *ptr, u64 value) }#ifdef CONFIG_X86_CMPXCHG64 -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ (unsigned long long)(n))) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ (unsigned long long)(n)))#endif
@@ -76,7 +76,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)* to simulate the cmpxchg8b on the 80386 and 80486 CPU. */ -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
@@ -93,7 +93,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new) __ret; }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
arch/x86/include/asm/cmpxchg_64.h +2 -2
@@ -7,13 +7,13 @@ static inline void set_64bit(volatile u64 *ptr, u64 val) *ptr = val; } -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg((ptr), (o), (n)); \ }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \
Signature · 7 lines
2.16.0.rc1.238.g530d649a79-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic/x86: Switch atomic.h to use atomic-instrumented.h
locking/atomic/x86: Switch atomic.h to use atomic-instrumented.h
Commit-ID: 8bf705d130396e69c04cd8e6e010244ad2ce71f4 Gitweb: https://git.kernel.org/tip/8bf705d130396e69c04cd8e6e010244ad2ce71f4 Author: Dmitry Vyukov <[email protected]> AuthorDate: Mon, 29 Jan 2018 18:26:05 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 12 Mar 2018 12:15:35 +0100
locking/atomic/x86: Switch atomic.h to use atomic-instrumented.h
Add arch_ prefix to all atomic operations and include <asm-generic/atomic-instrumented.h>. This will allow to add KASAN instrumentation to all atomic ops.
--- arch/x86/include/asm/atomic.h | 102 ++++++++++++++++++----------------- arch/x86/include/asm/atomic64_32.h | 106 ++++++++++++++++++------------------ arch/x86/include/asm/atomic64_64.h | 108 ++++++++++++++++++------------------- arch/x86/include/asm/cmpxchg.h | 12 ++--- arch/x86/include/asm/cmpxchg_32.h | 8 +-- arch/x86/include/asm/cmpxchg_64.h | 4 +- 6 files changed, 172 insertions(+), 168 deletions(-)
arch/x86/include/asm/atomic.h +52 -50
@@ -17,36 +17,36 @@#define ATOMIC_INIT (i) { (i) }/** -* atomic_read - read atomic variable +* arch_atomic_read - read atomic variable * @v: pointer of type atomic_t * * Atomically reads the value of @v. */ -static __always_inline int atomic_read(const atomic_t *v) +static __always_inline int arch_atomic_read(const atomic_t *v) {return READ_ONCE ((v)->counter); }/** -* atomic_set - set atomic variable +* arch_atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value * * Atomically sets the value of @v to @i. */ -static __always_inline void atomic_set(atomic_t *v, int i) +static __always_inline void arch_atomic_set(atomic_t *v, int i) {WRITE_ONCE (v->counter, i); }/** -* atomic_add - add integer to atomic variable +* arch_atomic_add - add integer to atomic variable * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v. */ -static __always_inline void atomic_add(int i, atomic_t *v) +static __always_inline void arch_atomic_add(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "addl %1,%0" : "+m" (v->counter)
@@ -54,13 +54,13 @@ static __always_inline void atomic_add(int i, atomic_t *v) }/** -* atomic_sub - subtract integer from atomic variable +* arch_atomic_sub - subtract integer from atomic variable * @i: integer value to subtract * @v: pointer of type atomic_t * * Atomically subtracts @i from @v. */ -static __always_inline void atomic_sub(int i, atomic_t *v) +static __always_inline void arch_atomic_sub(int i, atomic_t *v) { asmvolatile (LOCK_PREFIX "subl %1,%0" : "+m" (v->counter)
@@ -68,7 +68,7 @@ static __always_inline void atomic_sub(int i, atomic_t *v) }/** -* atomic_sub_and_test - subtract value from variable and test result +* arch_atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract * @v: pointer of type atomic_t *
@@ -76,63 +76,63 @@ static __always_inline void atomic_sub(int i, atomic_t *v)* true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) +static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "subl" , v->counter,"er" , i,"%0" , e); }/** -* atomic_inc - increment atomic variable +* arch_atomic_inc - increment atomic variable * @v: pointer of type atomic_t * * Atomically increments @v by 1. */ -static __always_inline void atomic_inc(atomic_t *v) +static __always_inline void arch_atomic_inc(atomic_t *v) { asmvolatile (LOCK_PREFIX "incl %0" :"+m" (v->counter)); }/** -* atomic_dec - decrement atomic variable +* arch_atomic_dec - decrement atomic variable * @v: pointer of type atomic_t * * Atomically decrements @v by 1. */ -static __always_inline void atomic_dec(atomic_t *v) +static __always_inline void arch_atomic_dec(atomic_t *v) { asmvolatile (LOCK_PREFIX "decl %0" :"+m" (v->counter)); }/** -* atomic_dec_and_test - decrement and test +* arch_atomic_dec_and_test - decrement and test * @v: pointer of type atomic_t * * Atomically decrements @v by 1 and * returns true if the result is 0, or false for all other * cases. */ -static __always_inline bool atomic_dec_and_test(atomic_t *v) +static __always_inline bool arch_atomic_dec_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "decl" , v->counter,"%0" , e); }/** -* atomic_inc_and_test - increment and test +* arch_atomic_inc_and_test - increment and test * @v: pointer of type atomic_t * * Atomically increments @v by 1 * and returns true if the result is zero, or false for all * other cases. */ -static __always_inline bool atomic_inc_and_test(atomic_t *v) +static __always_inline bool arch_atomic_inc_and_test(atomic_t *v) {GEN_UNARY_RMWcc (LOCK_PREFIX "incl" , v->counter,"%0" , e); }/** -* atomic_add_negative - add and test if negative +* arch_atomic_add_negative - add and test if negative * @i: integer value to add * @v: pointer of type atomic_t *
@@ -140,65 +140,65 @@ static __always_inline bool atomic_inc_and_test(atomic_t *v)* if the result is negative, or false when * result is greater than or equal to zero. */ -static __always_inline bool atomic_add_negative(int i, atomic_t *v) +static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v) {GEN_BINARY_RMWcc (LOCK_PREFIX "addl" , v->counter,"er" , i,"%0" , s); }/** -* atomic_add_return - add integer and return +* arch_atomic_add_return - add integer and return * @i: integer value to add * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns @i + @v */ -static __always_inline int atomic_add_return(int i, atomic_t *v) +static __always_inline int arch_atomic_add_return(int i, atomic_t *v) {return i +xadd (&v->counter, i); }/** -* atomic_sub_return - subtract integer and return +* arch_atomic_sub_return - subtract integer and return * @v: pointer of type atomic_t * @i: integer value to subtract * * Atomically subtracts @i from @v and returns @v - @i */ -static __always_inline int atomic_sub_return(int i, atomic_t *v) +static __always_inline int arch_atomic_sub_return(int i, atomic_t *v) { -return atomic_add_return (-i, v); +return arch_atomic_add_return (-i, v); } -#define atomic_inc_return (v) (atomic_add_return(1, v)) -#define atomic_dec_return (v) (atomic_sub_return(1, v)) +#define arch_atomic_inc_return (v) (arch_atomic_add_return(1, v)) +#define arch_atomic_dec_return (v) (arch_atomic_sub_return(1, v)) -static __always_inline int atomic_fetch_add(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_add(int i, atomic_t *v) {return xadd (&v->counter, i); } -static __always_inline int atomic_fetch_sub(int i, atomic_t *v) +static __always_inline int arch_atomic_fetch_sub(int i, atomic_t *v) {return xadd (&v->counter, -i); } -static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) +static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) { -return cmpxchg (&v->counter, old, new); +return arch_cmpxchg (&v->counter, old, new); } -#define atomic_try_cmpxchg atomic_try_cmpxchg -static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) +#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg +static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new) {return try_cmpxchg (&v->counter, old, new); } -static inline int atomic_xchg (atomic_t *v,int new) +static inline int arch_atomic_xchg (atomic_t *v,int new) {return xchg (&v->counter, new); } -static inline void atomic_and (int i,atomic_t *v) +static inline void arch_atomic_and (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "andl %1,%0" : "+m" (v->counter)
@@ -206,16 +206,16 @@ static inline void atomic_and(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_and (int i,atomic_t *v) +static inline int arch_atomic_fetch_and (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val & i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val & i));return val; } -static inline void atomic_or (int i,atomic_t *v) +static inline void arch_atomic_or (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "orl %1,%0" : "+m" (v->counter)
@@ -223,16 +223,16 @@ static inline void atomic_or(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_or (int i,atomic_t *v) +static inline int arch_atomic_fetch_or (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val | i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val | i));return val; } -static inline void atomic_xor (int i,atomic_t *v) +static inline void arch_atomic_xor (int i,atomic_t *v) { asmvolatile (LOCK_PREFIX "xorl %1,%0" : "+m" (v->counter)
@@ -240,17 +240,17 @@ static inline void atomic_xor(int i, atomic_t *v) : "memory"); } -static inline int atomic_fetch_xor (int i,atomic_t *v) +static inline int arch_atomic_fetch_xor (int i,atomic_t *v) { -int val =atomic_read (v); +int val =arch_atomic_read (v); -do { }while (!atomic_try_cmpxchg (v, &val, val ^ i)); +do { }while (!arch_atomic_try_cmpxchg (v, &val, val ^ i));return val; }/** -* __atomic_add_unless - add unless the number is already a given value +* __arch_atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t * @a: the amount to add to v... * @u: ...unless v is equal to u.
@@ -258,14 +258,14 @@ static inline int atomic_fetch_xor(int i, atomic_t *v)* Atomically adds @a to @v, so long as @v was not already @u. * Returns the old value of @v. */ -static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) +static __always_inline int __arch_atomic_add_unless(atomic_t *v, int a, int u) { -int c =atomic_read (v); +int c =arch_atomic_read (v);do {if (unlikely (c == u))break ; - }while (!atomic_try_cmpxchg (v, &c, c + a)); + }while (!arch_atomic_try_cmpxchg (v, &c, c + a));return c; }
@@ -276,4 +276,6 @@ static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u)# include <asm/atomic64_64.h> #endif +#include <asm-generic/atomic-instrumented.h> +#endif /* _ASM_X86_ATOMIC_H */
arch/x86/include/asm/atomic64_32.h +54 -52
336 lines not on this page · raw message
arch/x86/include/asm/atomic64_64.h +54 -54
314 lines not on this page · raw message
arch/x86/include/asm/cmpxchg.h +6 -6
@@ -145,13 +145,13 @@ extern void __add_wrong_size(void)# include <asm/cmpxchg_64.h> #endif -#define cmpxchg (ptr, old, new) \ +#define arch_cmpxchg (ptr, old, new) \ __cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define sync_cmpxchg (ptr, old, new) \ +#define arch_sync_cmpxchg (ptr, old, new) \ __sync_cmpxchg(ptr, old, new, sizeof(*(ptr))) -#define cmpxchg_local (ptr, old, new) \ +#define arch_cmpxchg_local (ptr, old, new) \ __cmpxchg_local(ptr, old, new, sizeof(*(ptr)))
@@ -221,7 +221,7 @@ extern void __add_wrong_size(void)#define __try_cmpxchg (ptr, pold, new, size) \ __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) -#define try_cmpxchg (ptr, pold, new) \ +#define try_cmpxchg (ptr, pold, new) \ __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr)))/*
@@ -250,10 +250,10 @@ extern void __add_wrong_size(void) __ret; \ }) -#define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2) -#define cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ +#define arch_cmpxchg_double_local (p1, p2, o1, o2, n1, n2) \ __cmpxchg_double(, p1, p2, o1, o2, n1, n2)#endif /* ASM_X86_CMPXCHG_H */
arch/x86/include/asm/cmpxchg_32.h +4 -4
@@ -36,10 +36,10 @@ static inline void set_64bit(volatile u64 *ptr, u64 value) }#ifdef CONFIG_X86_CMPXCHG64 -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ (unsigned long long)(n))) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \ (unsigned long long)(n)))#endif
@@ -76,7 +76,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)* to simulate the cmpxchg8b on the 80386 and 80486 CPU. */ -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
@@ -93,7 +93,7 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new) __ret; }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ __typeof__(*(ptr)) __ret; \ __typeof__(*(ptr)) __old = (o); \
arch/x86/include/asm/cmpxchg_64.h +2 -2
@@ -7,13 +7,13 @@ static inline void set_64bit(volatile u64 *ptr, u64 val) *ptr = val; } -#define cmpxchg64 (ptr, o, n) \ +#define arch_cmpxchg64 (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg((ptr), (o), (n)); \ }) -#define cmpxchg64_local (ptr, o, n) \ +#define arch_cmpxchg64_local (ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ cmpxchg_local((ptr), (o), (n)); \
Dmitry Vyukov
reviewerPATCH v6 3/4 asm-generic: add KASAN instrumentation to atomic operations
In reply to Dmitry VyukovKASAN 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.
--- include/asm-generic/atomic-instrumented.h | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
include/asm-generic/atomic-instrumented.h +62 -0
@@ -2,44 +2,53 @@#define _LINUX_ATOMIC_INSTRUMENTED_H#include <linux/build_bug.h> +#include <linux/kasan-checks.h> static __always_inline int atomic_read(const atomic_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic_read (v); } static __always_inline s64 atomic64_read(const atomic64_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic64_read (v); } static __always_inline void atomic_set(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));arch_atomic_set (v, i); } static __always_inline void atomic64_set(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));arch_atomic64_set (v, i); } static __always_inline int atomic_xchg(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));return arch_atomic_xchg (v, i); } static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_xchg (v, i); } static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { +kasan_check_write (v,sizeof (*v));return arch_atomic_cmpxchg (v, old, new); } static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_cmpxchg (v, old, new); }
@@ -47,6 +56,8 @@ static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)#define atomic_try_cmpxchg atomic_try_cmpxchg static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic_try_cmpxchg (v, old, new); }#endif
@@ -55,234 +66,281 @@ static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new)#define atomic64_try_cmpxchg atomic64_try_cmpxchg static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic64_try_cmpxchg (v, old, new); }#endif static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) { +kasan_check_write (v,sizeof (*v));return __arch_atomic_add_unless (v, a, u); } static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_unless (v, a, u); } static __always_inline void atomic_inc(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_inc (v); } static __always_inline void atomic64_inc(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_inc (v); } static __always_inline void atomic_dec(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_dec (v); } static __always_inline void atomic64_dec(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_dec (v); } static __always_inline void atomic_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_add (i, v); } static __always_inline void atomic64_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_add (i, v); } static __always_inline void atomic_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_sub (i, v); } static __always_inline void atomic64_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_sub (i, v); } static __always_inline void atomic_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_and (i, v); } static __always_inline void atomic64_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_and (i, v); } static __always_inline void atomic_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_or (i, v); } static __always_inline void atomic64_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_or (i, v); } static __always_inline void atomic_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_xor (i, v); } static __always_inline void atomic64_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_xor (i, v); } static __always_inline int atomic_inc_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_return (v); } static __always_inline s64 atomic64_inc_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_return (v); } static __always_inline int atomic_dec_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_return (v); } static __always_inline s64 atomic64_dec_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_return (v); } static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_not_zero (v); } static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_if_positive (v); } static __always_inline bool atomic_dec_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_and_test (v); } static __always_inline bool atomic64_dec_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_and_test (v); } static __always_inline bool atomic_inc_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_and_test (v); } static __always_inline bool atomic64_inc_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_and_test (v); } static __always_inline int atomic_add_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_return (i, v); } static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_return (i, v); } static __always_inline int atomic_sub_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_return (i, v); } static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_return (i, v); } static __always_inline int atomic_fetch_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_add (i, v); } static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_add (i, v); } static __always_inline int atomic_fetch_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_sub (i, v); } static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_sub (i, v); } static __always_inline int atomic_fetch_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_and (i, v); } static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_and (i, v); } static __always_inline int atomic_fetch_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_or (i, v); } static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_or (i, v); } static __always_inline int atomic_fetch_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_xor (i, v); } static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_xor (i, v); } static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_and_test (i, v); } static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_and_test (i, v); } static __always_inline bool atomic_add_negative(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_negative (i, v); } static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_negative (i, v); }static __always_inline unsigned long cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new,int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -308,6 +366,7 @@ static __always_inline unsigned long sync_cmpxchg_size(volatile void *ptr, unsigned long old, unsigned long new, int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_sync_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -334,6 +393,7 @@ static __always_inline unsigned long cmpxchg_local_size(volatile void *ptr, unsigned long old, unsigned long new, int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_cmpxchg_local ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -359,6 +419,7 @@ cmpxchg_local_size(volatile void *ptr, unsigned long old, unsigned long new, static __always_inline u64cmpxchg64_size (volatile u64 *ptr,u64 old,u64 new) { +kasan_check_write (ptr,sizeof (*ptr));return arch_cmpxchg64 (ptr, old, new); }
@@ -371,6 +432,7 @@ cmpxchg64_size(volatile u64 *ptr, u64 old, u64 new) static __always_inline u64cmpxchg64_local_size (volatile u64 *ptr,u64 old,u64 new) { +kasan_check_write (ptr,sizeof (*ptr));return arch_cmpxchg64_local (ptr, old, new); }
Signature · 7 lines
2.16.0.rc1.238.g530d649a79-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic, asm-generic: Add KASAN instrumentation to atomic operations
locking/atomic, asm-generic: Add KASAN instrumentation to atomic operations
Commit-ID: a35353bb9eb1990a44a0d7585f99e9589bcdb682 Gitweb: https://git.kernel.org/tip/a35353bb9eb1990a44a0d7585f99e9589bcdb682 Author: Dmitry Vyukov <[email protected]> AuthorDate: Mon, 29 Jan 2018 18:26:06 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 12 Mar 2018 12:15:35 +0100
locking/atomic, asm-generic: Add KASAN instrumentation to atomic operations
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.
--- include/asm-generic/atomic-instrumented.h | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
include/asm-generic/atomic-instrumented.h +62 -0
@@ -2,44 +2,53 @@#define _LINUX_ATOMIC_INSTRUMENTED_H#include <linux/build_bug.h> +#include <linux/kasan-checks.h> static __always_inline int atomic_read(const atomic_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic_read (v); } static __always_inline s64 atomic64_read(const atomic64_t *v) { +kasan_check_read (v,sizeof (*v));return arch_atomic64_read (v); } static __always_inline void atomic_set(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));arch_atomic_set (v, i); } static __always_inline void atomic64_set(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));arch_atomic64_set (v, i); } static __always_inline int atomic_xchg(atomic_t *v, int i) { +kasan_check_write (v,sizeof (*v));return arch_atomic_xchg (v, i); } static __always_inline s64 atomic64_xchg(atomic64_t *v, s64 i) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_xchg (v, i); } static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) { +kasan_check_write (v,sizeof (*v));return arch_atomic_cmpxchg (v, old, new); } static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_cmpxchg (v, old, new); }
@@ -47,6 +56,8 @@ static __always_inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new)#define atomic_try_cmpxchg atomic_try_cmpxchg static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic_try_cmpxchg (v, old, new); }#endif
@@ -55,234 +66,281 @@ static __always_inline bool atomic_try_cmpxchg(atomic_t *v, int *old, int new)#define atomic64_try_cmpxchg atomic64_try_cmpxchg static __always_inline bool atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) { +kasan_check_write (v,sizeof (*v)); +kasan_check_read (old,sizeof (*old));return arch_atomic64_try_cmpxchg (v, old, new); }#endif static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) { +kasan_check_write (v,sizeof (*v));return __arch_atomic_add_unless (v, a, u); } static __always_inline bool atomic64_add_unless(atomic64_t *v, s64 a, s64 u) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_unless (v, a, u); } static __always_inline void atomic_inc(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_inc (v); } static __always_inline void atomic64_inc(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_inc (v); } static __always_inline void atomic_dec(atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_dec (v); } static __always_inline void atomic64_dec(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_dec (v); } static __always_inline void atomic_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_add (i, v); } static __always_inline void atomic64_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_add (i, v); } static __always_inline void atomic_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_sub (i, v); } static __always_inline void atomic64_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_sub (i, v); } static __always_inline void atomic_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_and (i, v); } static __always_inline void atomic64_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_and (i, v); } static __always_inline void atomic_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_or (i, v); } static __always_inline void atomic64_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_or (i, v); } static __always_inline void atomic_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic_xor (i, v); } static __always_inline void atomic64_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));arch_atomic64_xor (i, v); } static __always_inline int atomic_inc_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_return (v); } static __always_inline s64 atomic64_inc_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_return (v); } static __always_inline int atomic_dec_return(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_return (v); } static __always_inline s64 atomic64_dec_return(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_return (v); } static __always_inline s64 atomic64_inc_not_zero(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_not_zero (v); } static __always_inline s64 atomic64_dec_if_positive(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_if_positive (v); } static __always_inline bool atomic_dec_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_dec_and_test (v); } static __always_inline bool atomic64_dec_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_dec_and_test (v); } static __always_inline bool atomic_inc_and_test(atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_inc_and_test (v); } static __always_inline bool atomic64_inc_and_test(atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_inc_and_test (v); } static __always_inline int atomic_add_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_return (i, v); } static __always_inline s64 atomic64_add_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_return (i, v); } static __always_inline int atomic_sub_return(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_return (i, v); } static __always_inline s64 atomic64_sub_return(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_return (i, v); } static __always_inline int atomic_fetch_add(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_add (i, v); } static __always_inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_add (i, v); } static __always_inline int atomic_fetch_sub(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_sub (i, v); } static __always_inline s64 atomic64_fetch_sub(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_sub (i, v); } static __always_inline int atomic_fetch_and(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_and (i, v); } static __always_inline s64 atomic64_fetch_and(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_and (i, v); } static __always_inline int atomic_fetch_or(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_or (i, v); } static __always_inline s64 atomic64_fetch_or(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_or (i, v); } static __always_inline int atomic_fetch_xor(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_fetch_xor (i, v); } static __always_inline s64 atomic64_fetch_xor(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_fetch_xor (i, v); } static __always_inline bool atomic_sub_and_test(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_sub_and_test (i, v); } static __always_inline bool atomic64_sub_and_test(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_sub_and_test (i, v); } static __always_inline bool atomic_add_negative(int i, atomic_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic_add_negative (i, v); } static __always_inline bool atomic64_add_negative(s64 i, atomic64_t *v) { +kasan_check_write (v,sizeof (*v));return arch_atomic64_add_negative (i, v); }static __always_inline unsigned long cmpxchg_size (volatile void *ptr,unsigned long old,unsigned long new,int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -308,6 +366,7 @@ static __always_inline unsigned long sync_cmpxchg_size(volatile void *ptr, unsigned long old, unsigned long new, int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_sync_cmpxchg ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -334,6 +393,7 @@ static __always_inline unsigned long cmpxchg_local_size(volatile void *ptr, unsigned long old, unsigned long new, int size) { +kasan_check_write (ptr, size);switch (size) {case 1 :return arch_cmpxchg_local ((u8 *)ptr, (u8 )old, (u8 )new);
@@ -359,6 +419,7 @@ cmpxchg_local_size(volatile void *ptr, unsigned long old, unsigned long new, static __always_inline u64cmpxchg64_size (volatile u64 *ptr,u64 old,u64 new) { +kasan_check_write (ptr,sizeof (*ptr));return arch_cmpxchg64 (ptr, old, new); }
@@ -371,6 +432,7 @@ cmpxchg64_size(volatile u64 *ptr, u64 old, u64 new) static __always_inline u64cmpxchg64_local_size (volatile u64 *ptr,u64 old,u64 new) { +kasan_check_write (ptr,sizeof (*ptr));return arch_cmpxchg64_local (ptr, old, new); }
Dmitry Vyukov
reviewerPATCH v6 4/4 asm-generic, x86: add comments for atomic instrumentation
In reply to Dmitry VyukovThe comments are factored out from the code changes to make them easier to read. Add them separately to explain some non-obvious aspects.
---
Changes since v3:
- rephrase comment in arch_atomic_read()
Changes since v5:
- remove comment explaining cmpxchg macro mess,
since we don't have the mess now.
--- arch/x86/include/asm/atomic.h | 4 ++++ include/asm-generic/atomic-instrumented.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+)
arch/x86/include/asm/atomic.h +4 -0
@@ -24,6 +24,10 @@*/ static __always_inline int arch_atomic_read(const atomic_t *v) { +/* +* Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here, +* it's non-inlined function that increases binary size and stack usage. +*/ return READ_ONCE ((v)->counter); }
include/asm-generic/atomic-instrumented.h +21 -0
@@ -1,3 +1,15 @@ +/* +* This file provides wrappers with KASAN instrumentation for atomic operations. +* To use this functionality an arch's atomic.h file needs to define all +* atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include +* this file at the end. This file provides atomic_read() that forwards to +* arch_atomic_read() for actual atomic operation. +* Note: if an arch atomic operation is implemented by means of other atomic +* operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use +* arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid +* double instrumentation. +*/ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H
@@ -442,6 +454,15 @@ cmpxchg64_local_size(volatile u64 *ptr, u64 old, u64 new) (u64)(new))); \ }) +/* +* Originally we had the following code here: +* __typeof__(p1) ____p1 = (p1); +* kasan_check_write(____p1, 2 * sizeof(*____p1)); +* arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); +* But it leads to compilation failures (see gcc issue 72873). +* So for now it's left non-instrumented. +* There are few callers of cmpxchg_double(), so it's not critical. +*/ #define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ ({ \ arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \
Signature · 7 lines
2.16.0.rc1.238.g530d649a79-goog -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
tip-bot for Dmitry Vyukov
merge bot[tip:locking/core] locking/atomic, asm-generic, x86: Add comments for atomic instrumentation
locking/atomic, asm-generic, x86: Add comments for atomic instrumentation
Commit-ID: ac605bee0bfab40fd5d11964705e907d2d5a32de Gitweb: https://git.kernel.org/tip/ac605bee0bfab40fd5d11964705e907d2d5a32de Author: Dmitry Vyukov <[email protected]> AuthorDate: Mon, 29 Jan 2018 18:26:07 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 12 Mar 2018 12:15:35 +0100
locking/atomic, asm-generic, x86: Add comments for atomic instrumentation
The comments are factored out from the code changes to make them easier to read. Add them separately to explain some non-obvious aspects.
--- arch/x86/include/asm/atomic.h | 4 ++++ include/asm-generic/atomic-instrumented.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+)
arch/x86/include/asm/atomic.h +4 -0
@@ -24,6 +24,10 @@*/ static __always_inline int arch_atomic_read(const atomic_t *v) { +/* +* Note for KASAN: we deliberately don't use READ_ONCE_NOCHECK() here, +* it's non-inlined function that increases binary size and stack usage. +*/ return READ_ONCE ((v)->counter); }
include/asm-generic/atomic-instrumented.h +21 -0
@@ -1,3 +1,15 @@ +/* +* This file provides wrappers with KASAN instrumentation for atomic operations. +* To use this functionality an arch's atomic.h file needs to define all +* atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include +* this file at the end. This file provides atomic_read() that forwards to +* arch_atomic_read() for actual atomic operation. +* Note: if an arch atomic operation is implemented by means of other atomic +* operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use +* arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid +* double instrumentation. +*/ +#ifndef _LINUX_ATOMIC_INSTRUMENTED_H#define _LINUX_ATOMIC_INSTRUMENTED_H
@@ -442,6 +454,15 @@ cmpxchg64_local_size(volatile u64 *ptr, u64 old, u64 new) (u64)(new))); \ }) +/* +* Originally we had the following code here: +* __typeof__(p1) ____p1 = (p1); +* kasan_check_write(____p1, 2 * sizeof(*____p1)); +* arch_cmpxchg_double(____p1, (p2), (o1), (o2), (n1), (n2)); +* But it leads to compilation failures (see gcc issue 72873). +* So for now it's left non-instrumented. +* There are few callers of cmpxchg_double(), so it's not critical. +*/ #define cmpxchg_double (p1, p2, o1, o2, n1, n2) \ ({ \ arch_cmpxchg_double((p1), (p2), (o1), (o2), (n1), (n2)); \
Dmitry Vyukov
reviewerQuoted 90 lines · Dmitry Vyukov
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
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 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: 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 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 __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/0x7aChanges since v1:
- dropped "x86: remove unusedatomic_inc_short()" patch it is mailed separately
- rebased on top of tip/locking/core head
- other changes noted within individual patchesChanges since v2:
- rebased on top of tip/locking/core head
- dropped a pervasive "x86: use long long for 64-bit atomic ops" commit, instead use s64 type in wrappers
- added "x86: use s64* for old arg ofatomic64_try_cmpxchg()" commit
Quoted 8 lines
Changes since v3 are noted in individual commits.
Changes since v4:
- rebased on tip/locking/core HEADChanges since v5:
- rework cmpxchg* implementations so that we have less code in macros and more code in functions
Some context.
This revives a half-year old patch. v5 of this was applied to tip/locking/core, but then reverted due to a reported crash:
https://groups.google.com/d/msg/kasan-dev/ZJl66N7smmk/lJY99HmmAgAJ
The root cause was in the cmpxchg macros:
#define cmpxchg64(ptr, old, new) \
({ \
__typeof__(ptr) ____ptr = (ptr); \
kasan_check_write(____ptr, sizeof(*____ptr)); \
arch_cmpxchg64(____ptr, (old), (new)); \})
I had to introduce the new ____ptr variable, so that kasan_check_write() and arch_cmpxchg64() don't evaluate ptr twice. But there are multiple layers of macros and ____ptr ended up referring to something else (to itself).
v6 changes cmpxchg macros to (as was suggested by Mark and Thomas):
static __always_inline unsigned longcmpxchg_size(volatile void *ptr, unsigned long old, unsigned long new, int size)
{
kasan_check_write(ptr, size);
switch (size) {
case 1:
return arch_cmpxchg((u8 *)ptr, (u8)old, (u8)new);
case 2:
return arch_cmpxchg((u16 *)ptr, (u16)old, (u16)new);
case 4:
return arch_cmpxchg((u32 *)ptr, (u32)old, (u32)new);
case 8:
BUILD_BUG_ON(sizeof(unsigned long) != 8);
return arch_cmpxchg((u64 *)ptr, (u64)old, (u64)new);
}
BUILD_BUG();
return 0;
}#define cmpxchg(ptr, old, new) \
({ \
((__typeof__(*(ptr)))cmpxchg_size((ptr), (unsigned long)(old), \
(unsigned long)(new), sizeof(*(ptr)))); \
})Otherwise the patch series were rebased without any conflicts (surprisingly).
There is now some duplication between cmpxchg_size, cmpxchg_local_size and sync_cmpxchg_size, but I thought that employing more macros while trying to resolve macro mess bugs is not the best idea.
Quoted 24 lines
Tested:
- build/bootx86_64defconfig
- build/bootx86_64defconfig+KASAN
- build i686/powerpc defconfigDmitry Vyukov (4):
locking/atomic: Addasm-generic/atomic-instrumented.h
x86: switchatomic.hto useatomic-instrumented.h
asm-generic: add KASAN instrumentation to atomic operations asm-generic, x86: add comments for atomic instrumentationarch/x86/include/asm/atomic.h | 106 +++---- arch/x86/include/asm/atomic64_32.h | 106 +++---- arch/x86/include/asm/atomic64_64.h | 108 +++---- arch/x86/include/asm/cmpxchg.h | 12 +- arch/x86/include/asm/cmpxchg_32.h | 8 +- arch/x86/include/asm/cmpxchg_64.h | 4 +- include/asm-generic/atomic-instrumented.h | 476 ++++++++++++++++++++++++++++++ 7 files changed, 652 insertions(+), 168 deletions(-) create mode 100644 include/asm-generic/atomic-instrumented.h--
2.16.0.rc1.238.g530d649a79-goog
Dmitry Vyukov
reviewerQuoted 146 lines · Dmitry Vyukov
Quoted 90 lines · Dmitry Vyukov
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
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 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: 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 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 __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/0x7aChanges since v1:
- dropped "x86: remove unusedatomic_inc_short()" patch it is mailed separately
- rebased on top of tip/locking/core head
- other changes noted within individual patchesChanges since v2:
- rebased on top of tip/locking/core head
- dropped a pervasive "x86: use long long for 64-bit atomic ops" commit, instead use s64 type in wrappers
- added "x86: use s64* for old arg ofatomic64_try_cmpxchg()" commitQuoted 8 lines
Changes since v3 are noted in individual commits.
Changes since v4:
- rebased on tip/locking/core HEADChanges since v5:
- rework cmpxchg* implementations so that we have less code in macros and more code in functionsSome context.
This revives a half-year old patch. v5 of this was applied to tip/locking/core, but then reverted due to a reported crash:
https://groups.google.com/d/msg/kasan-dev/ZJl66N7smmk/lJY99HmmAgAJThe root cause was in the cmpxchg macros:
#define cmpxchg64(ptr, old, new) \ ({ \ __typeof__(ptr) ____ptr = (ptr); \ kasan_check_write(____ptr, sizeof(*____ptr)); \ arch_cmpxchg64(____ptr, (old), (new)); \})
I had to introduce the new
____ptrvariable, so thatkasan_check_write()andarch_cmpxchg64()don't evaluate ptr twice. But there are multiple layers of macros and____ptrended up referring to something else (to itself).v6 changes cmpxchg macros to (as was suggested by Mark and Thomas):
static
__always_inlineunsigned longcmpxchg_size(volatile void *ptr, unsigned long old, unsigned long new, int size){ kasan_check_write(ptr, size); switch (size) { case 1: return arch_cmpxchg((u8 *)ptr, (u8)old, (u8)new); case 2: return arch_cmpxchg((u16 *)ptr, (u16)old, (u16)new); case 4: return arch_cmpxchg((u32 *)ptr, (u32)old, (u32)new); case 8: BUILD_BUG_ON(sizeof(unsigned long) != 8); return arch_cmpxchg((u64 *)ptr, (u64)old, (u64)new); } BUILD_BUG(); return 0; }#define
cmpxchg(ptr, old, new)\({ \ ((__typeof__(*(ptr)))cmpxchg_size((ptr), (unsigned long)(old), \ (unsigned long)(new), sizeof(*(ptr)))); \ })
Quoted 5 lines
Otherwise the patch series were rebased without any conflicts (surprisingly).
There is now some duplication between
cmpxchg_size,cmpxchg_local_sizeandsync_cmpxchg_size, but I thought that employing more macros while trying to resolve macro mess bugs is not the best idea.
Why I am reviving this patch now: besides the fact that it needs to be done sooner or later anyway (also useful for KMSAN/KTSAN), now there is another reason. Any silent heap corruptions produce very negative effect on syzbot. If we miss a corruption on atomic access, syzbot can report a dozen of induced crashes in random places. These look broken, unexplainable, non-reproducible and cause complaints. It's better to proactively prevent at this this known source of silent corruptions.
Hi Dmitry,
Quoted 11 lines · Dmitry Vyukov
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
Quoted 6 lines
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
One way you could reduce the intrusivness for each architecture would be to leave the existing macro names as-is, and redefine them in the asm-generic header. It's certainly ugly, but it makes the porting work a lot smaller. Apologies if you've considered this approach before, but I figured it was worth mentioning just in case.
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef _LINUX_ATOMIC_INSTRUMENTED_H
#define _LINUX_ATOMIC_INSTRUMENTED_H
#include <linux/build_bug.h>
#include <linux/kasan-checks.h>
static __always_inline int __atomic_read_instrumented(const atomic_t *v)
{
kasan_check_read(v, sizeof(*v));
return atomic_read(v);
}static __always_inline s64 __atomic64_read_instrumented(const atomic64_t *v)
{
kasan_check_read(v, sizeof(*v));
return atomic64_read(v);
}#undef atomic_read
#undef atomic64_read
#define atomic_read __atomic_read_instrumented
#define atomic64_read __atomic64_read_instrumented
#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
and the arch code just includes that in asm/atomic.h once it's done with its definitions.
What do you think? Too stinky?
Will
Quoted 53 lines · Will Deacon
Hi Dmitry,
Quoted 11 lines · Dmitry Vyukov
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
Quoted 6 lines
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
One way you could reduce the intrusivness for each architecture would be to leave the existing macro names as-is, and redefine them in the asm-generic header. It's certainly ugly, but it makes the porting work a lot smaller. Apologies if you've considered this approach before, but I figured it was worth mentioning just in case.
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumented
Quoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the arch_ prefix that makes it abundantly clear that this isn't the highest level interface.
The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
Thanks,
Ingo
Dmitry Vyukov
reviewerQuoted 71 lines · Ingo Molnar
Quoted 53 lines · Will Deacon
Hi Dmitry,
Quoted 11 lines · Dmitry Vyukov
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.
Atomic operations are defined in arch files, but KASAN instrumentation is required for several archs that support KASAN. Later we will need similar hooks for KMSAN (uninit use detector) and KTSAN (data race detector).
Quoted 6 lines
This change introduces wrappers around atomic operations that can be used to add KASAN/KMSAN/KTSAN instrumentation across several archs, and adds KASAN checks to them.
This patch uses the wrappers only for x86 arch. Arm64 will be switched later. And we also plan to instrument bitops in a similar way.
One way you could reduce the intrusivness for each architecture would be to leave the existing macro names as-is, and redefine them in the asm-generic header. It's certainly ugly, but it makes the porting work a lot smaller. Apologies if you've considered this approach before, but I figured it was worth mentioning just in case.
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumentedQuoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the
arch_prefix that makes it abundantly clear that this isn't the highest level interface.The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Quoted 7 lines
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
I think I mildly leaning towards Ingo's point.
I guess people will first find the version in arch (because that's where they used to be), but that version is actually not the one that is called.
The renaming is mechanical and you get build errors if anything is wrong. It's macros that caused hard to debug runtime crashes and multiple revisions of this series.
Quoted 52 lines · Dmitry Vyukov
Quoted 42 lines · Ingo Molnar
Quoted 26 lines · Will Deacon
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumentedQuoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the
arch_prefix that makes it abundantly clear that this isn't the highest level interface.The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Quoted 7 lines
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
Quoted 7 lines
I think I mildly leaning towards Ingo's point.
I guess people will first find the version in arch (because that's where they used to be), but that version is actually not the one that is called.
The renaming is mechanical and you get build errors if anything is wrong. It's macros that caused hard to debug runtime crashes and multiple revisions of this series.
Sure, and it sounds like you're proposing to do the arm64 changes anyway so I'm not complaining! Just thought I'd float the alternative to see what people think.
Will
Dmitry Vyukov
reviewerQuoted 59 lines · Will Deacon
Quoted 51 lines
Quoted 42 lines · Will Deacon
Quoted 26 lines
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumentedQuoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the
arch_prefix that makes it abundantly clear that this isn't the highest level interface.The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Quoted 7 lines
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
Quoted 7 lines
I think I mildly leaning towards Ingo's point.
I guess people will first find the version in arch (because that's where they used to be), but that version is actually not the one that is called.
The renaming is mechanical and you get build errors if anything is wrong. It's macros that caused hard to debug runtime crashes and multiple revisions of this series.
Quoted 3 lines
Sure, and it sounds like you're proposing to do the arm64 changes anyway so I'm not complaining! Just thought I'd float the alternative to see what people think.
Any other comments?
Ingo, will you take this to locking tree?
Dmitry Vyukov
reviewerQuoted 60 lines · Dmitry Vyukov
Quoted 59 lines · Will Deacon
Quoted 58 lines
Quoted 42 lines · Will Deacon
Quoted 26 lines
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumentedQuoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the
arch_prefix that makes it abundantly clear that this isn't the highest level interface.The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Quoted 7 lines
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
I think I mildly leaning towards Ingo's point.
I guess people will first find the version in arch (because that's where they used to be), but that version is actually not the one that is called.
The renaming is mechanical and you get build errors if anything is wrong. It's macros that caused hard to debug runtime crashes and multiple revisions of this series.
Quoted 7 lines
Quoted 3 lines
Sure, and it sounds like you're proposing to do the arm64 changes anyway so I'm not complaining! Just thought I'd float the alternative to see what people think.
Any other comments?
Ingo, will you take this to locking tree?
Any other comments?
Ingo, will you take this to locking tree?
Dmitry Vyukov
reviewerQuoted 66 lines · Dmitry Vyukov
Quoted 65 lines · Dmitry Vyukov
Quoted 62 lines · Will Deacon
Quoted 51 lines
Quoted 42 lines · Will Deacon
Quoted 26 lines
e.g. for atomic[64]_read, your asm-generic header looks like:
#ifndef
_LINUX_ATOMIC_INSTRUMENTED_H
#define_LINUX_ATOMIC_INSTRUMENTED_H#include <
linux/build_bug.h>
#include <linux/kasan-checks.h>static
__always_inlineint__atomic_read_instrumented(const atomic_t *v){ kasan_check_read(v, sizeof(*v)); return atomic_read(v); }static
__always_inlines64__atomic64_read_instrumented(const atomic64_t *v){ kasan_check_read(v, sizeof(*v)); return atomic64_read(v); }#undef
atomic_read
#undefatomic64_read#define
atomic_read__atomic_read_instrumented
#defineatomic64_read__atomic64_read_instrumentedQuoted 6 lines
#endif /*
_LINUX_ATOMIC_INSTRUMENTED_H*/and the arch code just includes that in
asm/atomic.honce it's done with its definitions.What do you think? Too stinky?
Hm, so while this could work - I actually *like* the low level changes: they are straightforward, trivial, easy to read and they add the
arch_prefix that makes it abundantly clear that this isn't the highest level interface.The KASAN callbacks in the generic methods are also abundantly clear and very easy to read. I could literally verify the sanity of the series while still being only half awake. ;-)
Quoted 7 lines
Also note that the arch renaming should be 'trivial', in the sense that any missing rename results in a clear build breakage. Plus any architecture making use of this new KASAN feature should probably be tested before it's enabled - and the renaming of the low level atomic APIs kind of forces that too.
So while this approach creates some churn, this series is IMHO a marked improvement over the previous iterations.
Quoted 7 lines
I think I mildly leaning towards Ingo's point.
I guess people will first find the version in arch (because that's where they used to be), but that version is actually not the one that is called.
The renaming is mechanical and you get build errors if anything is wrong. It's macros that caused hard to debug runtime crashes and multiple revisions of this series.Sure, and it sounds like you're proposing to do the arm64 changes anyway so I'm not complaining! Just thought I'd float the alternative to see what people think.
Quoted 6 lines
Quoted 2 lines
Any other comments?
Ingo, will you take this to locking tree?Any other comments?
Ingo, will you take this to locking tree?
Peter, Ingo, ping.