Update the self-protection checks adopted by KSPP (part II)
[kconfig-hardened-check.git] / kconfig_hardened_check / __init__.py
index 859a5082dcf1cc153386584e7dcaae1adb06e71e..6ccea34b93beb36a8f6375123d06de4ea48b351f 100644 (file)
 #
 # N.B Hardening command line parameters:
 #    iommu=force (does it help against DMA attacks?)
-#    loadpin.enforce=1
 #
 #    Mitigations of CPU vulnerabilities:
 #       Аrch-independent:
 #           mitigations=auto,nosmt (nosmt is slow)
 #       X86:
-#           spectre_v2=on
 #           spec_store_bypass_disable=on
 #           l1tf=full,force
 #           l1d_flush=on (a part of the l1tf option)
@@ -366,6 +364,9 @@ def add_kconfig_checks(l, arch):
     if arch in ('X86_64', 'ARM64'):
         l += [KconfigCheck('self_protection', 'defconfig', 'VMAP_STACK', 'y')]
     if arch in ('X86_64', 'X86_32'):
+        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', 'MICROCODE', 'y')] # is needed for mitigating CPU bugs
         l += [KconfigCheck('self_protection', 'defconfig', 'RETPOLINE', 'y')]
         l += [OR(KconfigCheck('self_protection', 'defconfig', 'X86_SMAP', 'y'),
@@ -411,6 +412,7 @@ def add_kconfig_checks(l, arch):
     l += [KconfigCheck('self_protection', 'kspp', 'SHUFFLE_PAGE_ALLOCATOR', 'y')]
     l += [KconfigCheck('self_protection', 'kspp', 'FORTIFY_SOURCE', 'y')]
     l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_LIST', 'y')]
+    l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_VIRTUAL', 'y')]
     l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_SG', 'y')]
     l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_CREDENTIALS', 'y')]
     l += [KconfigCheck('self_protection', 'kspp', 'DEBUG_NOTIFIERS', 'y')]
@@ -422,9 +424,14 @@ def add_kconfig_checks(l, arch):
     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
     randstruct_is_set = OR(KconfigCheck('self_protection', 'kspp', 'RANDSTRUCT_FULL', 'y'),
                            KconfigCheck('self_protection', 'kspp', 'GCC_PLUGIN_RANDSTRUCT', 'y'))
     l += [randstruct_is_set]
+    l += [AND(KconfigCheck('self_protection', 'kspp', 'RANDSTRUCT_PERFORMANCE', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'GCC_PLUGIN_RANDSTRUCT_PERFORMANCE', 'is not set'),
+              randstruct_is_set)]
     hardened_usercopy_is_set = KconfigCheck('self_protection', 'kspp', 'HARDENED_USERCOPY', 'y')
     l += [hardened_usercopy_is_set]
     l += [AND(KconfigCheck('self_protection', 'kspp', 'HARDENED_USERCOPY_FALLBACK', 'is not set'),
@@ -448,9 +455,34 @@ def add_kconfig_checks(l, arch):
              # Starting from v5.11 CONFIG_PAGE_POISONING unconditionally checks
              # the 0xAA poison pattern on allocation.
              # That brings higher performance penalty.
+    l += [OR(KconfigCheck('self_protection', 'kspp', 'EFI_DISABLE_PCI_DMA', 'y'),
+             efi_not_set)]
+    l += [OR(KconfigCheck('self_protection', 'kspp', 'RESET_ATTACK_MITIGATION', 'y'),
+             efi_not_set)] # needs userspace support (systemd)
+    ubsan_bounds_is_set = KconfigCheck('self_protection', 'kspp', 'UBSAN_BOUNDS', 'y')
+    l += [ubsan_bounds_is_set]
+    l += [OR(KconfigCheck('self_protection', 'kspp', 'UBSAN_LOCAL_BOUNDS', 'y'),
+             AND(ubsan_bounds_is_set,
+                 cc_is_gcc))]
+    l += [AND(KconfigCheck('self_protection', 'kspp', 'UBSAN_TRAP', 'y'),
+              ubsan_bounds_is_set,
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_SHIFT', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_DIV_ZERO', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_UNREACHABLE', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_BOOL', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_ENUM', 'is not set'),
+              KconfigCheck('self_protection', 'kspp', 'UBSAN_ALIGNMENT', 'is not set'))] # only array index bounds checking with traps
     if arch in ('X86_64', 'ARM64', 'X86_32'):
+        l += [AND(KconfigCheck('self_protection', 'kspp', 'UBSAN_SANITIZE_ALL', 'y'),
+                  ubsan_bounds_is_set)] # ARCH_HAS_UBSAN_SANITIZE_ALL is not enabled for ARM
         stackleak_is_set = KconfigCheck('self_protection', 'kspp', 'GCC_PLUGIN_STACKLEAK', 'y')
         l += [AND(stackleak_is_set, gcc_plugins_support_is_set)]
+        l += [AND(KconfigCheck('self_protection', 'kspp', 'STACKLEAK_METRICS', 'is not set'),
+                  stackleak_is_set,
+                  gcc_plugins_support_is_set)]
+        l += [AND(KconfigCheck('self_protection', 'kspp', 'STACKLEAK_RUNTIME_DISABLE', 'is not set'),
+                  stackleak_is_set,
+                  gcc_plugins_support_is_set)]
         l += [KconfigCheck('self_protection', 'kspp', 'RANDOMIZE_KSTACK_OFFSET_DEFAULT', 'y')]
     if arch in ('X86_64', 'X86_32'):
         l += [KconfigCheck('self_protection', 'kspp', 'SCHED_CORE', 'y')]
@@ -465,33 +497,8 @@ def add_kconfig_checks(l, arch):
         l += [KconfigCheck('self_protection', 'kspp', 'HIGHMEM64G', 'y')]
         l += [KconfigCheck('self_protection', 'kspp', 'X86_PAE', 'y')]
 
-    # 'self_protection', 'maintainer'
-    ubsan_bounds_is_set = KconfigCheck('self_protection', 'maintainer', 'UBSAN_BOUNDS', 'y') # only array index bounds checking
-    l += [ubsan_bounds_is_set] # recommended by Kees Cook in /issues/53
-    if arch in ('X86_64', 'ARM64', 'X86_32'):  # ARCH_HAS_UBSAN_SANITIZE_ALL is not enabled for ARM
-        l += [AND(KconfigCheck('self_protection', 'maintainer', 'UBSAN_SANITIZE_ALL', 'y'),
-                  ubsan_bounds_is_set)] # recommended by Kees Cook in /issues/53
-    l += [AND(KconfigCheck('self_protection', 'maintainer', 'UBSAN_TRAP', 'y'),
-              ubsan_bounds_is_set)] # recommended by Kees Cook in /issues/53
-
     # 'self_protection', 'clipos'
-    l += [KconfigCheck('self_protection', 'clipos', 'DEBUG_VIRTUAL', 'y')]
-    l += [KconfigCheck('self_protection', 'clipos', 'STATIC_USERMODEHELPER', 'y')] # needs userspace support
-    l += [OR(KconfigCheck('self_protection', 'clipos', 'EFI_DISABLE_PCI_DMA', 'y'),
-             efi_not_set)]
     l += [KconfigCheck('self_protection', 'clipos', 'SLAB_MERGE_DEFAULT', 'is not set')]
-    l += [KconfigCheck('self_protection', 'clipos', 'RANDOM_TRUST_BOOTLOADER', 'is not set')]
-    l += [KconfigCheck('self_protection', 'clipos', 'RANDOM_TRUST_CPU', 'is not set')]
-    l += [AND(KconfigCheck('self_protection', 'clipos', 'RANDSTRUCT_PERFORMANCE', 'is not set'),
-              KconfigCheck('self_protection', 'clipos', 'GCC_PLUGIN_RANDSTRUCT_PERFORMANCE', 'is not set'),
-              randstruct_is_set)]
-    if arch in ('X86_64', 'ARM64', 'X86_32'):
-        l += [AND(KconfigCheck('self_protection', 'clipos', 'STACKLEAK_METRICS', 'is not set'),
-                  stackleak_is_set,
-                  gcc_plugins_support_is_set)]
-        l += [AND(KconfigCheck('self_protection', 'clipos', 'STACKLEAK_RUNTIME_DISABLE', 'is not set'),
-                  stackleak_is_set,
-                  gcc_plugins_support_is_set)]
     if arch in ('X86_64', 'X86_32'):
         l += [AND(KconfigCheck('self_protection', 'clipos', 'INTEL_IOMMU_DEFAULT_ON', 'y'),
                   iommu_support_is_set)]
@@ -503,11 +510,6 @@ def add_kconfig_checks(l, arch):
                   iommu_support_is_set)]
 
     # 'self_protection', 'my'
-    l += [OR(KconfigCheck('self_protection', 'my', 'RESET_ATTACK_MITIGATION', 'y'),
-             efi_not_set)] # needs userspace support (systemd)
-    l += [OR(KconfigCheck('self_protection', 'my', 'UBSAN_LOCAL_BOUNDS', 'y'),
-             AND(ubsan_bounds_is_set,
-                 cc_is_gcc))]
     if arch == 'X86_64':
         l += [KconfigCheck('self_protection', 'my', 'SLS', 'y')] # vs CVE-2021-26341 in Straight-Line-Speculation
         l += [AND(KconfigCheck('self_protection', 'my', 'AMD_IOMMU_V2', 'y'),
@@ -528,15 +530,12 @@ def add_kconfig_checks(l, arch):
     l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_YAMA', 'y')]
     l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_LANDLOCK', 'y')]
     l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_SELINUX_DISABLE', 'is not set')]
-    l += [KconfigCheck('security_policy', 'clipos', 'SECURITY_LOCKDOWN_LSM', 'y')]
-    l += [KconfigCheck('security_policy', 'clipos', 'SECURITY_LOCKDOWN_LSM_EARLY', 'y')]
-    l += [KconfigCheck('security_policy', 'clipos', 'LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY', 'y')]
-    l += [KconfigCheck('security_policy', 'my', 'SECURITY_WRITABLE_HOOKS', 'is not set')] # refers to SECURITY_SELINUX_DISABLE
-    l += [KconfigCheck('security_policy', 'my', 'SECURITY_SAFESETID', 'y')]
-    loadpin_is_set = KconfigCheck('security_policy', 'my', 'SECURITY_LOADPIN', 'y')
-    l += [loadpin_is_set] # needs userspace support
-    l += [AND(KconfigCheck('security_policy', 'my', 'SECURITY_LOADPIN_ENFORCE', 'y'),
-              loadpin_is_set)]
+    l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_SELINUX_BOOTPARAM', 'is not set')]
+    l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_SELINUX_DEVELOP', 'is not set')]
+    l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_LOCKDOWN_LSM', 'y')]
+    l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_LOCKDOWN_LSM_EARLY', 'y')]
+    l += [KconfigCheck('security_policy', 'kspp', 'LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY', 'y')]
+    l += [KconfigCheck('security_policy', 'kspp', 'SECURITY_WRITABLE_HOOKS', 'is not set')] # refers to SECURITY_SELINUX_DISABLE
 
     # 'cut_attack_surface', 'defconfig'
     l += [OR(KconfigCheck('cut_attack_surface', 'defconfig', 'BPF_UNPRIV_DEFAULT_OFF', 'y'),
@@ -638,6 +637,7 @@ def add_kconfig_checks(l, arch):
     l += [KconfigCheck('cut_attack_surface', 'clipos', 'X86_IOPL_IOPERM', 'is not set')] # refers to LOCKDOWN
     l += [KconfigCheck('cut_attack_surface', 'clipos', 'ACPI_TABLE_UPGRADE', 'is not set')] # refers to LOCKDOWN
     l += [KconfigCheck('cut_attack_surface', 'clipos', 'EFI_CUSTOM_SSDT_OVERLAYS', 'is not set')]
+    l += [KconfigCheck('cut_attack_surface', 'clipos', 'COREDUMP', 'is not set')] # cut userspace attack surface
     l += [AND(KconfigCheck('cut_attack_surface', 'clipos', 'LDISC_AUTOLOAD', 'is not set'),
               KconfigCheck('cut_attack_surface', 'clipos', 'LDISC_AUTOLOAD'))] # option presence check
     if arch in ('X86_64', 'X86_32'):
@@ -700,7 +700,10 @@ def add_cmdline_checks(l, arch):
     # 'self_protection', 'defconfig'
     l += [CmdlineCheck('self_protection', 'defconfig', 'nosmep', 'is not set')]
     l += [CmdlineCheck('self_protection', 'defconfig', 'nosmap', 'is not set')]
+    l += [CmdlineCheck('self_protection', 'defconfig', 'nokaslr', 'is not set')]
+    l += [CmdlineCheck('self_protection', 'defconfig', 'nopti', 'is not set')]
     l += [CmdlineCheck('self_protection', 'defconfig', 'nospectre_v1', 'is not set')]
+    l += [CmdlineCheck('self_protection', 'defconfig', 'nospectre_v2', 'is not set')]
     if arch == 'ARM64':
         l += [OR(CmdlineCheck('self_protection', 'defconfig', 'rodata', 'full'),
                  AND(KconfigCheck('self_protection', 'defconfig', 'RODATA_FULL_DEFAULT_ENABLED', 'y'),
@@ -729,24 +732,26 @@ def add_cmdline_checks(l, arch):
              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 += [CmdlineCheck('self_protection', 'kspp', 'nokaslr', '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', 'X86_32'):
-        l += [AND(CmdlineCheck('self_protection', 'kspp', 'pti', 'on'),
-                  CmdlineCheck('self_protection', 'kspp', 'nopti', 'is not set'))] # ... the end
+    # ... 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'),
                      CmdlineCheck('self_protection', 'kspp', 'randomize_kstack_offset', 'is not set')))]
+    if arch in ('X86_64', 'X86_32'):
+        l += [AND(CmdlineCheck('self_protection', 'kspp', 'pti', 'on'),
+                  CmdlineCheck('self_protection', 'defconfig', 'nopti', 'is not set'))]
 
     # 'self_protection', 'clipos'
     l += [CmdlineCheck('self_protection', 'clipos', 'page_alloc.shuffle', '1')]
-
+    if arch in ('X86_64', 'X86_32'):
+        l += [AND(CmdlineCheck('self_protection', 'clipos', 'spectre_v2', 'on'),
+                  CmdlineCheck('self_protection', 'defconfig', 'nospectre_v2', 'is not set'))]
 
     # 'cut_attack_surface', 'kspp'
     if arch == 'X86_64':
@@ -906,6 +911,9 @@ def normalize_cmdline_options(option, value):
     if option == 'pti':
         # See pti_check_boottime_disable() in linux/arch/x86/mm/pti.c
         return value
+    if option == 'spectre_v2':
+        # See spectre_v2_parse_cmdline() in linux/arch/x86/kernel/cpu/bugs.c
+        return value
     if option == 'debugfs':
         # See debugfs_kernel() in fs/debugfs/inode.c
         return value