X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kconfig_hardened_check%2F__init__.py;h=0367d88094b22ea8e779e2146841ed7dd18270b0;hb=e9fa43330ce69e7b532c845b01ec61d626ed206a;hp=3daddcbdaba5a860789ffacf1366c7dc49efbae6;hpb=5d007e67c6db0af09c6cf5a303cfea23e4234403;p=kconfig-hardened-check.git diff --git a/kconfig_hardened_check/__init__.py b/kconfig_hardened_check/__init__.py index 3daddcb..0367d88 100644 --- a/kconfig_hardened_check/__init__.py +++ b/kconfig_hardened_check/__init__.py @@ -56,6 +56,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 +311,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 @@ -321,7 +325,10 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('self_protection', 'defconfig', 'SLUB_DEBUG', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'GCC_PLUGINS', 'y')] l += [OR(KconfigCheck('self_protection', 'defconfig', 'STACKPROTECTOR', 'y'), - KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR', 'y'))] + KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR', 'y'), + KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR_REGULAR', 'y'), + KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR_AUTO', 'y'), + KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR_STRONG', 'y'))] l += [OR(KconfigCheck('self_protection', 'defconfig', 'STACKPROTECTOR_STRONG', 'y'), KconfigCheck('self_protection', 'defconfig', 'CC_STACKPROTECTOR_STRONG', 'y'))] l += [OR(KconfigCheck('self_protection', 'defconfig', 'STRICT_KERNEL_RWX', 'y'), @@ -375,7 +382,6 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('self_protection', 'defconfig', 'HARDEN_BRANCH_HISTORY', 'y')] # 'self_protection', 'kspp' - l += [KconfigCheck('self_protection', 'kspp', 'SECURITY_DMESG_RESTRICT', 'y')] 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')] @@ -512,6 +518,7 @@ def add_kconfig_checks(l, arch): devmem_not_set)] # refers to LOCKDOWN # 'cut_attack_surface', 'kspp' + l += [KconfigCheck('cut_attack_surface', 'kspp', 'SECURITY_DMESG_RESTRICT', 'y')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'ACPI_CUSTOM_METHOD', 'is not set')] # refers to LOCKDOWN l += [KconfigCheck('cut_attack_surface', 'kspp', 'COMPAT_BRK', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'kspp', 'DEVKMEM', 'is not set')] # refers to LOCKDOWN @@ -643,13 +650,30 @@ 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. 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'))] l += [OR(CmdlineCheck('self_protection', 'kspp', 'init_on_alloc', '1'), AND(KconfigCheck('self_protection', 'kspp', 'INIT_ON_ALLOC_DEFAULT_ON', 'y'), @@ -669,6 +693,12 @@ 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')))] + 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')))] 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'), @@ -824,6 +854,24 @@ def parse_kconfig_file(parsed_options, fname): parsed_options[option] = value +def normalize_cmdline_options(option, value): + # Handle special cases + if option == 'pti': + # Don't normalize the pti value since + # the Linux kernel doesn't use kstrtobool() for pti. + # See pti_check_boottime_disable() in linux/arch/x86/mm/pti.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() @@ -839,6 +887,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