From 86d98c9da8723f5f3e10538a98dbbc46bc5d43aa Mon Sep 17 00:00:00 2001 From: Sergio Correia Date: Fri, 22 May 2026 21:31:01 +0000 Subject: [PATCH] Apply limit on keylime-policy workers Resolves: RHEL-114482 Signed-off-by: Sergio Correia --- ...pply-limit-on-keylime-policy-workers.patch | 145 ++++++++++++++++++ keylime.spec | 10 +- 2 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 0024-Apply-limit-on-keylime-policy-workers.patch diff --git a/0024-Apply-limit-on-keylime-policy-workers.patch b/0024-Apply-limit-on-keylime-policy-workers.patch new file mode 100644 index 0000000..bbca776 --- /dev/null +++ b/0024-Apply-limit-on-keylime-policy-workers.patch @@ -0,0 +1,145 @@ +From 6466fcd8071c6332db4c695797ca6a0573e8df23 Mon Sep 17 00:00:00 2001 +From: Sergio Correia +Date: Sun, 24 May 2026 20:28:42 +0000 +Subject: [PATCH 24/24] Apply limit on keylime-policy workers + +Upstream backport: https://github.com/keylime/keylime/pull/1811 + +Signed-off-by: Sergio Correia +--- + keylime/policy/create_runtime_policy.py | 24 ++++++++++++++++++++++-- + keylime/policy/rpm_repo.py | 17 +++++++++++++---- + 2 files changed, 35 insertions(+), 6 deletions(-) + +diff --git a/keylime/policy/create_runtime_policy.py b/keylime/policy/create_runtime_policy.py +index 8e1c687..2db9b73 100644 +--- a/keylime/policy/create_runtime_policy.py ++++ b/keylime/policy/create_runtime_policy.py +@@ -434,6 +434,13 @@ def get_arg_parser(create_parser: _SubparserType, parent_parser: argparse.Argume + dest="remote_rpm_repo", + help="Remote RPM repo URL", + ) ++ repo_group.add_argument( ++ "--max-workers", ++ dest="max_workers", ++ type=_positive_int, ++ default=rpm_repo.MAX_WORKERS_DEFAULT, ++ help=f"The maximum number of workers used for RPM processing (must be a positive integer; default {rpm_repo.MAX_WORKERS_DEFAULT}).", ++ ) + + fs_group.add_argument( + "--algo", +@@ -839,6 +846,19 @@ def _get_digest_algorithm_from_map_list(maplist: Dict[str, List[str]]) -> str: + return algo + + ++def _positive_int(value: str) -> int: ++ """ ++ A custom type function for argparse that checks for a positive integer. ++ """ ++ try: ++ ivalue = int(value) ++ if ivalue <= 0: ++ raise argparse.ArgumentTypeError(f"'{value}' is not a positive integer.") ++ return ivalue ++ except ValueError as exc: ++ raise argparse.ArgumentTypeError(f"'{value}' is not a positive integer.") from exc ++ ++ + def create_runtime_policy(args: argparse.Namespace) -> Optional[RuntimePolicyType]: + """Create a runtime policy from the input arguments.""" + policy = None +@@ -924,7 +944,7 @@ def create_runtime_policy(args: argparse.Namespace) -> Optional[RuntimePolicyTyp + # FIXME: pass the IMA sigs as well. + local_rpm_digests = {} + local_rpm_digests, _imasigs, ok = rpm_repo.analyze_local_repo( +- args.local_rpm_repo, digests=local_rpm_digests ++ args.local_rpm_repo, digests=local_rpm_digests, max_workers=args.max_workers + ) + if not ok: + return None +@@ -932,7 +952,7 @@ def create_runtime_policy(args: argparse.Namespace) -> Optional[RuntimePolicyTyp + # FIXME: pass the IMA sigs as well. + remote_rpm_digests = {} + remote_rpm_digests, _imasigs, ok = rpm_repo.analyze_remote_repo( +- args.remote_rpm_repo, digests=remote_rpm_digests ++ args.remote_rpm_repo, digests=remote_rpm_digests, max_workers=args.max_workers + ) + if not ok: + return None +diff --git a/keylime/policy/rpm_repo.py b/keylime/policy/rpm_repo.py +index d6a8bda..ab55484 100644 +--- a/keylime/policy/rpm_repo.py ++++ b/keylime/policy/rpm_repo.py +@@ -25,6 +25,8 @@ from keylime.types import PathLike_str + + logger = Logger().logger() + ++MAX_WORKERS_DEFAULT = 8 ++ + + def _parse_rpm_header(hdr: rpm.hdr) -> Tuple[Dict[str, List[str]], Dict[str, List[bytes]]]: + # First, the file digests. +@@ -110,6 +112,7 @@ def analyze_local_repo( + digests: Optional[Dict[str, List[str]]] = None, + imasigs: Optional[Dict[str, List[bytes]]] = None, + jobs: Optional[int] = None, ++ max_workers: int = MAX_WORKERS_DEFAULT, + ) -> Tuple[Dict[str, List[str]], Dict[str, List[bytes]], bool]: + """ + Analyze a local repository. +@@ -121,6 +124,7 @@ def analyze_local_repo( + :param imasigs: dict of str and a list of bytes, to store the files and + their associated IMA signatures + :param jobs: integer, the number of jobs to use when processing the rpms ++ :param max_workers: integer, the maximum number of workers used for RPM processing + :return: tuple with the dict of digests, the dict of IMA signatures and a + boolean indicating the success of this method + """ +@@ -163,7 +167,7 @@ def analyze_local_repo( + else: + logger.warning("Warning. Unsigned repository. Continuing the RPM scanning") + +- jobs = jobs if jobs else multiprocessing.cpu_count() ++ jobs = jobs if jobs else min(multiprocessing.cpu_count(), max_workers) + + if not digests: + digests = {} +@@ -255,7 +259,11 @@ def _parse_xml_file(filepath: str) -> ET.ElementTree: + + + def _analyze_remote_repo( +- repo: str, digests: Optional[Dict[str, List[str]]], imasigs: Optional[Dict[str, List[bytes]]], jobs: Optional[int] ++ repo: str, ++ digests: Optional[Dict[str, List[str]]], ++ imasigs: Optional[Dict[str, List[bytes]]], ++ jobs: Optional[int], ++ max_workers: int = MAX_WORKERS_DEFAULT, + ) -> Tuple[Dict[str, List[str]], Dict[str, List[bytes]], bool]: + # Make the repo ends with "/", so we can be considered as a base URL + repo = repo if (repo).endswith("/") else f"{repo}/" +@@ -319,7 +327,7 @@ def _analyze_remote_repo( + # single thread (asyncio) or multiple process. To avoid change + # all the stack, I go for synchronous functions but with many + # process. In the future we can move all to asyncio. +- jobs = jobs if jobs else (multiprocessing.cpu_count() * 8) ++ jobs = jobs if jobs else max_workers + + # Analyze all the RPMs in parallel + with multiprocessing.Pool(jobs) as pool: +@@ -335,10 +343,11 @@ def analyze_remote_repo( + digests: Optional[Dict[str, List[str]]] = None, + imasigs: Optional[Dict[str, List[bytes]]] = None, + jobs: Optional[int] = None, ++ max_workers: int = MAX_WORKERS_DEFAULT, + ) -> Tuple[Dict[str, List[str]], Dict[str, List[bytes]], bool]: + """Analyze a remote repository.""" + try: +- return _analyze_remote_repo(str(*repourl), digests, imasigs, jobs) ++ return _analyze_remote_repo(str(*repourl), digests, imasigs, jobs, max_workers) + except Exception as exc: + logger.error(exc) + return {}, {}, False +-- +2.47.3 + diff --git a/keylime.spec b/keylime.spec index 7d8c250..c9f20c2 100644 --- a/keylime.spec +++ b/keylime.spec @@ -9,7 +9,7 @@ Name: keylime Version: 7.12.1 -Release: 16%{?dist} +Release: 17%{?dist} Summary: Open source TPM software for Bootstrapping and Maintaining Trust URL: https://github.com/keylime/keylime @@ -70,6 +70,10 @@ Patch: 0022-CVE-2026-1709.patch # - https://github.com/keylime/keylime/pull/1845 Patch: 0023-Backport-tenant-version-negotiation-mechanism.patch +# Backport from: +# - https://github.com/keylime/keylime/pull/1811 +Patch: 0024-Apply-limit-on-keylime-policy-workers.patch + License: ASL 2.0 and MIT BuildRequires: git-core @@ -464,6 +468,10 @@ fi %license LICENSE %changelog +* Fri May 22 2026 Sergio Correia 7.12.1-17 +- Apply limit on keylime-policy workers + Resolves: RHEL-114482 + * Fri May 22 2026 Sergio Correia 7.12.1-16 - Add API version negotiation to keylime_tenant Resolves: RHEL-151705