X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig_hardened_check%2F__init__.py;h=9bfb52f3520b6b2c3a39bbd7f7e75219867e4256;hb=40df99601f46d3c3eba273248e0ebacb30897463;hp=797e3e08cf824b309d7da9890b7808c36d9fa482;hpb=8877e263e1801802f54dbf6b1b4bf892f5adcc3e;p=kconfig-hardened-check.git diff --git a/kconfig_hardened_check/__init__.py b/kconfig_hardened_check/__init__.py index 797e3e0..9bfb52f 100644 --- a/kconfig_hardened_check/__init__.py +++ b/kconfig_hardened_check/__init__.py @@ -10,18 +10,10 @@ # Please don't cry if my Python code looks like C. # # -# N.B Missing hardening command line parameters: -# iommu=force (does it help against DMA attacks?) -# -# Hardware tag-based KASAN with arm64 Memory Tagging Extension (MTE): -# kasan=on -# kasan.stacktrace=off -# kasan.fault=panic -# # N.B. Hardening sysctls: # kernel.kptr_restrict=2 (or 1?) # kernel.dmesg_restrict=1 (also see the kconfig option) -# kernel.perf_event_paranoid=3 +# kernel.perf_event_paranoid=2 (or 3 with a custom patch, see https://lwn.net/Articles/696216/) # kernel.kexec_load_disabled=1 # kernel.yama.ptrace_scope=3 # user.max_user_namespaces=0 @@ -59,29 +51,29 @@ SIMPLE_OPTION_TYPES = ('kconfig', 'version', 'cmdline') class OptCheck: def __init__(self, reason, decision, name, expected): assert(name and name == name.strip() and len(name.split()) == 1), \ - 'invalid name "{}" for {}'.format(name, self.__class__.__name__) + f'invalid name "{name}" for {self.__class__.__name__}' self.name = name assert(decision and decision == decision.strip() and len(decision.split()) == 1), \ - 'invalid decision "{}" for "{}" check'.format(decision, name) + f'invalid decision "{decision}" for "{name}" check' self.decision = decision assert(reason and reason == reason.strip() and len(reason.split()) == 1), \ - 'invalid reason "{}" for "{}" check'.format(reason, name) + f'invalid reason "{reason}" for "{name}" check' self.reason = reason assert(expected and expected == expected.strip()), \ - 'invalid expected value "{}" for "{}" check (1)'.format(expected, name) + f'invalid expected value "{expected}" for "{name}" check (1)' val_len = len(expected.split()) if val_len == 3: - assert(expected == 'is not set' or expected == 'is not off'), \ - 'invalid expected value "{}" for "{}" check (2)'.format(expected, name) + assert(expected in ('is not set', 'is not off')), \ + f'invalid expected value "{expected}" for "{name}" check (2)' elif val_len == 2: assert(expected == 'is present'), \ - 'invalid expected value "{}" for "{}" check (3)'.format(expected, name) + f'invalid expected value "{expected}" for "{name}" check (3)' else: assert(val_len == 1), \ - 'invalid expected value "{}" for "{}" check (4)'.format(expected, name) + f'invalid expected value "{expected}" for "{name}" check (4)' self.expected = expected self.state = None @@ -124,9 +116,9 @@ class OptCheck: self.result = 'FAIL: "' + self.state + '"' def table_print(self, _mode, with_results): - print('{:<40}|{:^7}|{:^12}|{:^10}|{:^18}'.format(self.name, self.type, self.expected, self.decision, self.reason), end='') + print(f'{self.name:<40}|{self.type:^7}|{self.expected:^12}|{self.decision:^10}|{self.reason:^18}', end='') if with_results: - print('| {}'.format(self.result), end='') + print(f'| {self.result}', end='') def json_dump(self, with_results): dump = [self.name, self.type, self.expected, self.decision, self.reason] @@ -154,7 +146,7 @@ class CmdlineCheck(OptCheck): class VersionCheck: def __init__(self, ver_expected): assert(ver_expected and isinstance(ver_expected, tuple) and len(ver_expected) == 2), \ - 'invalid version "{}" for VersionCheck'.format(ver_expected) + f'invalid version "{ver_expected}" for VersionCheck' self.ver_expected = ver_expected self.ver = () self.result = None @@ -177,20 +169,20 @@ class VersionCheck: def table_print(self, _mode, with_results): ver_req = 'kernel version >= ' + str(self.ver_expected[0]) + '.' + str(self.ver_expected[1]) - print('{:<91}'.format(ver_req), end='') + print(f'{ver_req:<91}', end='') if with_results: - print('| {}'.format(self.result), end='') + print(f'| {self.result}', end='') class ComplexOptCheck: def __init__(self, *opts): self.opts = opts assert(self.opts), \ - 'empty {} check'.format(self.__class__.__name__) + f'empty {self.__class__.__name__} check' assert(len(self.opts) != 1), \ - 'useless {} check: {}'.format(self.__class__.__name__, opts) + f'useless {self.__class__.__name__} check: {opts}' assert(isinstance(opts[0], (KconfigCheck, CmdlineCheck))), \ - 'invalid {} check: {}'.format(self.__class__.__name__, opts) + f'invalid {self.__class__.__name__} check: {opts}' self.result = None @property @@ -207,9 +199,9 @@ class ComplexOptCheck: def table_print(self, mode, with_results): if mode == 'verbose': - print(' {:87}'.format('<<< ' + self.__class__.__name__ + ' >>>'), end='') + print(f" {'<<< ' + self.__class__.__name__ + ' >>>':87}", end='') if with_results: - print('| {}'.format(self.result), end='') + print(f'| {self.result}', end='') for o in self.opts: print() o.table_print(mode, with_results) @@ -217,7 +209,7 @@ class ComplexOptCheck: o = self.opts[0] o.table_print(mode, False) if with_results: - print('| {}'.format(self.result), end='') + print(f'| {self.result}', end='') def json_dump(self, with_results): dump = self.opts[0].json_dump(False) @@ -249,7 +241,7 @@ class OR(ComplexOptCheck): else: # VersionCheck provides enough info assert(opt.result.startswith('OK: version')), \ - 'unexpected OK description "{}"'.format(opt.result) + f'unexpected OK description "{opt.result}"' return self.result = self.opts[0].result @@ -274,7 +266,7 @@ class AND(ComplexOptCheck): self.result = 'FAIL: {} is not "{}"'.format(opt.name, opt.expected) elif opt.result == 'FAIL: is not present': self.result = 'FAIL: {} is not present'.format(opt.name) - elif opt.result == 'FAIL: is off' or opt.result == 'FAIL: is off, "0"': + elif opt.result in ('FAIL: is off', 'FAIL: is off, "0"'): self.result = 'FAIL: {} is off'.format(opt.name) elif opt.result == 'FAIL: is off, not found': self.result = 'FAIL: {} is off, not found'.format(opt.name) @@ -282,7 +274,7 @@ class AND(ComplexOptCheck): # VersionCheck provides enough info self.result = opt.result assert(opt.result.startswith('FAIL: version')), \ - 'unexpected FAIL description "{}"'.format(opt.result) + f'unexpected FAIL description "{opt.result}"' return @@ -378,9 +370,11 @@ def add_kconfig_checks(l, arch): VersionCheck((5, 5)))] # REFCOUNT_FULL is enabled by default since v5.5 if arch in ('X86_64', 'ARM64', 'X86_32'): l += [KconfigCheck('self_protection', 'defconfig', 'RANDOMIZE_BASE', 'y')] - if arch in ('X86_64', 'ARM64'): + if arch in ('X86_64', 'ARM64', 'ARM'): l += [KconfigCheck('self_protection', 'defconfig', 'VMAP_STACK', 'y')] if arch in ('X86_64', 'X86_32'): + l += [KconfigCheck('self_protection', 'defconfig', 'DEBUG_WX', 'y')] + l += [KconfigCheck('self_protection', 'defconfig', 'WERROR', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'X86_MCE', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'X86_MCE_INTEL', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'X86_MCE_AMD', 'y')] @@ -392,6 +386,8 @@ def add_kconfig_checks(l, arch): l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_UMIP', 'y'), KconfigCheck('self_protection', 'defconfig', 'X86_INTEL_UMIP', 'y'))] if arch in ('ARM64', 'ARM'): + l += [KconfigCheck('self_protection', 'defconfig', 'IOMMU_DEFAULT_DMA_STRICT', 'y')] + l += [KconfigCheck('self_protection', 'defconfig', 'IOMMU_DEFAULT_PASSTHROUGH', 'is not set')] # true if IOMMU_DEFAULT_DMA_STRICT is set l += [KconfigCheck('self_protection', 'defconfig', 'STACKPROTECTOR_PER_TASK', 'y')] if arch == 'X86_64': l += [KconfigCheck('self_protection', 'defconfig', 'PAGE_TABLE_ISOLATION', 'y')] @@ -423,7 +419,6 @@ def add_kconfig_checks(l, arch): # 'self_protection', 'kspp' l += [KconfigCheck('self_protection', 'kspp', 'BUG_ON_DATA_CORRUPTION', 'y')] - l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_WX', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'SCHED_STACK_END_CHECK', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'SLAB_FREELIST_HARDENED', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'SLAB_FREELIST_RANDOM', 'y')] @@ -436,13 +431,9 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_NOTIFIERS', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'INIT_ON_ALLOC_DEFAULT_ON', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'KFENCE', 'y')] - l += [KconfigCheck('self_protection', 'kspp', 'WERROR', 'y')] - l += [KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_DMA_STRICT', 'y')] - l += [KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_PASSTHROUGH', 'is not set')] # true if IOMMU_DEFAULT_DMA_STRICT is set l += [KconfigCheck('self_protection', 'kspp', 'ZERO_CALL_USED_REGS', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'HW_RANDOM_TPM', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'STATIC_USERMODEHELPER', 'y')] # needs userspace support - l += [KconfigCheck('self_protection', 'kspp', 'SCHED_CORE', 'y')] randstruct_is_set = OR(KconfigCheck('self_protection', 'kspp', 'RANDSTRUCT_FULL', 'y'), KconfigCheck('self_protection', 'kspp', 'GCC_PLUGIN_RANDSTRUCT', 'y')) l += [randstruct_is_set] @@ -509,10 +500,15 @@ def add_kconfig_checks(l, arch): l += [AND(KconfigCheck('self_protection', 'kspp', 'CFI_PERMISSIVE', 'is not set'), cfi_clang_is_set)] if arch in ('X86_64', 'X86_32'): + l += [KconfigCheck('self_protection', 'kspp', 'SCHED_CORE', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'DEFAULT_MMAP_MIN_ADDR', '65536')] + l += [KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_DMA_STRICT', 'y')] + l += [KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_PASSTHROUGH', 'is not set')] # true if IOMMU_DEFAULT_DMA_STRICT is set l += [AND(KconfigCheck('self_protection', 'kspp', 'INTEL_IOMMU_DEFAULT_ON', 'y'), iommu_support_is_set)] if arch in ('ARM64', 'ARM'): + l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_WX', 'y')] + l += [KconfigCheck('self_protection', 'kspp', 'WERROR', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'DEFAULT_MMAP_MIN_ADDR', '32768')] l += [KconfigCheck('self_protection', 'kspp', 'SYN_COOKIES', 'y')] # another reason? if arch == 'X86_64': @@ -524,7 +520,7 @@ def add_kconfig_checks(l, arch): if arch == 'ARM64': l += [KconfigCheck('self_protection', 'kspp', 'ARM64_SW_TTBR0_PAN', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'SHADOW_CALL_STACK', 'y')] - l += [KconfigCheck('self_protection', 'kspp', 'KASAN_HW_TAGS', 'y')] + l += [KconfigCheck('self_protection', 'kspp', 'KASAN_HW_TAGS', 'y')] # see also: kasan=on, kasan.stacktrace=off, kasan.fault=panic if arch == 'X86_32': l += [KconfigCheck('self_protection', 'kspp', 'PAGE_TABLE_ISOLATION', 'y')] l += [KconfigCheck('self_protection', 'kspp', 'HIGHMEM64G', 'y')] @@ -573,8 +569,10 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('cut_attack_surface', 'kspp', 'PROC_KCORE', 'is not set')] # refers to LOCKDOWN l += [KconfigCheck('cut_attack_surface', 'kspp', 'LEGACY_PTYS', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'HIBERNATION', 'is not set')] # refers to LOCKDOWN + l += [KconfigCheck('cut_attack_surface', 'kspp', 'COMPAT', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'IA32_EMULATION', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'X86_X32', 'is not set')] + l += [KconfigCheck('cut_attack_surface', 'kspp', 'X86_X32_ABI', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'MODIFY_LDT_SYSCALL', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'OABI_COMPAT', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'X86_MSR', 'is not set')] # refers to LOCKDOWN @@ -637,6 +635,8 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('cut_attack_surface', 'maintainer', 'VT', 'is not set')] # recommended by Daniel Vetter in /issues/38 l += [KconfigCheck('cut_attack_surface', 'maintainer', 'BLK_DEV_FD', 'is not set')] # recommended by Denis Efremov in /pull/54 l += [KconfigCheck('cut_attack_surface', 'maintainer', 'BLK_DEV_FD_RAWCMD', 'is not set')] # recommended by Denis Efremov in /pull/62 + l += [KconfigCheck('cut_attack_surface', 'maintainer', 'NOUVEAU_LEGACY_CTX_SUPPORT', 'is not set')] + # recommended by Dave Airlie in kernel commit b30a43ac7132cdda # 'cut_attack_surface', 'clipos' l += [KconfigCheck('cut_attack_surface', 'clipos', 'STAGING', 'is not set')] @@ -668,6 +668,7 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('cut_attack_surface', 'my', 'VIDEO_VIVID', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'my', 'INPUT_EVBUG', 'is not set')] # Can be used as a keylogger l += [KconfigCheck('cut_attack_surface', 'my', 'KGDB', 'is not set')] + l += [KconfigCheck('cut_attack_surface', 'my', 'AIO', 'is not set')] l += [OR(KconfigCheck('cut_attack_surface', 'my', 'TRIM_UNUSED_KSYMS', 'y'), modules_not_set)] @@ -719,8 +720,6 @@ def add_cmdline_checks(l, arch): l += [CmdlineCheck('self_protection', 'defconfig', 'arm64.nobti', 'is not set')] l += [CmdlineCheck('self_protection', 'defconfig', 'arm64.nopauth', 'is not set')] l += [CmdlineCheck('self_protection', 'defconfig', 'arm64.nomte', 'is not set')] - l += [OR(CmdlineCheck('self_protection', 'defconfig', 'mitigations', 'is not off'), - CmdlineCheck('self_protection', 'defconfig', 'mitigations', 'is not set'))] l += [OR(CmdlineCheck('self_protection', 'defconfig', 'spectre_v2', 'is not off'), CmdlineCheck('self_protection', 'defconfig', 'spectre_v2', 'is not set'))] l += [OR(CmdlineCheck('self_protection', 'defconfig', 'spectre_v2_user', 'is not off'), @@ -741,6 +740,8 @@ def add_cmdline_checks(l, arch): CmdlineCheck('self_protection', 'defconfig', 'retbleed', 'is not set'))] l += [OR(CmdlineCheck('self_protection', 'defconfig', 'kpti', 'is not off'), CmdlineCheck('self_protection', 'defconfig', 'kpti', 'is not set'))] + l += [OR(CmdlineCheck('self_protection', 'defconfig', 'kvm.nx_huge_pages', 'is not off'), + CmdlineCheck('self_protection', 'defconfig', 'kvm.nx_huge_pages', 'is not set'))] if arch == 'ARM64': l += [OR(CmdlineCheck('self_protection', 'defconfig', 'ssbd', 'kernel'), CmdlineCheck('self_protection', 'my', 'ssbd', 'force-on'), @@ -754,6 +755,7 @@ def add_cmdline_checks(l, arch): # 'self_protection', 'kspp' l += [CmdlineCheck('self_protection', 'kspp', 'nosmt', 'is present')] + l += [CmdlineCheck('self_protection', 'kspp', 'mitigations', 'auto,nosmt')] # 'nosmt' by kspp + 'auto' by defconfig l += [OR(CmdlineCheck('self_protection', 'kspp', 'init_on_alloc', '1'), AND(KconfigCheck('self_protection', 'kspp', 'INIT_ON_ALLOC_DEFAULT_ON', 'y'), CmdlineCheck('self_protection', 'kspp', 'init_on_alloc', 'is not set')))] @@ -765,7 +767,8 @@ def add_cmdline_checks(l, arch): CmdlineCheck('self_protection', 'kspp', 'slub_debug', 'P')))] l += [OR(CmdlineCheck('self_protection', 'kspp', 'slab_nomerge', 'is present'), AND(KconfigCheck('self_protection', 'clipos', 'SLAB_MERGE_DEFAULT', 'is not set'), - CmdlineCheck('self_protection', 'kspp', 'slab_merge', 'is not set')))] + CmdlineCheck('self_protection', 'kspp', 'slab_merge', 'is not set'), + CmdlineCheck('self_protection', 'clipos', 'slub_merge', 'is not set')))] l += [OR(CmdlineCheck('self_protection', 'kspp', 'iommu.strict', '1'), AND(KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_DMA_STRICT', 'y'), CmdlineCheck('self_protection', 'kspp', 'iommu.strict', 'is not set')))] @@ -790,6 +793,8 @@ def add_cmdline_checks(l, arch): # 'self_protection', 'clipos' l += [CmdlineCheck('self_protection', 'clipos', 'page_alloc.shuffle', '1')] + if arch in ('X86_64', 'X86_32'): + l += [CmdlineCheck('self_protection', 'clipos', 'iommu', 'force')] # 'cut_attack_surface', 'defconfig' if arch in ('X86_64', 'X86_32'): @@ -825,13 +830,13 @@ def print_unknown_options(checklist, parsed_options): continue for o3 in o2.opts: assert(o3.type != 'complex'), \ - 'unexpected ComplexOptCheck inside {}'.format(o2.name) + f'unexpected ComplexOptCheck inside {o2.name}' if hasattr(o3, 'name'): known_options.append(o3.name) for option, value in parsed_options.items(): if option not in known_options: - print('[?] No check for option {} ({})'.format(option, value)) + print(f'[?] No check for option {option} ({value})') def print_checklist(mode, checklist, with_results): @@ -847,9 +852,9 @@ def print_checklist(mode, checklist, with_results): if with_results: sep_line_len += 30 print('=' * sep_line_len) - print('{:^40}|{:^7}|{:^12}|{:^10}|{:^18}'.format('option name', 'type', 'desired val', 'decision', 'reason'), end='') + print(f"{'option name':^40}|{'type':^7}|{'desired val':^12}|{'decision':^10}|{'reason':^18}", end='') if with_results: - print('| {}'.format('check result'), end='') + print('| check result', end='') print() print('=' * sep_line_len) @@ -879,16 +884,16 @@ def print_checklist(mode, checklist, with_results): if mode == 'show_fail': ok_suppressed = ' (suppressed in output)' if mode != 'json': - print('[+] Config check is finished: \'OK\' - {}{} / \'FAIL\' - {}{}'.format(ok_count, ok_suppressed, fail_count, fail_suppressed)) + print(f'[+] Config check is finished: \'OK\' - {ok_count}{ok_suppressed} / \'FAIL\' - {fail_count}{fail_suppressed}') def populate_simple_opt_with_data(opt, data, data_type): assert(opt.type != 'complex'), \ - 'unexpected ComplexOptCheck "{}"'.format(opt.name) + f'unexpected ComplexOptCheck "{opt.name}"' assert(opt.type in SIMPLE_OPTION_TYPES), \ - 'invalid opt type "{}"'.format(opt.type) + f'invalid opt type "{opt.type}"' assert(data_type in SIMPLE_OPTION_TYPES), \ - 'invalid data type "{}"'.format(data_type) + f'invalid data type "{data_type}"' if data_type != opt.type: return @@ -897,7 +902,7 @@ def populate_simple_opt_with_data(opt, data, data_type): opt.state = data.get(opt.name, None) else: assert(data_type == 'version'), \ - 'unexpected data type "{}"'.format(data_type) + f'unexpected data type "{data_type}"' opt.ver = data @@ -911,7 +916,7 @@ def populate_opt_with_data(opt, data, data_type): populate_simple_opt_with_data(o, data, data_type) else: assert(opt.type in ('kconfig', 'cmdline')), \ - 'bad type "{}" for a simple check'.format(opt.type) + f'bad type "{opt.type}" for a simple check' populate_simple_opt_with_data(opt, data, data_type) @@ -1048,7 +1053,7 @@ def main(): if args.mode: mode = args.mode if mode != 'json': - print('[+] Special report mode: {}'.format(mode)) + print(f'[+] Special report mode: {mode}') config_checklist = [] @@ -1057,28 +1062,28 @@ def main(): sys.exit('[!] ERROR: --config and --print can\'t be used together') if mode != 'json': - print('[+] Kconfig file to check: {}'.format(args.config)) + print(f'[+] Kconfig file to check: {args.config}') if args.cmdline: - print('[+] Kernel cmdline file to check: {}'.format(args.cmdline)) + print(f'[+] Kernel cmdline file to check: {args.cmdline}') arch, msg = detect_arch(args.config, supported_archs) if not arch: sys.exit('[!] ERROR: {}'.format(msg)) if mode != 'json': - print('[+] Detected architecture: {}'.format(arch)) + print(f'[+] Detected architecture: {arch}') kernel_version, msg = detect_kernel_version(args.config) if not kernel_version: sys.exit('[!] ERROR: {}'.format(msg)) if mode != 'json': - print('[+] Detected kernel version: {}.{}'.format(kernel_version[0], kernel_version[1])) + print(f'[+] Detected kernel version: {kernel_version[0]}.{kernel_version[1]}') compiler, msg = detect_compiler(args.config) if mode != 'json': if compiler: - print('[+] Detected compiler: {}'.format(compiler)) + print(f'[+] Detected compiler: {compiler}') else: - print('[-] Can\'t detect the compiler: {}'.format(msg)) + print(f'[-] Can\'t detect the compiler: {msg}') # add relevant kconfig checks to the checklist add_kconfig_checks(config_checklist, arch) @@ -1099,12 +1104,17 @@ def main(): parse_cmdline_file(parsed_cmdline_options, args.cmdline) populate_with_data(config_checklist, parsed_cmdline_options, 'cmdline') - # now everything is ready for performing the checks + # now everything is ready, perform the checks perform_checks(config_checklist) - # finally print the results if mode == 'verbose': - print_unknown_options(config_checklist, parsed_kconfig_options) + # print the parsed options without the checks (for debugging) + all_parsed_options = parsed_kconfig_options # assignment does not copy + if args.cmdline: + all_parsed_options.update(parsed_cmdline_options) + print_unknown_options(config_checklist, all_parsed_options) + + # finally print the results print_checklist(mode, config_checklist, True) sys.exit(0) @@ -1118,7 +1128,7 @@ def main(): add_kconfig_checks(config_checklist, arch) add_cmdline_checks(config_checklist, arch) if mode != 'json': - print('[+] Printing kernel security hardening preferences for {}...'.format(arch)) + print(f'[+] Printing kernel security hardening preferences for {arch}...') print_checklist(mode, config_checklist, False) sys.exit(0)