diff --git a/src/drivers/linker.py b/src/drivers/linker.py index 5b92336..049d27a 100644 --- a/src/drivers/linker.py +++ b/src/drivers/linker.py @@ -22,6 +22,22 @@ def __init__(self, name, file_name): self.file_name = file_name +class SmRel: + def __init__(self, sm, offset, sym): + self.sm = sm + self.rela_offset = offset + self.sym = sym.strip('_') + + def get_sym(self): + return '__sm_{0}_{1}'.format(self.sm, self.sym) + + def get_sect(self): + return '.sm.{0}.text'.format(self.sm) + + def get_rela_sect(self): + return '.rela.sm.{0}.text'.format(self.sm) + + def rename_syms_sects(file, sym_map, sect_map): args = [] for old, new in sym_map.items(): @@ -35,6 +51,18 @@ def rename_syms_sects(file, sym_map, sect_map): return out_file +# The `--add-symbol` option is only available for GNU binutils > msp430-gcc. +# This function therefore relies on msp430-elf-objcopy from the TI GCC port. +def add_sym(file, sym_map): + args = [] + for sym, sect in sym_map.items(): + args += ['--add-symbol', '{0}={1}:0,weak'.format(sym, sect)] + + args += [file, file] + call_prog('msp430-elf-objcopy', args) + return file + + def parse_size(val): try: return int(val) @@ -143,6 +171,10 @@ def sort_key(entry): parser.add_argument('--print-default-libs', help='Print libraries that are always linked', action='store_true') +parser.add_argument('--inline-arithmetic', + help='Intercept and securely inline integer arithmetic ' + 'routines inserted by the compiler back-end', + action='store_true') args, cli_ld_args = parser.parse_known_args() set_args(args) @@ -168,6 +200,7 @@ def sort_key(entry): sms_irq_handlers = defaultdict(list) existing_sms = set() existing_macs = [] +elf_relocations = defaultdict(list) added_set_key_stub = False added_input_stub = False @@ -181,8 +214,8 @@ def sort_key(entry): i += 1 try: - with open(file_name, 'rb') as file: - elf_file = ELFFile(file) + with open(file_name, 'rb') as f: + elf_file = ELFFile(f) for section in elf_file.iter_sections(): name = section.name match = re.match(r'.sm.(\w+).text', name) @@ -210,7 +243,8 @@ def sort_key(entry): # Find call from this SM to others sym = 'null' symtab = elf_file.get_section(section['sh_link']) - for rel in section.iter_relocations(): + for n in range(section.num_relocations()): + rel = section.get_relocation(n) prev_sym = sym sym = symtab.get_symbol(rel['r_info_sym']) @@ -224,6 +258,23 @@ def sort_key(entry): sms_unprotected_calls[sm_name] = set() sms_unprotected_calls[sm_name].add(prev_sym.name) + # Intercept unprotected arithmetic function calls + # inserted by the compiler back-end; see also: + # llvm/lib/Target/MSP430/MSP430ISelLowering.cpp + # llvm/lib/codegen/TargetLoweringBase.cpp + # https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html + ari_match = re.match(r'__(u|)(ashl|ashr|lshr|mul|div|mod)(q|h|s|d|t)i.*', sym.name) + if ari_match and args.inline_arithmetic: + rela_offset = n * section['sh_entsize'] + elf_relocations[file_name].append( + SmRel(sm_name, rela_offset, sym.name)) + elif ari_match: + fatal_error("Arithmetic function call '{0}' " + "detected in SM '{1}'. Use the " + "`--inline-arithmetic` option to securely inline " + "integer arithmetic routines inserted by the " + "compiler back-end.".format( sym.name, sm_name)) + rel_match = re.match(r'__sm_(\w+)_entry$', sym.name) if not rel_match: continue @@ -351,6 +402,65 @@ def sort_key(entry): else: info('No existing Sancus modules found') + +if args.inline_arithmetic: + # create sm_mul asm stub for each unique SM multiplication symbol + sms_relocations = defaultdict(set) + for rels in elf_relocations.values(): + for sm_rel in rels: + sms_relocations[sm_rel.sm].add(sm_rel.sym) + + # resolve dependencies (hack) + for sm, syms in sms_relocations.items(): + if 'divhi3' in syms: + sms_relocations[sm].add('udivhi3') + elif 'modhi3' in syms: + sms_relocations[sm].add('divhi3') + sms_relocations[sm].add('udivhi3') + elif 'umodhi3' in syms: + sms_relocations[sm].add('udivhi3') + + # add asm stubs for final linking step + for sm, syms in sms_relocations.items(): + for sym in syms: + sym_map = {'__sm_mulhi3' : '__sm_{}_mulhi3'.format(sm), + '__sm_divhi3' : '__sm_{}_divhi3'.format(sm), + '__sm_udivhi3' : '__sm_{}_udivhi3'.format(sm), + '__sm_modhi3' : '__sm_{}_modhi3'.format(sm), + '__sm_umodhi3' : '__sm_{}_umodhi3'.format(sm) + } + sect_map = {'.sm.text' : '.sm.{}.text'.format(sm)} + obj = sancus.paths.get_data_path() + '/sm_{}.o'.format(sym) + input_files.append(rename_syms_sects(obj, sym_map, sect_map)) + + for fn in elf_relocations: + # add patched symbol names to infile + sym_map = { sm_rel.get_sym() : sm_rel.get_sect() for + sm_rel in elf_relocations[fn] } + add_sym(fn, sym_map) + + with open(fn, 'r+b') as f: + elf_file = ELFFile(f) + symtab = elf_file.get_section_by_name('.symtab') + + for sm_rel in elf_relocations[fn]: + # calculate relocation offset (file has changed after add_sym) + relasect = elf_file.get_section_by_name(sm_rel.get_rela_sect()) + offset = relasect['sh_offset'] + sm_rel.rela_offset + + # get symbol table index of added symbol + for sym_idx in range(symtab.num_symbols()): + if symtab.get_symbol(sym_idx).name == sm_rel.get_sym(): + break + + # overwrite symbol table index in targeted relocation + # skip r_offset and patch r_info lower byte (litte endian) + info("Patching relocation for symbol '{0}' in SM '{1}' ({2})". + format(sm_rel.get_sym(), sm_rel.sm, fn)) + f.seek(offset+5) + f.write(bytes([sym_idx])) + + # create output sections for the the SM to be inserted in the linker script text_section = '''.text.sm.{0} : {{ diff --git a/src/stubs/CMakeLists.txt b/src/stubs/CMakeLists.txt index c00a3dc..163ebc9 100644 --- a/src/stubs/CMakeLists.txt +++ b/src/stubs/CMakeLists.txt @@ -8,6 +8,12 @@ add_object(sm_isr_dummy.o sm_isr_dummy.s) add_object(sm_exit.o sm_exit.s) add_object(sm_verify.o sm_verify.s) +add_object(sm_mulhi3.o sm_mulhi3.s) +add_object(sm_udivhi3.o sm_udivhi3.s) +add_object(sm_divhi3.o sm_divhi3.s) +add_object(sm_modhi3.o sm_modhi3.s) +add_object(sm_umodhi3.o sm_umodhi3.s) + include(UseSancusCC) set(EXTRA_FLAGS -I${CMAKE_SOURCE_DIR}/src/sancus_support) add_object(sm_output.o sm_output.c ${EXTRA_FLAGS}) @@ -23,6 +29,12 @@ set(STUBS ${CMAKE_CURRENT_BINARY_DIR}/sm_output.o ${CMAKE_CURRENT_BINARY_DIR}/sm_input.o ${CMAKE_CURRENT_BINARY_DIR}/sm_set_key.o + + ${CMAKE_CURRENT_BINARY_DIR}/sm_mulhi3.o + ${CMAKE_CURRENT_BINARY_DIR}/sm_divhi3.o + ${CMAKE_CURRENT_BINARY_DIR}/sm_udivhi3.o + ${CMAKE_CURRENT_BINARY_DIR}/sm_modhi3.o + ${CMAKE_CURRENT_BINARY_DIR}/sm_umodhi3.o ) install(FILES ${STUBS} diff --git a/src/stubs/sm_divhi3.s b/src/stubs/sm_divhi3.s new file mode 100644 index 0000000..f6c3026 --- /dev/null +++ b/src/stubs/sm_divhi3.s @@ -0,0 +1,29 @@ + .section ".sm.text" + .align 2 + .global __sm_divhi3 + .type __sm_divhi3,@function + +__sm_divhi3: + clr r13 + tst r15 + jge 1f + mov #3, r13 + inv r15 + inc r15 +1: tst r14 + jge 2f + xor.b #1, r13 + inv r14 + inc r14 +2: push r13 + call #__sm_udivhi3 + pop r13 + bit.b #2, r13 + jz 3f + inv r14 + inc r14 +3: bit.b #1, r13 + jz 4f + inv r15 + inc r15 +4: ret diff --git a/src/stubs/sm_modhi3.s b/src/stubs/sm_modhi3.s new file mode 100644 index 0000000..3125461 --- /dev/null +++ b/src/stubs/sm_modhi3.s @@ -0,0 +1,9 @@ + .section ".sm.text" + .align 2 + .global __sm_modhi3 + .type __sm_modhi3,@function + +__sm_modhi3: + call #__sm_divhi3 + mov r14, r15 + ret diff --git a/src/stubs/sm_mulhi3.s b/src/stubs/sm_mulhi3.s new file mode 100644 index 0000000..a90f6d8 --- /dev/null +++ b/src/stubs/sm_mulhi3.s @@ -0,0 +1,22 @@ + .section ".sm.text" + .align 2 + .global __sm_mulhi3 + .type __sm_mulhi3,@function + + ; \arg r14: a + ; \arg r15: b + ; \ret r15: a*b + ; \note: clobbers r13 +__sm_mulhi3: + mov r15, r13 + clr r15 +1: tst r14 + jz 3f + clrc + rrc r13 + jnc 2f + add r14, r15 +2: rla r14 + tst r13 + jnz 1b +3: ret diff --git a/src/stubs/sm_udivhi3.s b/src/stubs/sm_udivhi3.s new file mode 100644 index 0000000..b313825 --- /dev/null +++ b/src/stubs/sm_udivhi3.s @@ -0,0 +1,18 @@ + .section ".sm.text" + .align 2 + .global __sm_udivhi3 + .type __sm_udivhi3,@function + +__sm_udivhi3: + mov.b #16, r12 + mov r14, r13 + clr r14 +1: rla r15 + rlc r14 + cmp r13, r14 + jnc 2f + sub r13, r14 + bis #1, r15 +2: dec r12 + jnz 1b + ret diff --git a/src/stubs/sm_umodhi3.s b/src/stubs/sm_umodhi3.s new file mode 100644 index 0000000..de80e13 --- /dev/null +++ b/src/stubs/sm_umodhi3.s @@ -0,0 +1,9 @@ + .section ".sm.text" + .align 2 + .global __sm_umodhi3 + .type __sm_umodhi3,@function + +__sm_umodhi3: + call #__sm_udivhi3 + mov r14, r15 + ret