Drop `if __name__ == "__main__"` from ./bin/kconfig-hardened-check
[kconfig-hardened-check.git] / kconfig_hardened_check / engine.py
index 8a4ccb8519dbe76323d1feb3dc527201f9ac6127..2e86ef307f1eea244fa593dc5899f095b578c35b 100644 (file)
@@ -1,9 +1,7 @@
 #!/usr/bin/python3
 
 """
-This tool helps me to check Linux kernel options against
-my security hardening preferences for X86_64, ARM64, X86_32, and ARM.
-Let the computers do their job!
+This tool is for checking the security hardening options of the Linux kernel.
 
 Author: Alexander Popov <alex.popov@linux.com>
 
@@ -45,10 +43,6 @@ class OptCheck:
         self.state = None
         self.result = None
 
-    @property
-    def type(self):
-        return None
-
     def check(self):
         # handle the 'is present' check
         if self.expected == 'is present':
@@ -109,6 +103,12 @@ class CmdlineCheck(OptCheck):
         return 'cmdline'
 
 
+class SysctlCheck(OptCheck):
+    @property
+    def type(self):
+        return 'sysctl'
+
+
 class VersionCheck:
     def __init__(self, ver_expected):
         assert(ver_expected and isinstance(ver_expected, tuple) and len(ver_expected) == 2), \
@@ -147,7 +147,7 @@ class ComplexOptCheck:
                f'empty {self.__class__.__name__} check'
         assert(len(self.opts) != 1), \
                f'useless {self.__class__.__name__} check: {opts}'
-        assert(isinstance(opts[0], (KconfigCheck, CmdlineCheck))), \
+        assert(isinstance(opts[0], (KconfigCheck, CmdlineCheck, SysctlCheck))), \
                f'invalid {self.__class__.__name__} check: {opts}'
         self.result = None
 
@@ -244,7 +244,7 @@ class AND(ComplexOptCheck):
                 return
 
 
-SIMPLE_OPTION_TYPES = ('kconfig', 'version', 'cmdline')
+SIMPLE_OPTION_TYPES = ('kconfig', 'cmdline', 'sysctl', 'version')
 
 
 def populate_simple_opt_with_data(opt, data, data_type):
@@ -255,12 +255,12 @@ def populate_simple_opt_with_data(opt, data, data_type):
     assert(data_type in SIMPLE_OPTION_TYPES), \
            f'invalid data type "{data_type}"'
     assert(data), \
-           f'empty data'
+           'empty data'
 
     if data_type != opt.type:
         return
 
-    if data_type in ('kconfig', 'cmdline'):
+    if data_type in ('kconfig', 'cmdline', 'sysctl'):
         opt.state = data.get(opt.name, None)
     else:
         assert(data_type == 'version'), \
@@ -269,17 +269,16 @@ def populate_simple_opt_with_data(opt, data, data_type):
 
 
 def populate_opt_with_data(opt, data, data_type):
-    if opt.type == 'complex':
+    assert(opt.type != 'version'), 'a single VersionCheck is useless'
+    if opt.type != 'complex':
+        populate_simple_opt_with_data(opt, data, data_type)
+    else:
         for o in opt.opts:
-            if o.type == 'complex':
+            if o.type != 'complex':
+                populate_simple_opt_with_data(o, data, data_type)
+            else:
                 # Recursion for nested ComplexOptCheck objects
                 populate_opt_with_data(o, data, data_type)
-            else:
-                populate_simple_opt_with_data(o, data, data_type)
-    else:
-        assert(opt.type in ('kconfig', 'cmdline')), \
-               f'bad type "{opt.type}" for a simple check'
-        populate_simple_opt_with_data(opt, data, data_type)
 
 
 def populate_with_data(checklist, data, data_type):
@@ -287,6 +286,14 @@ def populate_with_data(checklist, data, data_type):
         populate_opt_with_data(opt, data, data_type)
 
 
+def override_expected_value(checklist, name, new_val):
+    for opt in checklist:
+        if opt.name == name:
+            assert(opt.type in ('kconfig', 'cmdline', 'sysctl')), \
+                   f'overriding an expected value for "{opt.type}" checks is not supported yet'
+            opt.expected = new_val
+
+
 def perform_checks(checklist):
     for opt in checklist:
         opt.check()