[RFC cip-dev][isar-cip-core][PATCH 08/14] Add class for validating the CIS options in the kernel config
Quirin Gylstorff <[email protected]> Fri, 24 Jul 2026 14:39:10 +0200
| Newsgroups | org.cip-project.lists.cip-dev |
|---|---|
| Message-ID | <[email protected]> |
From: Quirin Gylstorff <[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 0000000..184da7f --- /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.53.0