Merge branch 'KASAN-read_word_at_a_time'
Merge KASAN word-at-a-time fixups from Andrey Ryabinin. The word-at-a-time optimizations have caused headaches for KASAN, since the whole point is that we access byte streams in bigger chunks, and KASAN can be unhappy about the potential extra access at the end of the string. We used to have a horrible hack in dcache, and then people got complaints from the strscpy() case. This fixes it all up properly, by adding an explicit helper for the "access byte stream one word at a time" case. * emailed patches from Andrey Ryabinin <aryabinin@virtuozzo.com>: fs: dcache: Revert "manually unpoison dname after allocation to shut up kasan's reports" fs/dcache: Use read_word_at_a_time() in dentry_string_cmp() lib/strscpy: Shut up KASAN false-positives in strscpy() compiler.h: Add read_word_at_a_time() function. compiler.h, kasan: Avoid duplicating __read_once_size_nocheck()
This commit is contained in:
commit
8e44e6600c
|
@ -37,8 +37,6 @@
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/list_lru.h>
|
#include <linux/list_lru.h>
|
||||||
#include <linux/kasan.h>
|
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "mount.h"
|
#include "mount.h"
|
||||||
|
|
||||||
|
@ -193,7 +191,7 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char
|
||||||
unsigned long a,b,mask;
|
unsigned long a,b,mask;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
a = *(unsigned long *)cs;
|
a = read_word_at_a_time(cs);
|
||||||
b = load_unaligned_zeropad(ct);
|
b = load_unaligned_zeropad(ct);
|
||||||
if (tcount < sizeof(unsigned long))
|
if (tcount < sizeof(unsigned long))
|
||||||
break;
|
break;
|
||||||
|
@ -1628,9 +1626,6 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
||||||
}
|
}
|
||||||
atomic_set(&p->u.count, 1);
|
atomic_set(&p->u.count, 1);
|
||||||
dname = p->name;
|
dname = p->name;
|
||||||
if (IS_ENABLED(CONFIG_DCACHE_WORD_ACCESS))
|
|
||||||
kasan_unpoison_shadow(dname,
|
|
||||||
round_up(name->len + 1, sizeof(unsigned long)));
|
|
||||||
} else {
|
} else {
|
||||||
dname = dentry->d_iname;
|
dname = dentry->d_iname;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,23 +185,21 @@ void __read_once_size(const volatile void *p, void *res, int size)
|
||||||
|
|
||||||
#ifdef CONFIG_KASAN
|
#ifdef CONFIG_KASAN
|
||||||
/*
|
/*
|
||||||
* This function is not 'inline' because __no_sanitize_address confilcts
|
* We can't declare function 'inline' because __no_sanitize_address confilcts
|
||||||
* with inlining. Attempt to inline it may cause a build failure.
|
* with inlining. Attempt to inline it may cause a build failure.
|
||||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
|
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
|
||||||
* '__maybe_unused' allows us to avoid defined-but-not-used warnings.
|
* '__maybe_unused' allows us to avoid defined-but-not-used warnings.
|
||||||
*/
|
*/
|
||||||
static __no_sanitize_address __maybe_unused
|
# define __no_kasan_or_inline __no_sanitize_address __maybe_unused
|
||||||
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
|
|
||||||
{
|
|
||||||
__READ_ONCE_SIZE;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static __always_inline
|
# define __no_kasan_or_inline __always_inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static __no_kasan_or_inline
|
||||||
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
|
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
|
||||||
{
|
{
|
||||||
__READ_ONCE_SIZE;
|
__READ_ONCE_SIZE;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
|
static __always_inline void __write_once_size(volatile void *p, void *res, int size)
|
||||||
{
|
{
|
||||||
|
@ -240,6 +238,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
|
||||||
* required ordering.
|
* required ordering.
|
||||||
*/
|
*/
|
||||||
#include <asm/barrier.h>
|
#include <asm/barrier.h>
|
||||||
|
#include <linux/kasan-checks.h>
|
||||||
|
|
||||||
#define __READ_ONCE(x, check) \
|
#define __READ_ONCE(x, check) \
|
||||||
({ \
|
({ \
|
||||||
|
@ -259,6 +258,13 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
|
||||||
*/
|
*/
|
||||||
#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
|
#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
|
||||||
|
|
||||||
|
static __no_kasan_or_inline
|
||||||
|
unsigned long read_word_at_a_time(const void *addr)
|
||||||
|
{
|
||||||
|
kasan_check_read(addr, 1);
|
||||||
|
return *(unsigned long *)addr;
|
||||||
|
}
|
||||||
|
|
||||||
#define WRITE_ONCE(x, val) \
|
#define WRITE_ONCE(x, val) \
|
||||||
({ \
|
({ \
|
||||||
union { typeof(x) __val; char __c[1]; } __u = \
|
union { typeof(x) __val; char __c[1]; } __u = \
|
||||||
|
|
|
@ -203,7 +203,7 @@ ssize_t strscpy(char *dest, const char *src, size_t count)
|
||||||
while (max >= sizeof(unsigned long)) {
|
while (max >= sizeof(unsigned long)) {
|
||||||
unsigned long c, data;
|
unsigned long c, data;
|
||||||
|
|
||||||
c = *(unsigned long *)(src+res);
|
c = read_word_at_a_time(src+res);
|
||||||
if (has_zero(c, &data, &constants)) {
|
if (has_zero(c, &data, &constants)) {
|
||||||
data = prep_zero_mask(c, data, &constants);
|
data = prep_zero_mask(c, data, &constants);
|
||||||
data = create_zero_mask(data);
|
data = create_zero_mask(data);
|
||||||
|
|
Loading…
Reference in New Issue