X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=kernel_hardening_checker%2Fchecks.py;h=fa664e04861f31a4e655842d76bf71495cd9c6ae;hb=78c65e167ec315fcc5d04e5ca2a2194a18f28f67;hp=21f4d2f5316fa6a8090037af5e7b314c8965db45;hpb=cf8d3739c10cd9e6e1b768b0fadd2518f97b9f99;p=kconfig-hardened-check.git diff --git a/kernel_hardening_checker/checks.py b/kernel_hardening_checker/checks.py index 21f4d2f..fa664e0 100644 --- a/kernel_hardening_checker/checks.py +++ b/kernel_hardening_checker/checks.py @@ -26,6 +26,9 @@ def add_kconfig_checks(l, arch): efi_not_set = KconfigCheck('-', '-', 'EFI', 'is not set') cc_is_gcc = KconfigCheck('-', '-', 'CC_IS_GCC', 'y') # exists since v4.18 cc_is_clang = KconfigCheck('-', '-', 'CC_IS_CLANG', 'y') # exists since v4.18 + if arch in ('X86_64', 'X86_32'): + cpu_sup_amd_not_set = KconfigCheck('-', '-', 'CPU_SUP_AMD', 'is not set') + cpu_sup_intel_not_set = KconfigCheck('-', '-', 'CPU_SUP_INTEL', 'is not set') modules_not_set = KconfigCheck('cut_attack_surface', 'kspp', 'MODULES', 'is not set') # radical, but may be useful in some cases devmem_not_set = KconfigCheck('cut_attack_surface', 'kspp', 'DEVMEM', 'is not set') # refers to LOCKDOWN @@ -65,22 +68,26 @@ def add_kconfig_checks(l, arch): 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')] l += [KconfigCheck('self_protection', 'defconfig', 'RETPOLINE', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'SYN_COOKIES', 'y')] # another reason? microcode_is_set = KconfigCheck('self_protection', 'defconfig', 'MICROCODE', 'y') l += [microcode_is_set] # is needed for mitigating CPU bugs l += [OR(KconfigCheck('self_protection', 'defconfig', 'MICROCODE_INTEL', 'y'), + cpu_sup_intel_not_set, AND(microcode_is_set, VersionCheck((6, 6, 0))))] # MICROCODE_INTEL was included in MICROCODE since v6.6 l += [OR(KconfigCheck('self_protection', 'defconfig', 'MICROCODE_AMD', 'y'), + cpu_sup_amd_not_set, AND(microcode_is_set, VersionCheck((6, 6, 0))))] # MICROCODE_AMD was included in MICROCODE since v6.6 l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_SMAP', 'y'), VersionCheck((5, 19, 0)))] # X86_SMAP is enabled by default since v5.19 l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_UMIP', 'y'), KconfigCheck('self_protection', 'defconfig', 'X86_INTEL_UMIP', 'y'))] + l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_MCE_INTEL', 'y'), + cpu_sup_intel_not_set)] + l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_MCE_AMD', 'y'), + cpu_sup_amd_not_set)] if arch in ('ARM64', 'ARM'): l += [KconfigCheck('self_protection', 'defconfig', 'HW_RANDOM_TPM', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'IOMMU_DEFAULT_DMA_STRICT', 'y')] @@ -90,7 +97,8 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('self_protection', 'defconfig', 'PAGE_TABLE_ISOLATION', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'RANDOMIZE_MEMORY', 'y')] l += [KconfigCheck('self_protection', 'defconfig', 'X86_KERNEL_IBT', 'y')] - l += [KconfigCheck('self_protection', 'defconfig', 'CPU_SRSO', 'y')] + l += [OR(KconfigCheck('self_protection', 'defconfig', 'CPU_SRSO', 'y'), + cpu_sup_amd_not_set)] l += [AND(KconfigCheck('self_protection', 'defconfig', 'INTEL_IOMMU', 'y'), iommu_support_is_set)] l += [AND(KconfigCheck('self_protection', 'defconfig', 'AMD_IOMMU', 'y'), @@ -274,7 +282,8 @@ def add_kconfig_checks(l, arch): l += [OR(KconfigCheck('cut_attack_surface', 'defconfig', 'STRICT_DEVMEM', 'y'), devmem_not_set)] # refers to LOCKDOWN if arch in ('X86_64', 'X86_32'): - l += [KconfigCheck('cut_attack_surface', 'defconfig', 'X86_INTEL_TSX_MODE_OFF', 'y')] # tsx=off + l += [OR(KconfigCheck('cut_attack_surface', 'defconfig', 'X86_INTEL_TSX_MODE_OFF', 'y'), + cpu_sup_intel_not_set)] # tsx=off # 'cut_attack_surface', 'kspp' l += [KconfigCheck('cut_attack_surface', 'kspp', 'SECURITY_DMESG_RESTRICT', 'y')] @@ -395,13 +404,13 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'KGDB', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'CORESIGHT', 'is not set')] l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'XFS_SUPPORT_V4', 'is not set')] + l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'MODULE_FORCE_LOAD', 'is not set')] + l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'BLK_DEV_WRITE_MOUNTED', 'is not set')] l += [OR(KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'TRIM_UNUSED_KSYMS', 'y'), modules_not_set)] - l += [KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'MODULE_FORCE_LOAD', 'is not set')] + # 'harden_userspace' - if arch == 'X86_64': - l += [KconfigCheck('harden_userspace', 'defconfig', 'X86_USER_SHADOW_STACK', 'y')] if arch == 'ARM64': l += [KconfigCheck('harden_userspace', 'defconfig', 'ARM64_PTR_AUTH', 'y')] l += [KconfigCheck('harden_userspace', 'defconfig', 'ARM64_BTI', 'y')] @@ -409,6 +418,8 @@ def add_kconfig_checks(l, arch): l += [KconfigCheck('harden_userspace', 'defconfig', 'VMSPLIT_3G', 'y')] l += [KconfigCheck('harden_userspace', 'clipos', 'COREDUMP', 'is not set')] l += [KconfigCheck('harden_userspace', 'a13xp0p0v', 'ARCH_MMAP_RND_BITS', 'MAX')] # 'MAX' value is refined using ARCH_MMAP_RND_BITS_MAX + if arch == 'X86_64': + l += [KconfigCheck('harden_userspace', 'a13xp0p0v', 'X86_USER_SHADOW_STACK', 'y')] def add_cmdline_checks(l, arch): @@ -546,9 +557,12 @@ def add_cmdline_checks(l, arch): # 'cut_attack_surface', 'defconfig' if arch in ('X86_64', 'X86_32'): + tsx_not_set = CmdlineCheck('cut_attack_surface', 'defconfig', 'tsx', 'is not set') l += [OR(CmdlineCheck('cut_attack_surface', 'defconfig', 'tsx', 'off'), AND(KconfigCheck('cut_attack_surface', 'defconfig', 'X86_INTEL_TSX_MODE_OFF', 'y'), - CmdlineCheck('cut_attack_surface', 'defconfig', 'tsx', 'is not set')))] + tsx_not_set), + AND(KconfigCheck('-', '-', 'CPU_SUP_INTEL', 'is not set'), + tsx_not_set))] # 'cut_attack_surface', 'kspp' l += [CmdlineCheck('cut_attack_surface', 'kspp', 'nosmt', 'is present')] # slow (high performance penalty) @@ -577,6 +591,9 @@ def add_cmdline_checks(l, arch): # 'cut_attack_surface', 'a13xp0p0v' l += [CmdlineCheck('cut_attack_surface', 'a13xp0p0v', 'sysrq_always_enabled', 'is not set')] + l += [OR(CmdlineCheck('cut_attack_surface', 'a13xp0p0v', 'bdev_allow_write_mounted', '0'), + AND(KconfigCheck('cut_attack_surface', 'a13xp0p0v', 'BLK_DEV_WRITE_MOUNTED', 'is not set'), + CmdlineCheck('cut_attack_surface', 'a13xp0p0v', 'bdev_allow_write_mounted', 'is not set')))] if arch == 'X86_64': l += [OR(CmdlineCheck('cut_attack_surface', 'a13xp0p0v', 'ia32_emulation', '0'), KconfigCheck('cut_attack_surface', 'kspp', 'IA32_EMULATION', 'is not set'), @@ -646,21 +663,34 @@ def add_sysctl_checks(l, _arch): # Calling the SysctlCheck class constructor: # SysctlCheck(reason, decision, name, expected) - l += [SysctlCheck('self_protection', 'kspp', 'net.core.bpf_jit_harden', '2')] + # Use an omnipresent kconfig symbol to see if we have a kconfig file for checking + have_kconfig = KconfigCheck('-', '-', 'LOCALVERSION', 'is present') + + l += [OR(SysctlCheck('self_protection', 'kspp', 'net.core.bpf_jit_harden', '2'), + AND(KconfigCheck('-', '-', 'BPF_JIT', 'is not set'), + have_kconfig))] l += [SysctlCheck('cut_attack_surface', 'kspp', 'kernel.dmesg_restrict', '1')] l += [SysctlCheck('cut_attack_surface', 'kspp', 'kernel.perf_event_paranoid', '3')] # with a custom patch, see https://lwn.net/Articles/696216/ - l += [SysctlCheck('cut_attack_surface', 'kspp', 'kernel.kexec_load_disabled', '1')] l += [SysctlCheck('cut_attack_surface', 'kspp', 'user.max_user_namespaces', '0')] # may break the upower daemon in Ubuntu l += [SysctlCheck('cut_attack_surface', 'kspp', 'dev.tty.ldisc_autoload', '0')] - l += [SysctlCheck('cut_attack_surface', 'kspp', 'kernel.unprivileged_bpf_disabled', '1')] l += [SysctlCheck('cut_attack_surface', 'kspp', 'kernel.kptr_restrict', '2')] l += [SysctlCheck('cut_attack_surface', 'kspp', 'dev.tty.legacy_tiocsti', '0')] - l += [SysctlCheck('cut_attack_surface', 'kspp', 'vm.unprivileged_userfaultfd', '0')] + l += [OR(SysctlCheck('cut_attack_surface', 'kspp', 'kernel.kexec_load_disabled', '1'), + AND(KconfigCheck('-', '-', 'KEXEC_CORE', 'is not set'), + have_kconfig))] + l += [OR(SysctlCheck('cut_attack_surface', 'kspp', 'kernel.unprivileged_bpf_disabled', '1'), + AND(KconfigCheck('cut_attack_surface', 'lockdown', 'BPF_SYSCALL', 'is not set'), + have_kconfig))] + l += [OR(SysctlCheck('cut_attack_surface', 'kspp', 'vm.unprivileged_userfaultfd', '0'), + AND(KconfigCheck('cut_attack_surface', 'grsec', 'USERFAULTFD', 'is not set'), + have_kconfig))] # At first, it disabled unprivileged userfaultfd, # and since v5.11 it enables unprivileged userfaultfd for user-mode only. - l += [SysctlCheck('cut_attack_surface', 'clipos', 'kernel.modules_disabled', '1')] # radical, but may be useful in some cases + l += [OR(SysctlCheck('cut_attack_surface', 'clipos', 'kernel.modules_disabled', '1'), + AND(KconfigCheck('cut_attack_surface', 'kspp', 'MODULES', 'is not set'), + have_kconfig))] # radical, but may be useful in some cases l += [SysctlCheck('harden_userspace', 'kspp', 'fs.protected_symlinks', '1')] l += [SysctlCheck('harden_userspace', 'kspp', 'fs.protected_hardlinks', '1')]