X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig-hardened-check.py;h=d76a5fa1c3b1ad6eb7a58bc400eea07a9fb493dd;hb=dd40ca5ca2460051eeb61f9f36bc12e4d9b0c375;hp=fa2452652e70c7b4ff155c1fa9d9a133a3d254fd;hpb=4fdae6705916ab457d76d0913d33808d8e22a681;p=kconfig-hardened-check.git diff --git a/kconfig-hardened-check.py b/kconfig-hardened-check.py index fa24526..d76a5fa 100755 --- a/kconfig-hardened-check.py +++ b/kconfig-hardened-check.py @@ -32,22 +32,25 @@ # kpti=on # ssbd=force-on # -# N.B. Hardening sysctl's: -# net.core.bpf_jit_harden +# N.B. Hardening sysctls: +# net.core.bpf_jit_harden=2 # kptr_restrict=2 +# vm.unprivileged_userfaultfd=0 +# kernel.perf_event_paranoid=3 +# kernel.yama.ptrace_scope=1 +# kernel.unprivileged_bpf_disabled=1 import sys from argparse import ArgumentParser from collections import OrderedDict import re +import json debug_mode = False # set it to True to print the unknown options from the config json_mode = False # if True, print results in JSON format supported_archs = [ 'X86_64', 'X86_32', 'ARM64', 'ARM' ] -checklist = [] - class OptCheck: def __init__(self, name, expected, decision, reason): @@ -165,7 +168,7 @@ def detect_arch(fname): return arch, 'OK' -def construct_checklist(arch): +def construct_checklist(checklist, arch): modules_not_set = OptCheck('MODULES', 'is not set', 'kspp', 'cut_attack_surface') devmem_not_set = OptCheck('DEVMEM', 'is not set', 'kspp', 'cut_attack_surface') # refers to LOCK_DOWN_KERNEL @@ -204,12 +207,11 @@ def construct_checklist(arch): checklist.append(OptCheck('SCHED_STACK_END_CHECK', '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('SHUFFLE_PAGE_ALLOCATOR', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('FORTIFY_SOURCE', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('GCC_PLUGINS', 'y', 'kspp', 'self_protection')) randstruct_is_set = OptCheck('GCC_PLUGIN_RANDSTRUCT', 'y', 'kspp', 'self_protection') checklist.append(randstruct_is_set) - checklist.append(OptCheck('GCC_PLUGIN_STRUCTLEAK', 'y', 'kspp', 'self_protection')) - checklist.append(OptCheck('GCC_PLUGIN_STRUCTLEAK_BYREF_ALL', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('GCC_PLUGIN_LATENT_ENTROPY', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('DEBUG_LIST', 'y', 'kspp', 'self_protection')) checklist.append(OptCheck('DEBUG_SG', 'y', 'kspp', 'self_protection')) @@ -268,6 +270,8 @@ def construct_checklist(arch): checklist.append(AND(OptCheck('INTEL_IOMMU_DEFAULT_ON', 'y', 'clipos', 'self_protection'), \ iommu_support_is_set)) + checklist.append(OR(OptCheck('INIT_STACK_ALL', 'y', 'my', 'self_protection'), \ + OptCheck('GCC_PLUGIN_STRUCTLEAK_BYREF_ALL', 'y', 'kspp', 'self_protection'))) if debug_mode or arch == 'X86_64': checklist.append(AND(OptCheck('AMD_IOMMU', 'y', 'my', 'self_protection'), \ iommu_support_is_set)) @@ -375,42 +379,40 @@ def construct_checklist(arch): # checklist.append(OptCheck('LKDTM', 'm', 'my', 'feature_test')) -def print_checks(arch=None): +def print_checklist(checklist, with_results): if json_mode: opts = [] for o in checklist: opt = ['CONFIG_'+o.name, o.expected, o.decision, o.reason] - if not arch: + if with_results: opt.append(o.result) opts.append(opt) - print(opts) - else: - if arch: - print('[+] Printing kernel hardening preferences for {}...'.format(arch)) + print(json.dumps(opts)) + return - # header - print('{:^40}|{:^13}|{:^10}|{:^20}'.format('option name', 'desired val', 'decision', 'reason'), end='') - sep_line_len = 87 - if not arch: - print('||{:^28}'.format('check result'), end='') - sep_line_len = 116 - print() + # header + print('{:^40}|{:^13}|{:^10}|{:^20}'.format('option name', 'desired val', 'decision', 'reason'), end='') + sep_line_len = 86 + if with_results: + print('||{:^28}'.format('check result'), end='') + sep_line_len += 30 + print() - print('=' * sep_line_len) + print('=' * sep_line_len) - for opt in checklist: - print('CONFIG_{:<33}|{:^13}|{:^10}|{:^20}'.format(opt.name, opt.expected, opt.decision, opt.reason), end='') - if not arch: - print('||{:^28}'.format(opt.result), end='') - print() + for opt in checklist: + print('CONFIG_{:<33}|{:^13}|{:^10}|{:^20}'.format(opt.name, opt.expected, opt.decision, opt.reason), end='') + if with_results: + print('||{:^28}'.format(opt.result), end='') print() + print() def get_option_state(options, name): return options.get(name, None) -def perform_checks(parsed_options): +def perform_checks(checklist, parsed_options): for opt in checklist: if hasattr(opt, 'opts'): for o in opt.opts: @@ -420,7 +422,7 @@ def perform_checks(parsed_options): opt.check() -def check_config_file(fname): +def check_config_file(checklist, fname): with open(fname, 'r') as f: parsed_options = OrderedDict() opt_is_on = re.compile("CONFIG_[a-zA-Z0-9_]*=[a-zA-Z0-9_\"]*") @@ -446,7 +448,7 @@ def check_config_file(fname): if option is not None: parsed_options[option] = value - perform_checks(parsed_options) + perform_checks(checklist, parsed_options) if debug_mode: known_options = [opt.name for opt in checklist] @@ -454,10 +456,12 @@ def check_config_file(fname): if option not in known_options: print("DEBUG: dunno about option {} ({})".format(option, value)) - print_checks() + print_checklist(checklist, True) if __name__ == '__main__': + config_checklist = [] + parser = ArgumentParser(description='Checks the hardening options in the Linux kernel config') parser.add_argument('-p', '--print', choices=supported_archs, help='print hardening preferences for selected architecture') @@ -483,10 +487,10 @@ if __name__ == '__main__': elif not json_mode: print('[+] Detected architecture: {}'.format(arch)) - 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))) + construct_checklist(config_checklist, arch) + check_config_file(config_checklist, args.config) + error_count = len(list(filter(lambda opt: opt.result.startswith('FAIL'), config_checklist))) + ok_count = len(list(filter(lambda opt: opt.result.startswith('OK'), config_checklist))) if debug_mode: sys.exit(0) if not json_mode: @@ -495,8 +499,10 @@ if __name__ == '__main__': if args.print: arch = args.print - construct_checklist(arch) - print_checks(arch) + construct_checklist(config_checklist, arch) + if not json_mode: + print('[+] Printing kernel hardening preferences for {}...'.format(arch)) + print_checklist(config_checklist, False) sys.exit(0) parser.print_help()