From 0309446a526b3820156dee343acf3faab580e728 Mon Sep 17 00:00:00 2001 From: Preston Watson Date: Thu, 25 Jan 2024 20:06:38 -0500 Subject: [PATCH] [RHELC-1200] Add OVERRIDABLE result to tainted kernel module check (#1015) * [RHELC-1200] Add OVERRIDABLE result to tainted kernel module check * Apply suggestions from code review Co-authored-by: E Gustavsson Co-authored-by: Rodolfo Olivieri * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: E Gustavsson Co-authored-by: Rodolfo Olivieri Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../actions/system_checks/tainted_kmods.py | 58 +++++++++--- .../system_checks/tainted_kmods_test.py | 93 ++++++++++++++++++- 2 files changed, 135 insertions(+), 16 deletions(-) diff --git a/convert2rhel/actions/system_checks/tainted_kmods.py b/convert2rhel/actions/system_checks/tainted_kmods.py index 3b2bf8f617..f57bf39760 100644 --- a/convert2rhel/actions/system_checks/tainted_kmods.py +++ b/convert2rhel/actions/system_checks/tainted_kmods.py @@ -16,6 +16,7 @@ __metaclass__ = type import logging +import os from convert2rhel import actions from convert2rhel.utils import run_subprocess @@ -25,6 +26,7 @@ LINK_KMODS_RH_POLICY = "https://access.redhat.com/third-party-software-support" LINK_PREVENT_KMODS_FROM_LOADING = "https://access.redhat.com/solutions/41278" +LINK_TAINTED_KMOD_DOCS = "https://docs.kernel.org/admin-guide/tainted-kernels.html" class TaintedKmods(actions.Action): @@ -43,21 +45,55 @@ def run(self): logger.task("Prepare: Check if loaded kernel modules are not tainted") unsigned_modules, _ = run_subprocess(["grep", "(", "/proc/modules"]) module_names = "\n ".join([mod.split(" ")[0] for mod in unsigned_modules.splitlines()]) + tainted_kmods_skip = os.environ.get("CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP", None) + diagnosis = ( + "Tainted kernel modules detected:\n {0}\n" + "Third-party components are not supported per our " + "software support policy:\n{1}\n".format(module_names, LINK_KMODS_RH_POLICY) + ) + if unsigned_modules: - self.set_result( - level="ERROR", - id="TAINTED_KMODS_DETECTED", - description="Please refer to the diagnosis for further information", - title="Tainted kernel modules detected", - diagnosis=( - "Tainted kernel modules detected:\n {0}\n" - "Third-party components are not supported per our " - "software support policy:\n {1}\n".format(module_names, LINK_KMODS_RH_POLICY) + if not tainted_kmods_skip: + self.set_result( + level="OVERRIDABLE", + id="TAINTED_KMODS_DETECTED", + title="Tainted kernel modules detected", + description="Please refer to the diagnosis for further information", + diagnosis=diagnosis, + remediations=( + "Prevent the modules from loading by following {0}" + " and run convert2rhel again to continue with the conversion." + " Although it is not recommended, you can ignore this message by setting the environment variable" + " 'CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP' to 1. Overriding this check can be dangerous" + " so it is recommended that you do a system backup beforehand." + " For information on what a tainted kernel module is, please refer to this documentation {1}".format( + LINK_PREVENT_KMODS_FROM_LOADING, LINK_TAINTED_KMOD_DOCS + ) + ), + ) + return + + self.add_message( + level="WARNING", + id="SKIP_TAINTED_KERNEL_MODULE_CHECK", + title="Skip tainted kernel module check", + description=( + "Detected 'CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP' environment variable, we will skip " + "the tainted kernel module check.\n" + "Beware, this could leave your system in a broken state." ), + ) + self.add_message( + level="WARNING", + id="TAINTED_KMODS_DETECTED_MESSAGE", + title="Tainted kernel modules detected", + description="Please refer to the diagnosis for further information", + diagnosis=diagnosis, remediations=( "Prevent the modules from loading by following {0}" - " and run convert2rhel again to continue with the conversion.".format( - LINK_PREVENT_KMODS_FROM_LOADING + " and run convert2rhel again to continue with the conversion." + " For information on what a tainted kernel module is, please refer to this documentation {1}".format( + LINK_PREVENT_KMODS_FROM_LOADING, LINK_TAINTED_KMOD_DOCS ) ), ) diff --git a/convert2rhel/unit_tests/actions/system_checks/tainted_kmods_test.py b/convert2rhel/unit_tests/actions/system_checks/tainted_kmods_test.py index b5f39d718f..a05f8d3110 100644 --- a/convert2rhel/unit_tests/actions/system_checks/tainted_kmods_test.py +++ b/convert2rhel/unit_tests/actions/system_checks/tainted_kmods_test.py @@ -15,12 +15,18 @@ __metaclass__ = type +import os import pytest import six -from convert2rhel import unit_tests +from convert2rhel import actions, unit_tests from convert2rhel.actions.system_checks import tainted_kmods +from convert2rhel.actions.system_checks.tainted_kmods import ( + LINK_KMODS_RH_POLICY, + LINK_PREVENT_KMODS_FROM_LOADING, + LINK_TAINTED_KMOD_DOCS, +) six.add_move(six.MovedModule("mock", "mock", "unittest.mock")) @@ -60,15 +66,92 @@ def test_check_tainted_kmods(monkeypatch, command_return, is_error, tainted_kmod if is_error: unit_tests.assert_actions_result( tainted_kmods_action, - level="ERROR", + level="OVERRIDABLE", id="TAINTED_KMODS_DETECTED", title="Tainted kernel modules detected", description="Please refer to the diagnosis for further information", - diagnosis="Tainted kernel modules detected:\n system76_io\n", + diagnosis=( + "Tainted kernel modules detected:\n system76_io\n system76_acpi\nThird-party " + "components are not supported per our software support" + " policy:\n%s\n" % LINK_KMODS_RH_POLICY + ), remediations=( "Prevent the modules from loading by following {0}" - " and run convert2rhel again to continue with the conversion.".format( - tainted_kmods.LINK_PREVENT_KMODS_FROM_LOADING + " and run convert2rhel again to continue with the conversion." + " Although it is not recommended, you can ignore this message by setting the environment variable" + " 'CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP' to 1. Overriding this check can be dangerous" + " so it is recommended that you do a system backup beforehand." + " For information on what a tainted kernel module is, please refer to this documentation {1}".format( + LINK_PREVENT_KMODS_FROM_LOADING, LINK_TAINTED_KMOD_DOCS ) ), ) + + +@pytest.mark.parametrize( + ("command_return", "is_error"), + ( + (("", 0), False), + ( + ( + ( + "system76_io 16384 0 - Live 0x0000000000000000 (OE)\n" + "system76_acpi 16384 0 - Live 0x0000000000000000 (OE)" + ), + 0, + ), + True, + ), + ), +) +def test_check_tainted_kmods_skip(monkeypatch, command_return, is_error, tainted_kmods_action): + run_subprocess_mock = mock.Mock(return_value=command_return) + monkeypatch.setattr( + tainted_kmods, + "run_subprocess", + value=run_subprocess_mock, + ) + monkeypatch.setattr( + os, + "environ", + {"CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP": 1}, + ) + tainted_kmods_action.run() + + if is_error: + expected = set( + ( + actions.ActionMessage( + level="WARNING", + id="TAINTED_KMODS_DETECTED_MESSAGE", + title="Tainted kernel modules detected", + description="Please refer to the diagnosis for further information", + diagnosis=( + "Tainted kernel modules detected:\n system76_io\n system76_acpi\nThird-party " + "components are not supported per our software support" + " policy:\n%s\n" % LINK_KMODS_RH_POLICY + ), + remediations=( + "Prevent the modules from loading by following {0}" + " and run convert2rhel again to continue with the conversion." + " For information on what a tainted kernel module is, please refer to this documentation {1}".format( + LINK_PREVENT_KMODS_FROM_LOADING, LINK_TAINTED_KMOD_DOCS + ) + ), + ), + actions.ActionMessage( + level="WARNING", + id="SKIP_TAINTED_KERNEL_MODULE_CHECK", + title="Skip tainted kernel module check", + description=( + "Detected 'CONVERT2RHEL_TAINTED_KERNEL_MODULE_CHECK_SKIP' environment variable, we will skip " + "the tainted kernel module check.\n" + "Beware, this could leave your system in a broken state." + ), + ), + ) + ) + print(expected) + print(tainted_kmods_action.messages) + assert expected.issuperset(tainted_kmods_action.messages) + assert expected.issubset(tainted_kmods_action.messages)