X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig_hardened_check%2F__init__.py;h=46dc6586013724d626bffcec7970276fd60b4c5e;hb=a637a660d0e08637f19a2bfdbfbef5725568c6b4;hp=1b26a252f6f6253866d30fc900ac60107a1df387;hpb=2b7a15dd055e30baeed5d285711415cebaf39086;p=kconfig-hardened-check.git diff --git a/kconfig_hardened_check/__init__.py b/kconfig_hardened_check/__init__.py index 1b26a25..46dc658 100644 --- a/kconfig_hardened_check/__init__.py +++ b/kconfig_hardened_check/__init__.py @@ -11,11 +11,8 @@ # # # N.B Hardening command line parameters: -# page_alloc.shuffle=1 # iommu=force (does it help against DMA attacks?) -# slub_debug=FZ (slow) # loadpin.enforce=1 -# debugfs=no-mount (or off if possible) # # Mitigations of CPU vulnerabilities: # Аrch-independent: @@ -56,6 +53,7 @@ # vm.unprivileged_userfaultfd=0 # (at first, it disabled unprivileged userfaultfd, # and since v5.11 it enables unprivileged userfaultfd for user-mode only) +# vm.mmap_min_addr has a good value # dev.tty.ldisc_autoload=0 # fs.protected_symlinks=1 # fs.protected_hardlinks=1 @@ -310,6 +308,9 @@ def detect_version(fname): def add_kconfig_checks(l, arch): # Calling the KconfigCheck class constructor: # KconfigCheck(reason, decision, name, expected) + # + # [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results + # when the tool doesn't check the cmdline. modules_not_set = KconfigCheck('cut_attack_surface', 'kspp', 'MODULES', 'is not set') devmem_not_set = KconfigCheck('cut_attack_surface', 'kspp', 'DEVMEM', 'is not set') # refers to LOCKDOWN @@ -646,14 +647,33 @@ def add_kconfig_checks(l, arch): def add_cmdline_checks(l, arch): # Calling the CmdlineCheck class constructor: # CmdlineCheck(reason, decision, name, expected) - # Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results - # when the tool doesn't check the cmdline. + # + # [!] Don't add CmdlineChecks in add_kconfig_checks() to avoid wrong results + # when the tool doesn't check the cmdline. + # + # [!] Make sure that values of the options in CmdlineChecks need normalization. + # For more info see normalize_cmdline_options(). + # + # A common pattern for checking the 'param_x' cmdline parameter + # that __overrides__ the 'PARAM_X_DEFAULT' kconfig option: + # l += [OR(CmdlineCheck(reason, decision, 'param_x', '1'), + # AND(KconfigCheck(reason, decision, 'PARAM_X_DEFAULT_ON', 'y'), + # CmdlineCheck(reason, decision, 'param_x, 'is not set')))] + # + # Here we don't check the kconfig options or minimal kernel version + # required for the cmdline parameters. That would make the checks + # very complex and not give a 100% guarantee anyway. + # 'self_protection', 'defconfig' if arch == 'ARM64': l += [OR(CmdlineCheck('self_protection', 'defconfig', 'rodata', 'full'), AND(KconfigCheck('self_protection', 'defconfig', 'RODATA_FULL_DEFAULT_ENABLED', 'y'), CmdlineCheck('self_protection', 'defconfig', 'rodata', 'is not set')))] + else: + l += [OR(CmdlineCheck('self_protection', 'defconfig', 'rodata', '1'), + CmdlineCheck('self_protection', 'defconfig', 'rodata', 'is not set'))] + # 'self_protection', 'kspp' 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')))] @@ -672,9 +692,13 @@ def add_cmdline_checks(l, arch): l += [OR(CmdlineCheck('self_protection', 'kspp', 'iommu.passthrough', '0'), AND(KconfigCheck('self_protection', 'kspp', 'IOMMU_DEFAULT_PASSTHROUGH', 'is not set'), CmdlineCheck('self_protection', 'kspp', 'iommu.passthrough', 'is not set')))] + # The cmdline checks compatible with the kconfig recommendations of the KSPP project... + l += [OR(CmdlineCheck('self_protection', 'kspp', 'hardened_usercopy', '1'), + AND(KconfigCheck('self_protection', 'kspp', 'HARDENED_USERCOPY', 'y'), + CmdlineCheck('self_protection', 'kspp', 'hardened_usercopy', 'is not set')))] l += [OR(CmdlineCheck('self_protection', 'kspp', 'slab_common.usercopy_fallback', '0'), AND(KconfigCheck('self_protection', 'kspp', 'HARDENED_USERCOPY_FALLBACK', 'is not set'), - CmdlineCheck('self_protection', 'kspp', 'slab_common.usercopy_fallback', 'is not set')))] + CmdlineCheck('self_protection', 'kspp', 'slab_common.usercopy_fallback', 'is not set')))] # ... the end if arch in ('X86_64', 'ARM64', 'X86_32'): l += [OR(CmdlineCheck('self_protection', 'kspp', 'randomize_kstack_offset', '1'), AND(KconfigCheck('self_protection', 'kspp', 'RANDOMIZE_KSTACK_OFFSET_DEFAULT', 'y'), @@ -682,12 +706,19 @@ def add_cmdline_checks(l, arch): if arch in ('X86_64', 'X86_32'): l += [CmdlineCheck('self_protection', 'kspp', 'pti', 'on')] + # 'self_protection', 'clipos' + l += [CmdlineCheck('self_protection', 'clipos', 'page_alloc.shuffle', '1')] + + # 'cut_attack_surface', 'kspp' if arch == 'X86_64': l += [OR(CmdlineCheck('cut_attack_surface', 'kspp', 'vsyscall', 'none'), AND(KconfigCheck('cut_attack_surface', 'kspp', 'LEGACY_VSYSCALL_NONE', 'y'), CmdlineCheck('cut_attack_surface', 'kspp', 'vsyscall', 'is not set')))] - # TODO: add other + # 'cut_attack_surface', 'grsec' + # The cmdline checks compatible with the kconfig options disabled by grsecurity... + l += [OR(CmdlineCheck('cut_attack_surface', 'grsec', 'debugfs', 'off'), + KconfigCheck('cut_attack_surface', 'grsec', 'DEBUG_FS', 'is not set'))] # ... the end def print_unknown_options(checklist, parsed_options): @@ -830,6 +861,26 @@ def parse_kconfig_file(parsed_options, fname): parsed_options[option] = value +def normalize_cmdline_options(option, value): + # Don't normalize the cmdline option values if + # the Linux kernel doesn't use kstrtobool() for them + if option == 'pti': + # See pti_check_boottime_disable() in linux/arch/x86/mm/pti.c + return value + if option == 'debugfs': + # See debugfs_kernel() in fs/debugfs/inode.c + return value + + # Implement a limited part of the kstrtobool() logic + if value in ('1', 'on', 'On', 'ON', 'y', 'Y', 'yes', 'Yes', 'YES'): + return '1' + if value in ('0', 'off', 'Off', 'OFF', 'n', 'N', 'no', 'No', 'NO'): + return '0' + + # Preserve unique values + return value + + def parse_cmdline_file(parsed_options, fname): with open(fname, 'r') as f: line = f.readline() @@ -845,6 +896,7 @@ def parse_cmdline_file(parsed_options, fname): else: name = opt value = '' # '' is not None + value = normalize_cmdline_options(name, value) parsed_options[name] = value