X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig-hardened-check.py;h=64f6efb5a94a0a63d006df94f47c0b7c061440b9;hb=a6b4f7ae9d5a8b17c9553b9f7851e2007ab823f1;hp=d9ffba637eec4b9ef603f74bb2b742b209bcbbfe;hpb=47226fe77ab14311a172343d3e306264d9062d88;p=kconfig-hardened-check.git diff --git a/kconfig-hardened-check.py b/kconfig-hardened-check.py index d9ffba6..64f6efb 100755 --- a/kconfig-hardened-check.py +++ b/kconfig-hardened-check.py @@ -68,14 +68,11 @@ class OptCheck: return '{} = {}'.format(self.name, self.state) -class OR: +class ComplexOptCheck: def __init__(self, *opts): self.opts = opts self.result = None - # self.opts[0] is the option which this OR-check is about. - # Use case: OR(, ) - @property def name(self): return self.opts[0].name @@ -96,10 +93,20 @@ class OR: def reason(self): return self.opts[0].reason + +class OR(ComplexOptCheck): + # self.opts[0] is the option which this OR-check is about. + # Use case: + # OR(, ) + # OR(, ) + def check(self): + if not self.opts: + sys.exit('[!] ERROR: invalid OR check') + for i, opt in enumerate(self.opts): - result, msg = opt.check() - if result: + ret, msg = opt.check() + if ret: if i == 0: self.result = opt.result else: @@ -109,6 +116,24 @@ class OR: return False, self.result +class AND(ComplexOptCheck): + # self.opts[0] is the option which this AND-check is about. + # Use case: AND(, ) + # Suboption is not checked if checking of the main_option is failed. + + def check(self): + for i, opt in reversed(list(enumerate(self.opts))): + ret, msg = opt.check() + if i == 0: + self.result = opt.result + return ret, self.result + elif not ret: + # The requirement is not met. Skip the check. + return False, '' + + sys.exit('[!] ERROR: invalid AND check') + + def detect_arch(fname): with open(fname, 'r') as f: arch_pattern = re.compile("CONFIG_[a-zA-Z0-9_]*=y") @@ -166,11 +191,8 @@ def construct_checklist(arch): checklist.append(OptCheck('BUG_ON_DATA_CORRUPTION', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('DEBUG_WX', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('SCHED_STACK_END_CHECK', 'y', 'kspp', 'self_protection')) - checklist.append(OptCheck('PAGE_POISONING', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('SLAB_FREELIST_HARDENED', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('SLAB_FREELIST_RANDOM', 'y', 'kspp', 'self_protection')) - checklist.append(OptCheck('HARDENED_USERCOPY', 'y', 'kspp', 'self_protection')) - checklist.append(OptCheck('HARDENED_USERCOPY_FALLBACK', 'is not set', 'kspp', 'self_protection')) checklist.append(OptCheck('FORTIFY_SOURCE', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('GCC_PLUGINS', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('GCC_PLUGIN_RANDSTRUCT', 'y', 'kspp', 'self_protection')) @@ -181,6 +203,12 @@ def construct_checklist(arch): checklist.append(OptCheck('DEBUG_SG', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('DEBUG_CREDENTIALS', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('DEBUG_NOTIFIERS', 'y', 'kspp', 'self_protection')) + page_poisoning_is_set = OptCheck('PAGE_POISONING', 'y', 'kspp', 'self_protection') + checklist.append(page_poisoning_is_set) + hardened_usercopy_is_set = OptCheck('HARDENED_USERCOPY', 'y', 'kspp', 'self_protection') + checklist.append(hardened_usercopy_is_set) + checklist.append(AND(OptCheck('HARDENED_USERCOPY_FALLBACK', 'is not set', 'kspp', 'self_protection'), \ + hardened_usercopy_is_set)) checklist.append(OR(OptCheck('MODULE_SIG', 'y', 'kspp', 'self_protection'), \ modules_not_set)) checklist.append(OR(OptCheck('MODULE_SIG_ALL', 'y', 'kspp', 'self_protection'), \ @@ -210,9 +238,11 @@ def construct_checklist(arch): checklist.append(OptCheck('STATIC_USERMODEHELPER', 'y', 'my', 'self_protection')) # needs userspace support (systemd) checklist.append(OptCheck('SECURITY_LOADPIN', 'y', 'my', 'self_protection')) # needs userspace support checklist.append(OptCheck('RESET_ATTACK_MITIGATION', 'y', 'my', 'self_protection')) # needs userspace support (systemd) - checklist.append(OptCheck('PAGE_POISONING_NO_SANITY', 'is not set', 'my', 'self_protection')) - checklist.append(OptCheck('PAGE_POISONING_ZERO', 'is not set', 'my', 'self_protection')) checklist.append(OptCheck('SLAB_MERGE_DEFAULT', 'is not set', 'my', 'self_protection')) # slab_nomerge + checklist.append(AND(OptCheck('PAGE_POISONING_NO_SANITY', 'is not set', 'my', 'self_protection'), \ + page_poisoning_is_set)) + checklist.append(AND(OptCheck('PAGE_POISONING_ZERO', 'is not set', 'my', 'self_protection'), \ + page_poisoning_is_set)) if debug_mode or arch == 'X86_32': checklist.append(OptCheck('PAGE_TABLE_ISOLATION', 'y', 'my', 'self_protection')) @@ -229,6 +259,8 @@ def construct_checklist(arch): checklist.append(OR(OptCheck('STRICT_DEVMEM', 'y', 'defconfig', 'cut_attack_surface'), \ devmem_not_set)) # refers to LOCK_DOWN_KERNEL + checklist.append(modules_not_set) + checklist.append(devmem_not_set) checklist.append(OR(OptCheck('IO_STRICT_DEVMEM', 'y', 'kspp', 'cut_attack_surface'), \ devmem_not_set)) # refers to LOCK_DOWN_KERNEL if debug_mode or arch == 'ARM': @@ -312,8 +344,9 @@ def print_check_results(): 'option name', 'desired val', 'decision', 'reason', 'check result')) print(' ' + '=' * 115) for opt in checklist: - print(' CONFIG_{:<32}|{:^13}|{:^10}|{:^20}||{:^28}'.format( - opt.name, opt.expected, opt.decision, opt.reason, opt.result)) + if opt.result: + print(' CONFIG_{:<32}|{:^13}|{:^10}|{:^20}||{:^28}'.format( + opt.name, opt.expected, opt.decision, opt.reason, opt.result)) print() @@ -389,14 +422,12 @@ if __name__ == '__main__': construct_checklist(arch) check_config_file(args.config) - error_count = len(list(filter(lambda opt: opt.result.startswith('FAIL'), checklist))) + error_count = len(list(filter(lambda opt: opt.result and opt.result.startswith('FAIL'), checklist))) + ok_count = len(list(filter(lambda opt: opt.result and opt.result.startswith('OK'), checklist))) if debug_mode: sys.exit(0) - if error_count == 0: - print('[+] config check is PASSED') - sys.exit(0) - else: - sys.exit('[-] config check is NOT PASSED: {} errors'.format(error_count)) + print('[+] config check is finished: \'OK\' - {} / \'FAIL\' - {}'.format(ok_count, error_count)) + sys.exit(0) if args.print: arch = args.print