mm/kasan: Tag kasan and generic kasan use the same instrumentation options

1. Tested on QEMU, the two sockets were basically the same, and their performance was not affected. The size of the generated bin file was also the same
2. Extract global detection as a separate file, both types of Kasan support global variable out of bounds detection simultaneously

Signed-off-by: wangmingrong1 <wangmingrong1@xiaomi.com>
This commit is contained in:
wangmingrong1 2024-09-18 15:51:02 +08:00 committed by Xiang Xiao
parent 5c511443fe
commit 071af0c993
9 changed files with 158 additions and 94 deletions

View File

@ -143,4 +143,3 @@ If you want the module you are writing to not be inserted by the compiler,
you can add the option 'CFLAGS += -fno-sanitize=kernel-address' to a single module.
If it is a file, you can write it this way,
special_file.o: CFLAGS = -fno-sanitize=kernel-address
or : special_file.o: CFLAGS = -fno-sanitize=kernel-hwaddress

View File

@ -79,11 +79,7 @@ ifeq ($(CONFIG_MM_UBSAN_TRAP_ON_ERROR),y)
endif
ifeq ($(CONFIG_MM_KASAN_ALL),y)
ifeq ($(CONFIG_MM_KASAN_GENERIC),y)
ARCHOPTIMIZATION += -fsanitize=kernel-address
else ifeq ($(CONFIG_MM_KASAN_SW_TAGS),y)
ARCHOPTIMIZATION += -fsanitize=kernel-hwaddress
endif
ARCHOPTIMIZATION += -fsanitize=kernel-address
endif
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)

View File

@ -328,7 +328,7 @@ config MM_KASAN_DISABLE_WRITES_CHECK
config MM_KASAN_GLOBAL
bool "Enable global data check"
depends on MM_KASAN_GENERIC
depends on MM_KASAN_ALL
default n
---help---
This option enables KASan global data check.

View File

@ -23,13 +23,7 @@ set(SRCS hook.c)
if(CONFIG_MM_KASAN)
list(APPEND FLAGS -fno-builtin)
if(CONFIG_MM_KASAN_GENERIC)
list(APPEND FLAGS -fno-sanitize=kernel-address)
endif()
if(CONFIG_MM_KASAN_SW_TAGS)
list(APPEND FLAGS -fno-sanitize=kernel-hwaddress)
endif()
list(APPEND FLAGS -fno-sanitize=kernel-address)
if(CONFIG_LTO_NONE)
list(APPEND FLAGS -fno-lto)

View File

@ -23,23 +23,14 @@
CSRCS += hook.c
ifeq ($(CONFIG_MM_KASAN),y)
ifeq ($(CONFIG_MM_KASAN_GENERIC),y)
CFLAGS += -fno-sanitize=kernel-address
endif
ifeq ($(CONFIG_MM_KASAN_SW_TAGS),y)
CFLAGS += -fno-sanitize=kernel-hwaddress
endif
CFLAGS += -fno-builtin
CFLAGS += -fno-sanitize=kernel-address
ifeq ($(CONFIG_LTO_NONE),n)
CFLAGS += -fno-lto
endif
endif
CFLAGS += -fno-builtin
# Add the core heap directory to the build
DEPPATH += --dep-path kasan

View File

@ -51,10 +51,6 @@
#define KASAN_REGION_SIZE(size) \
(sizeof(struct kasan_region_s) + KASAN_SHADOW_SIZE(size))
#ifdef CONFIG_MM_KASAN_GLOBAL
# define KASAN_GLOBAL_SHADOW_SCALE (32)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
@ -74,21 +70,13 @@ static FAR struct kasan_region_s *g_region[CONFIG_MM_KASAN_REGIONS];
static size_t g_region_count;
static spinlock_t g_lock;
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef CONFIG_MM_KASAN_GLOBAL
extern const struct kasan_region_s *g_global_region[];
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
static inline_function FAR uintptr_t *
kasan_mem_to_shadow(FAR const void *ptr, size_t size,
FAR unsigned int *bit, FAR size_t *align)
FAR unsigned int *bit)
{
uintptr_t addr = (uintptr_t)ptr;
size_t i;
@ -99,30 +87,12 @@ kasan_mem_to_shadow(FAR const void *ptr, size_t size,
{
DEBUGASSERT(addr + size <= g_region[i]->end);
addr -= g_region[i]->begin;
*align = KASAN_SHADOW_SCALE;
addr /= KASAN_SHADOW_SCALE;
*bit = addr % KASAN_BITS_PER_WORD;
return &g_region[i]->shadow[addr / KASAN_BITS_PER_WORD];
}
}
#ifdef CONFIG_MM_KASAN_GLOBAL
for (i = 0; g_global_region[i]; i++)
{
if (addr >= g_global_region[i]->begin
&& addr < g_global_region[i]->end)
{
DEBUGASSERT(addr + size <= g_global_region[i]->end);
addr -= g_global_region[i]->begin;
*align = KASAN_GLOBAL_SHADOW_SCALE;
addr /= KASAN_GLOBAL_SHADOW_SCALE;
*bit = addr % KASAN_BITS_PER_WORD;
return (FAR uintptr_t *)
&g_global_region[i]->shadow[addr / KASAN_BITS_PER_WORD];
}
}
#endif
return NULL;
}
@ -133,23 +103,22 @@ kasan_is_poisoned(FAR const void *addr, size_t size)
unsigned int bit;
unsigned int nbit;
uintptr_t mask;
size_t align;
p = kasan_mem_to_shadow(addr, size, &bit, &align);
p = kasan_mem_to_shadow(addr, size, &bit);
if (p == NULL)
{
return false;
return kasan_global_is_poisoned(addr, size);
}
if (size <= align)
if (size <= KASAN_SHADOW_SCALE)
{
return ((*p >> bit) & 1);
}
nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD;
mask = KASAN_FIRST_WORD_MASK(bit);
size = ALIGN_UP(size, align);
size /= align;
size = ALIGN_UP(size, KASAN_SHADOW_SCALE);
size /= KASAN_SHADOW_SCALE;
while (size >= nbit)
{
@ -185,9 +154,8 @@ static void kasan_set_poison(FAR const void *addr, size_t size,
unsigned int bit;
unsigned int nbit;
uintptr_t mask;
size_t align;
p = kasan_mem_to_shadow(addr, size, &bit, &align);
p = kasan_mem_to_shadow(addr, size, &bit);
if (p == NULL)
{
return;
@ -195,7 +163,7 @@ static void kasan_set_poison(FAR const void *addr, size_t size,
nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD;
mask = KASAN_FIRST_WORD_MASK(bit);
size /= align;
size /= KASAN_SHADOW_SCALE;
flags = spin_lock_irqsave(&g_lock);
while (size >= nbit)

138
mm/kasan/global.c Normal file
View File

@ -0,0 +1,138 @@
/****************************************************************************
* mm/kasan/global.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/nuttx.h>
#include <nuttx/mm/kasan.h>
#include <assert.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define KASAN_BYTES_PER_WORD (sizeof(uintptr_t))
#define KASAN_BITS_PER_WORD (KASAN_BYTES_PER_WORD * 8)
#define KASAN_GLOBAL_FIRST_WORD_MASK(start) \
(UINTPTR_MAX << ((start) & (KASAN_BITS_PER_WORD - 1)))
#define KASAN_GLOBAL_LAST_WORD_MASK(end) \
(UINTPTR_MAX >> (-(end) & (KASAN_BITS_PER_WORD - 1)))
#define KASAN_GLOBAL_SHADOW_SCALE (32)
/****************************************************************************
* Private Types
****************************************************************************/
struct kasan_global_region_s
{
uintptr_t begin;
uintptr_t end;
uintptr_t shadow[1];
};
/****************************************************************************
* Public Data
****************************************************************************/
extern const struct kasan_global_region_s *g_global_region[];
/****************************************************************************
* Private Functions
****************************************************************************/
static inline_function FAR uintptr_t *
kasan_global_mem_to_shadow(FAR const void *ptr, size_t size,
FAR unsigned int *bit)
{
uintptr_t addr = (uintptr_t)ptr;
size_t i;
for (i = 0; g_global_region[i]; i++)
{
if (addr >= g_global_region[i]->begin &&
addr < g_global_region[i]->end)
{
DEBUGASSERT(addr + size <= g_global_region[i]->end);
addr -= g_global_region[i]->begin;
addr /= KASAN_GLOBAL_SHADOW_SCALE;
*bit = addr % KASAN_BITS_PER_WORD;
return (FAR uintptr_t *)
&g_global_region[i]->shadow[addr / KASAN_BITS_PER_WORD];
}
}
return NULL;
}
static inline_function bool
kasan_global_is_poisoned(FAR const void *addr, size_t size)
{
FAR uintptr_t *p;
unsigned int bit;
unsigned int nbit;
uintptr_t mask;
p = kasan_global_mem_to_shadow(addr, size, &bit);
if (p == NULL)
{
return false;
}
if (size <= KASAN_GLOBAL_SHADOW_SCALE)
{
return ((*p >> bit) & 1);
}
nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD;
mask = KASAN_GLOBAL_FIRST_WORD_MASK(bit);
size = ALIGN_UP(size, KASAN_GLOBAL_SHADOW_SCALE);
size /= KASAN_GLOBAL_SHADOW_SCALE;
while (size >= nbit)
{
if ((*p++ & mask) != 0)
{
return true;
}
bit += nbit;
size -= nbit;
nbit = KASAN_BITS_PER_WORD;
mask = UINTPTR_MAX;
}
if (size)
{
mask &= KASAN_GLOBAL_LAST_WORD_MASK(bit + size);
if ((*p & mask) != 0)
{
return true;
}
}
return false;
}

View File

@ -32,6 +32,12 @@
#include <stdint.h>
#include <stdio.h>
#ifdef CONFIG_MM_KASAN_GLOBAL
# include "global.c"
#else
# define kasan_global_is_poisoned(addr, size) false
#endif
#ifdef CONFIG_MM_KASAN_GENERIC
# include "generic.c"
#elif defined(CONFIG_MM_KASAN_SW_TAGS)
@ -70,16 +76,6 @@
kasan_check_report(addr, size, true, return_address(0)); \
}
#define DEFINE_HWASAN_LOAD_STORE(size) \
void __hwasan_load##size##_noabort(void *addr) \
{ \
kasan_check_report(addr, size, false, return_address(0)); \
} \
void __hwasan_store##size##_noabort(void *addr) \
{ \
kasan_check_report(addr, size, true, return_address(0)); \
}
#ifdef CONFIG_MM_KASAN_DISABLE_READ_PANIC
# define MM_KASAN_DISABLE_READ_PANIC 1
#else
@ -403,21 +399,3 @@ DEFINE_ASAN_LOAD_STORE(2)
DEFINE_ASAN_LOAD_STORE(4)
DEFINE_ASAN_LOAD_STORE(8)
DEFINE_ASAN_LOAD_STORE(16)
/* Soft tags KASan will instrument the following functions */
void __hwasan_loadN_noabort(FAR void *addr, size_t size)
{
kasan_check_report(addr, size, false, return_address(0));
}
void __hwasan_storeN_noabort(FAR void *addr, size_t size)
{
kasan_check_report(addr, size, true, return_address(0));
}
DEFINE_HWASAN_LOAD_STORE(1)
DEFINE_HWASAN_LOAD_STORE(2)
DEFINE_HWASAN_LOAD_STORE(4)
DEFINE_HWASAN_LOAD_STORE(8)
DEFINE_HWASAN_LOAD_STORE(16)

View File

@ -106,7 +106,7 @@ kasan_is_poisoned(FAR const void *addr, size_t size)
p = kasan_mem_to_shadow(addr, size);
if (p == NULL)
{
return false;
return kasan_global_is_poisoned(addr, size);
}
size = KASAN_SHADOW_SIZE(size);