[cip-dev][isar-cip-core][PATCH v2 07/12] Add class for validating the CIS options in the kernel config

Quirin Gylstorff <[email protected]>
Newsgroups org.cip-project.lists.cip-dev
Message-ID <[email protected]>
If CIS hardening options have been configured that change the
kernel configuration, this class checks whether the correct options
are selected in the resulting kernel configuration in ROOTFSDIR.
A JSON report is generated in DEPLOY_DIR_IMAGE indicating whether
the CIS rules for the kernel options were correctly applied
(compliant: true/false).

Co-Authored-by: Clara Kowalsky <[email protected]>
Co-Authored-by: Felix Moessbauer <[email protected]>
Co-Authored-by: Christoph Steiger <[email protected]>
Signed-off-by: Quirin Gylstorff <[email protected]>
---
 .../cis-kernel-hardening-validation.bbclass   | 110 ++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 classes-recipe/cis-kernel-hardening-validation.bbclass

diff --git a/classes-recipe/cis-kernel-hardening-validation.bbclass b/classes-recipe/cis-kernel-hardening-validation.bbclass
new file mode 100644
index 00000000..184da7fa
--- /dev/null
+++ b/classes-recipe/cis-kernel-hardening-validation.bbclass
@@ -0,0 +1,110 @@
+#
+# CIP Core, generic profile
+#
+# Copyright (c) Siemens AG, 2026
+#
+# Authors:
+#  Clara Kowalsky <[email protected]>
+#
+# SPDX-License-Identifier: MIT
+#
+# If CIS hardening options have been configured that change the
+# kernel configuration, this class checks whether the correct options
+# are selected in the resulting kernel configuration in ROOTFSDIR.
+# A JSON report is generated in DEPLOY_DIR_IMAGE indicating whether
+# the CIS rules for the kernel options were correctly applied
+# (compliant: true/false).
+#
+CIP_CIS_HARDENING_REPORT ??= "${DISTRO}-hardening-kernel-report.json"
+
+DEPLOYDIR_HARDENING = "${WORKDIR}/deploy-hardening"
+SSTATETASKS += "do_validate_kernel_config"
+
+do_validate_kernel_config[cleandirs] += "${DEPLOYDIR_HARDENING}"
+do_validate_kernel_config[sstate-inputdirs] = "${DEPLOYDIR_HARDENING}"
+do_validate_kernel_config[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
+do_validate_kernel_config[depends] += "cip-cis-rules-config:do_deploy_hardening"
+python do_validate_kernel_config() {
+    import os
+    import json
+    import re
+
+    deploy_dir_stage = d.getVar('DEPLOYDIR_HARDENING')
+    deploy_dir_image = d.getVar('DEPLOY_DIR_IMAGE')
+    boot_dir = os.path.join(d.getVar('ROOTFSDIR'), "boot")
+    kernel_config_path = None
+
+    if os.path.isdir(boot_dir):
+        for f in os.listdir(boot_dir):
+            if f.startswith("config-") and os.path.isfile(os.path.join(boot_dir, f)):
+                kernel_config_path = os.path.join(boot_dir, f)
+                break
+
+    if not kernel_config_path:
+        return
+
+    hardening_config_path = os.path.join(deploy_dir_image, d.getVar('CIP_CIS_HARDENING_KCONFIG'))
+    if not os.path.isfile(hardening_config_path):
+        return
+
+    report = os.path.join(deploy_dir_stage, d.getVar('CIP_CIS_HARDENING_REPORT'))
+
+    kernel_options = {}
+    with open(kernel_config_path, 'r') as f_kernel:
+        for line in f_kernel:
+            match = re.match(r"^(CONFIG_[A-Za-z0-9_]+)=(y|m)$", line.strip())
+            if match:
+                kernel_options[match.group(1)] = match.group(2)
+
+    report_rules = []
+    with open(hardening_config_path, 'r') as f_hardening:
+        hardening_lines = f_hardening.readlines()
+
+    i = 0
+    while i < len(hardening_lines):
+        line = hardening_lines[i].strip()
+        cis_match = re.match(r"^# CIS ([0-9.]+): (.*)$", line)
+        if cis_match:
+            cis_number = cis_match.group(1)
+            description = cis_match.group(2)
+            config_option = None
+
+            if i + 1 < len(hardening_lines):
+                next_line = hardening_lines[i+1].strip()
+                config_option_match = re.match(r"^# (CONFIG_[A-Za-z0-9_]*) is not set$", next_line)
+                if config_option_match:
+                    config_option = config_option_match.group(1)
+                    i += 1
+
+            is_compliant = not (config_option and kernel_options.get(config_option) in ['y', 'm'])
+
+            report_rules.append({
+                "rule": {
+                    "name": cis_number,
+                    "description": description,
+                    "compliant": is_compliant
+                }
+            })
+        i += 1
+
+    if not report_rules:
+        return
+
+    with open(report, 'w') as f:
+        json.dump({"rules": report_rules}, f, indent=2)
+
+    non_compliant = [r["rule"]["name"] for r in report_rules if not r["rule"]["compliant"]]
+    if non_compliant:
+        bb.fatal(
+            "CIS kernel hardening validation failed. The following CIS rules "
+            "have kernel options enabled that should be disabled: %s. "
+            "Details in %s." % (", ".join(non_compliant), report)
+        )
+}
+
+python do_validate_kernel_config_setscene () {
+    sstate_setscene(d)
+}
+addtask validate_kernel_config_setscene
+
+addtask validate_kernel_config before do_rootfs_finalize after do_rootfs_postprocess
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.