mm/kasan: Kasan global support setting alignment length
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 <wangmingrong1@xiaomi.com>
This commit is contained in:
parent
0d8b6de03a
commit
469418f3c9
@ -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) \
|
||||
|
@ -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) \
|
||||
|
@ -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) \
|
||||
|
@ -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),\
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
@ -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];
|
||||
@ -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)
|
||||
{
|
||||
|
@ -29,9 +29,6 @@ from elftools.elf.elffile import ELFFile
|
||||
|
||||
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
|
||||
|
||||
@ -68,10 +65,11 @@ KASAN_GLOBAL_STRUCT_64 = Struct(
|
||||
|
||||
# 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
|
||||
@ -97,43 +95,73 @@ class Config:
|
||||
|
||||
|
||||
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)
|
||||
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 mark_bit(self, index, nbits):
|
||||
self.shadow[index] |= 1 << nbits
|
||||
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
|
||||
@ -158,13 +186,15 @@ class KASanInfo:
|
||||
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
|
||||
|
||||
@ -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};")
|
||||
|
||||
@ -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(
|
||||
@ -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)
|
||||
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user