Add cmdline checks to '--print'
[kconfig-hardened-check.git] / kconfig_hardened_check / __init__.py
index 27cbd21b67dfc88cddfd1a36fa853f344ac30db2..7324a9eebaece13b9a0f2800651281f30e4f7251 100644 (file)
 #
 #    Should NOT be set:
 #           nokaslr
+#           rodata=off
+#           sysrq_always_enabled
 #           arm64.nobti
 #           arm64.nopauth
+#           arm64.nomte
 #
 #    Hardware tag-based KASAN with arm64 Memory Tagging Extension (MTE):
 #           kasan=on
 #    what about bpf_jit_enable?
 #    kernel.unprivileged_bpf_disabled=1
 #    net.core.bpf_jit_harden=2
-#
 #    vm.unprivileged_userfaultfd=0
 #        (at first, it disabled unprivileged userfaultfd,
 #         and since v5.11 it enables unprivileged userfaultfd for user-mode only)
-#
 #    dev.tty.ldisc_autoload=0
 #    fs.protected_symlinks=1
 #    fs.protected_hardlinks=1
@@ -70,6 +71,7 @@
 #    fs.protected_regular=2
 #    fs.suid_dumpable=0
 #    kernel.modules_disabled=1
+#    kernel.randomize_va_space = 2
 
 
 # pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
@@ -130,6 +132,12 @@ class OptCheck:
         if with_results:
             print('| {}'.format(self.result), end='')
 
+    def json_dump(self, with_results):
+        dump = [self.name, self.type, self.expected, self.decision, self.reason]
+        if with_results:
+            dump.append(self.result)
+        return dump
+
 
 class KconfigCheck(OptCheck):
     def __init__(self, *args, **kwargs):
@@ -140,11 +148,11 @@ class KconfigCheck(OptCheck):
     def type(self):
         return 'kconfig'
 
-    def json_dump(self, with_results):
-        dump = [self.name, self.type, self.expected, self.decision, self.reason]
-        if with_results:
-            dump.append(self.result)
-        return dump
+
+class CmdlineCheck(OptCheck):
+    @property
+    def type(self):
+        return 'cmdline'
 
 
 class VersionCheck:
@@ -183,7 +191,7 @@ class ComplexOptCheck:
             sys.exit('[!] ERROR: empty {} check'.format(self.__class__.__name__))
         if len(self.opts) == 1:
             sys.exit('[!] ERROR: useless {} check'.format(self.__class__.__name__))
-        if not isinstance(opts[0], KconfigCheck):
+        if not isinstance(opts[0], KconfigCheck) and not isinstance(opts[0], CmdlineCheck):
             sys.exit('[!] ERROR: invalid {} check: {}'.format(self.__class__.__name__, opts))
         self.result = None
 
@@ -631,6 +639,7 @@ def add_kconfig_checks(l, arch):
     l += [KconfigCheck('cut_attack_surface', 'my', 'FTRACE', 'is not set')] # refers to LOCKDOWN
     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')]
 
     # 'harden_userspace'
     if arch in ('X86_64', 'ARM64', 'X86_32'):
@@ -647,6 +656,14 @@ def add_kconfig_checks(l, arch):
 #   l += [KconfigCheck('feature_test', 'my', 'LKDTM', 'm')] # only for debugging!
 
 
+def add_cmdline_checks(l, arch):
+    # Calling the CmdlineCheck class constructor:
+    #     CmdlineCheck(reason, decision, name, expected)
+
+    l += [CmdlineCheck('self_protection', 'kspp', 'randomize_kstack_offset', 'on')]
+    # TODO: add other
+
+
 def print_unknown_options(checklist, parsed_options):
     known_options = []
 
@@ -852,6 +869,7 @@ def main():
             sys.exit('[!] ERROR: wrong mode "{}" for --print'.format(mode))
         arch = args.print
         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_checklist(mode, config_checklist, False)