Skip to content

Commit

Permalink
mm/kasan: Kasan global support setting alignment length
Browse files Browse the repository at this point in the history
1. Similar to asan, supports single byte out of bounds detection
2. Fix the script to address the issue of not supporting the big end

Signed-off-by: wangmingrong1 <[email protected]>
  • Loading branch information
W-M-R authored and xiaoxiang781216 committed Sep 20, 2024
1 parent 0d8b6de commit 469418f
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 35 deletions.
2 changes: 1 addition & 1 deletion arch/arm/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ define LINK_ALLSYMS_KASAN
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
$(Q) $(call DELFILE, allsyms.tmp))
$(if $(CONFIG_MM_KASAN_GLOBAL),
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp -a $(CONFIG_MM_KASAN_GLOBAL_ALIGN)
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
$(Q) $(call DELFILE, kasan_globals.tmp))
$(Q) $(LD) $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ define LINK_ALLSYMS_KASAN
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
$(Q) $(call DELFILE, allsyms.tmp))
$(if $(CONFIG_MM_KASAN_GLOBAL),
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp -a $(CONFIG_MM_KASAN_GLOBAL_ALIGN)
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
$(Q) $(call DELFILE, kasan_globals.tmp))
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
Expand Down
2 changes: 1 addition & 1 deletion arch/risc-v/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ define LINK_ALLSYMS_KASAN
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
$(Q) $(call DELFILE, allsyms.tmp))
$(if $(CONFIG_MM_KASAN_GLOBAL),
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp -a $(CONFIG_MM_KASAN_GLOBAL_ALIGN)
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
$(Q) $(call DELFILE, kasan_globals.tmp))
$(Q) $(LD) $(LDENTRY) $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
Expand Down
2 changes: 1 addition & 1 deletion arch/sim/src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ define LINK_ALLSYMS_KASAN
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
$(Q) $(call DELFILE, allsyms.tmp))
$(if $(CONFIG_MM_KASAN_GLOBAL),
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp -a $(CONFIG_MM_KASAN_GLOBAL_ALIGN)
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
$(Q) $(call DELFILE, kasan_globals.tmp))
$(if $(CONFIG_HAVE_CXX),\
Expand Down
8 changes: 8 additions & 0 deletions mm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ config MM_KASAN_GLOBAL
KEEP ( *(. data. rel. local.. LASAN0))
}", used to extract data generated by the compiler

if MM_KASAN_GLOBAL

config MM_KASAN_GLOBAL_ALIGN
int "KASan global alignment"
default 32

endif # MM_KASAN_GLOBAL

config MM_KASAN_DISABLE_READ_PANIC
bool "Disable panic on kasan read error"
default n
Expand Down
10 changes: 4 additions & 6 deletions mm/kasan/global.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
#define KASAN_GLOBAL_LAST_WORD_MASK(end) \
(UINTPTR_MAX >> (-(end) & (KASAN_BITS_PER_WORD - 1)))

#define KASAN_GLOBAL_SHADOW_SCALE (32)

/****************************************************************************
* Private Types
****************************************************************************/
Expand Down Expand Up @@ -77,7 +75,7 @@ kasan_global_mem_to_shadow(FAR const void *ptr, size_t size,
{
DEBUGASSERT(addr + size <= g_global_region[i]->end);
addr -= g_global_region[i]->begin;
addr /= KASAN_GLOBAL_SHADOW_SCALE;
addr /= CONFIG_MM_KASAN_GLOBAL_ALIGN;
*bit = addr % KASAN_BITS_PER_WORD;
return (FAR uintptr_t *)
&g_global_region[i]->shadow[addr / KASAN_BITS_PER_WORD];
Expand All @@ -101,15 +99,15 @@ kasan_global_is_poisoned(FAR const void *addr, size_t size)
return false;
}

if (size <= KASAN_GLOBAL_SHADOW_SCALE)
if (size <= CONFIG_MM_KASAN_GLOBAL_ALIGN)
{
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;
size = ALIGN_UP(size, CONFIG_MM_KASAN_GLOBAL_ALIGN);
size /= CONFIG_MM_KASAN_GLOBAL_ALIGN;

while (size >= nbit)
{
Expand Down
83 changes: 58 additions & 25 deletions tools/kasan_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@

debug = False

# N-byte aligned shadow area 1 bit
KASAN_GLOBAL_ALIGN = 32

# The maximum gap that two data segments can tolerate
KASAN_MAX_DATA_GAP = 1 << 16

Expand Down Expand Up @@ -68,10 +65,11 @@

# Global configuration information
class Config:
def __init__(self, outpath, elf, ldscript):
def __init__(self, outpath, elf, ldscript, align):
self.outpath = outpath
self.elf = elf
self.ldscript = ldscript
self.align = align

if self.elf is None or os.path.exists(self.elf) is False:
self.elf = None
Expand All @@ -97,43 +95,73 @@ def __init__(self, outpath, elf, ldscript):


class KASanRegion:
def __init__(self, start, end) -> None:
def __init__(self, start, end, align, endian, bitwides) -> None:
self.start = start
self.end = end
self.size = int((end - start) // KASAN_GLOBAL_ALIGN // 8) + 1
self.shadow = bytearray(b"\x00" * self.size)

def mark_bit(self, index, nbits):
self.shadow[index] |= 1 << nbits
self.align = align
self.endian = endian
self.bitwides = bitwides
self.size = int((end - start) // self.align // self.bitwides) + 1
self.__shadow = [0] * self.size

def shadow(self) -> bytearray:
ret = bytearray()
for i in self.__shadow:
for j in range(self.bitwides // 8):
if self.endian == "little":
ret.append((i >> (j * 8)) & 0xFF)
else:
ret.append((i >> ((self.bitwides // 8 - j - 1) * 8)) & 0xFF)
return ret

def mark_bit(self, index, nbit, nbits):
for i in range(nbits):
self.__shadow[index] |= 1 << nbit
nbit += 1
if nbit == self.bitwides:
index += 1
nbit = 0

def poison(self, dict):
dict_size = dict["size"]
if dict_size % 32:
dict_size = int((dict_size + 31) // 32) * 32
if dict_size % self.align:
dict_size = int((dict_size + self.align - 1) // self.align) * self.align

distance = (dict["beg"] + dict_size - self.start) // self.align

# Index of the marked shadow area
index = int(distance // self.bitwides)

# The X-th bit of the specific byte marked
nbit = distance % self.bitwides

# Number of digits to be marked
nbits = (dict["size_with_redzone"] - dict_size) // self.align

distance = (dict["beg"] + dict_size - self.start) // KASAN_GLOBAL_ALIGN
index = int(distance // 8)
nbits = distance % 8
if debug:
print(
"regin: %08x addr: %08x size: %d bits: %d || poison index: %d nbits: %d"
"regin: %08x addr: %08x size: %d bits: %d || poison index: %d nbit: %d nbits: %d"
% (
self.start,
dict["beg"],
dict["size"],
int(dict["size_with_redzone"] // KASAN_GLOBAL_ALIGN),
int(dict["size_with_redzone"] // self.align),
index,
nbit,
nbits,
)
)

# Using 32bytes: with 1bit alignment,
# only one bit of inaccessible area exists for each pair of global variables.
self.mark_bit(index, nbits)
self.mark_bit(index, nbit, nbits)


class KASanInfo:
def __init__(self) -> None:
def __init__(self, align, endian, bitwides) -> None:
self.align = align
self.endian = endian
self.bitwides = bitwides
# Record the starting position of the merged data block
self.data_sections = []
# Record the kasan region corresponding to each data block
Expand All @@ -158,13 +186,15 @@ def create_region(self):
end = i[1]
if debug:
print("KAsan Shadow Block: %08x ---- %08x" % (start, end))
self.regions.append(KASanRegion(start, end))
self.regions.append(
KASanRegion(start, end, self.align, self.endian, self.bitwides)
)

def mark_shadow(self, dict):
for i in self.regions:
start = i.start
end = i.end
if start <= dict["beg"] and dict["beg"] <= end:
if start <= dict["beg"] and dict["beg"] + dict["size_with_redzone"] <= end:
i.poison(dict)
break

Expand Down Expand Up @@ -227,10 +257,11 @@ def create_kasan_file(config: Config, region_list=[]):
% (long_to_bytestring(config.bitwides, config.endian, region.end))
)

for j in range(len(region.shadow)):
shadow = region.shadow()
for j in range(len(shadow)):
if j % 8 == 0:
file.write("\n")
file.write("0x%02x, " % (region.shadow[j]))
file.write("0x%02x, " % (shadow[j]))

file.write("\n};")

Expand All @@ -253,6 +284,7 @@ def parse_args() -> Config:
global debug
parser = argparse.ArgumentParser(description="Build kasan global variable region")
parser.add_argument("-o", "--outpath", help="outpath")
parser.add_argument("-a", "--align", default=32, type=int, help="alignment")
parser.add_argument("-d", "--ldscript", help="ld script path(Only support sim)")
parser.add_argument("-e", "--elffile", help="elffile")
parser.add_argument(
Expand All @@ -264,10 +296,11 @@ def parse_args() -> Config:

args = parser.parse_args()
debug = args.debug
return Config(args.outpath, args.elffile, args.ldscript)
return Config(args.outpath, args.elffile, args.ldscript, args.align)


def main():

config = parse_args()
if config.elf is None:
handle_error(config)
Expand Down Expand Up @@ -298,7 +331,7 @@ def main():
dict_list = sorted(dict_list, key=lambda item: item["beg"])

# Merge all global variables to obtain several segments of the distribution range
kasan = KASanInfo()
kasan = KASanInfo(config.align, config.endian, config.bitwides)
for i in dict_list:
kasan.merge_ranges(i)

Expand Down

0 comments on commit 469418f

Please sign in to comment.