X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig-hardened-check.py;h=f39995deb4a449f674680301324feede187b9f69;hb=d9aca2d28e9f95266bca2da09625d7d2c885a6b2;hp=fea5ef958b6eeec515cc9172cea07e825f6e86ca;hpb=30b0806bc19a138618027b75e9223f50076f8ca8;p=kconfig-hardened-check.git diff --git a/kconfig-hardened-check.py b/kconfig-hardened-check.py index fea5ef9..f39995d 100755 --- a/kconfig-hardened-check.py +++ b/kconfig-hardened-check.py @@ -68,16 +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(, ) - # OR(, ) - @property def name(self): return self.opts[0].name @@ -98,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: @@ -111,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: + self.result = 'FAIL: CONFIG_{} is needed'.format(opt.name) + return False, self.result + + 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") @@ -168,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')) @@ -183,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'), \ @@ -212,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')) @@ -394,13 +422,11 @@ if __name__ == '__main__': construct_checklist(arch) check_config_file(args.config) error_count = len(list(filter(lambda opt: opt.result.startswith('FAIL'), checklist))) + ok_count = len(list(filter(lambda opt: 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