Skip to content

Commit d6d51a9

Browse files
linuswRussell King
authored and
Russell King
committed
ARM: 9014/2: Replace string mem* functions for KASan
Functions like memset()/memmove()/memcpy() do a lot of memory accesses. If a bad pointer is passed to one of these functions it is important to catch this. Compiler instrumentation cannot do this since these functions are written in assembly. KASan replaces these memory functions with instrumented variants. The original functions are declared as weak symbols so that the strong definitions in mm/kasan/kasan.c can replace them. The original functions have aliases with a '__' prefix in their name, so we can call the non-instrumented variant if needed. We must use __memcpy()/__memset() in place of memcpy()/memset() when we copy .data to RAM and when we clear .bss, because kasan_early_init cannot be called before the initialization of .data and .bss. For the kernel compression and EFI libstub's custom string libraries we need a special quirk: even if these are built without KASan enabled, they rely on the global headers for their custom string libraries, which means that e.g. memcpy() will be defined to __memcpy() and we get link failures. Since these implementations are written i C rather than assembly we use e.g. __alias(memcpy) to redirected any users back to the local implementation. Cc: Andrey Ryabinin <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: [email protected] Reviewed-by: Ard Biesheuvel <[email protected]> Tested-by: Ard Biesheuvel <[email protected]> # QEMU/KVM/mach-virt/LPAE/8G Tested-by: Florian Fainelli <[email protected]> # Brahma SoCs Tested-by: Ahmad Fatoum <[email protected]> # i.MX6Q Reported-by: Russell King - ARM Linux <[email protected]> Signed-off-by: Ahmad Fatoum <[email protected]> Signed-off-by: Abbott Liu <[email protected]> Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: Linus Walleij <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent d5d44e7 commit d6d51a9

File tree

6 files changed

+57
-3
lines changed

6 files changed

+57
-3
lines changed

arch/arm/boot/compressed/string.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,25 @@
77

88
#include <linux/string.h>
99

10+
/*
11+
* The decompressor is built without KASan but uses the same redirects as the
12+
* rest of the kernel when CONFIG_KASAN is enabled, defining e.g. memcpy()
13+
* to __memcpy() but since we are not linking with the main kernel string
14+
* library in the decompressor, that will lead to link failures.
15+
*
16+
* Undefine KASan's versions, define the wrapped functions and alias them to
17+
* the right names so that when e.g. __memcpy() appear in the code, it will
18+
* still be linked to this local version of memcpy().
19+
*/
20+
#ifdef CONFIG_KASAN
21+
#undef memcpy
22+
#undef memmove
23+
#undef memset
24+
void *__memcpy(void *__dest, __const void *__src, size_t __n) __alias(memcpy);
25+
void *__memmove(void *__dest, __const void *__src, size_t count) __alias(memmove);
26+
void *__memset(void *s, int c, size_t count) __alias(memset);
27+
#endif
28+
1029
void *memcpy(void *__dest, __const void *__src, size_t __n)
1130
{
1231
int i = 0;

arch/arm/include/asm/string.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
/*
66
* We don't do inline string functions, since the
77
* optimised inline asm versions are not small.
8+
*
9+
* The __underscore versions of some functions are for KASan to be able
10+
* to replace them with instrumented versions.
811
*/
912

1013
#define __HAVE_ARCH_STRRCHR
@@ -15,15 +18,18 @@ extern char * strchr(const char * s, int c);
1518

1619
#define __HAVE_ARCH_MEMCPY
1720
extern void * memcpy(void *, const void *, __kernel_size_t);
21+
extern void *__memcpy(void *dest, const void *src, __kernel_size_t n);
1822

1923
#define __HAVE_ARCH_MEMMOVE
2024
extern void * memmove(void *, const void *, __kernel_size_t);
25+
extern void *__memmove(void *dest, const void *src, __kernel_size_t n);
2126

2227
#define __HAVE_ARCH_MEMCHR
2328
extern void * memchr(const void *, int, __kernel_size_t);
2429

2530
#define __HAVE_ARCH_MEMSET
2631
extern void * memset(void *, int, __kernel_size_t);
32+
extern void *__memset(void *s, int c, __kernel_size_t n);
2733

2834
#define __HAVE_ARCH_MEMSET32
2935
extern void *__memset32(uint32_t *, uint32_t v, __kernel_size_t);
@@ -39,4 +45,24 @@ static inline void *memset64(uint64_t *p, uint64_t v, __kernel_size_t n)
3945
return __memset64(p, v, n * 8, v >> 32);
4046
}
4147

48+
/*
49+
* For files that are not instrumented (e.g. mm/slub.c) we
50+
* must use non-instrumented versions of the mem*
51+
* functions named __memcpy() etc. All such kernel code has
52+
* been tagged with KASAN_SANITIZE_file.o = n, which means
53+
* that the address sanitization argument isn't passed to the
54+
* compiler, and __SANITIZE_ADDRESS__ is not set. As a result
55+
* these defines kick in.
56+
*/
57+
#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
58+
#define memcpy(dst, src, len) __memcpy(dst, src, len)
59+
#define memmove(dst, src, len) __memmove(dst, src, len)
60+
#define memset(s, c, n) __memset(s, c, n)
61+
62+
#ifndef __NO_FORTIFY
63+
#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
64+
#endif
65+
66+
#endif
67+
4268
#endif

arch/arm/kernel/head-common.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ __mmap_switched:
9595
THUMB( ldmia r4!, {r0, r1, r2, r3} )
9696
THUMB( mov sp, r3 )
9797
sub r2, r2, r1
98-
bl memcpy @ copy .data to RAM
98+
bl __memcpy @ copy .data to RAM
9999
#endif
100100

101101
ARM( ldmia r4!, {r0, r1, sp} )
102102
THUMB( ldmia r4!, {r0, r1, r3} )
103103
THUMB( mov sp, r3 )
104104
sub r2, r1, r0
105105
mov r1, #0
106-
bl memset @ clear .bss
106+
bl __memset @ clear .bss
107107

108108
ldmia r4, {r0, r1, r2, r3}
109109
str r9, [r0] @ Save processor ID

arch/arm/lib/memcpy.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,13 @@
5858

5959
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
6060

61+
.weak memcpy
62+
ENTRY(__memcpy)
6163
ENTRY(mmiocpy)
6264
ENTRY(memcpy)
6365

6466
#include "copy_template.S"
6567

6668
ENDPROC(memcpy)
6769
ENDPROC(mmiocpy)
70+
ENDPROC(__memcpy)

arch/arm/lib/memmove.S

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
* occurring in the opposite direction.
2525
*/
2626

27+
.weak memmove
28+
ENTRY(__memmove)
2729
ENTRY(memmove)
2830
UNWIND( .fnstart )
2931

3032
subs ip, r0, r1
3133
cmphi r2, ip
32-
bls memcpy
34+
bls __memcpy
3335

3436
stmfd sp!, {r0, r4, lr}
3537
UNWIND( .fnend )
@@ -222,3 +224,4 @@ ENTRY(memmove)
222224
18: backward_copy_shift push=24 pull=8
223225

224226
ENDPROC(memmove)
227+
ENDPROC(__memmove)

arch/arm/lib/memset.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
.text
1414
.align 5
1515

16+
.weak memset
17+
ENTRY(__memset)
1618
ENTRY(mmioset)
1719
ENTRY(memset)
1820
UNWIND( .fnstart )
@@ -132,6 +134,7 @@ UNWIND( .fnstart )
132134
UNWIND( .fnend )
133135
ENDPROC(memset)
134136
ENDPROC(mmioset)
137+
ENDPROC(__memset)
135138

136139
ENTRY(__memset32)
137140
UNWIND( .fnstart )

0 commit comments

Comments
 (0)