import CS keylime-7.3.0-15.el9
This commit is contained in:
parent
064a1edc0b
commit
ea625cf31f
59
SOURCES/0012-Restore-create-allowlist.patch
Normal file
59
SOURCES/0012-Restore-create-allowlist.patch
Normal file
@ -0,0 +1,59 @@
|
||||
--- a/scripts/create_runtime_policy.sh 2023-10-09 17:04:26.121194607 +0200
|
||||
+++ b/scripts/create_runtime_policy.sh 2023-10-09 17:06:02.089855614 +0200
|
||||
@@ -42,7 +42,7 @@
|
||||
exit $NOARGS;
|
||||
fi
|
||||
|
||||
-ALGO=sha1sum
|
||||
+ALGO=sha256sum
|
||||
|
||||
ALGO_LIST=("sha1sum" "sha256sum" "sha512sum")
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
|
||||
# Where to look for initramfs image
|
||||
-INITRAMFS_LOC="/boot/"
|
||||
+INITRAMFS_LOC="/boot"
|
||||
if [ -d "/ostree" ]; then
|
||||
# If we are on an ostree system change where we look for initramfs image
|
||||
loc=$(grep -E "/ostree/[^/]([^/]*)" -o /proc/cmdline | head -n 1 | cut -d / -f 3)
|
||||
@@ -121,7 +121,7 @@
|
||||
cp -r /tmp/ima/$i-extracted-unmk/. /tmp/ima/$i-extracted
|
||||
fi
|
||||
elif [[ -x "/usr/lib/dracut/skipcpio" ]] ; then
|
||||
- /usr/lib/dracut/skipcpio $i | gunzip -c | cpio -i -d 2> /dev/null
|
||||
+ /usr/lib/dracut/skipcpio $i | gunzip -c 2> /dev/null | cpio -i -d 2> /dev/null
|
||||
else
|
||||
echo "ERROR: No tools for initramfs image processing found!"
|
||||
break
|
||||
@@ -130,9 +130,26 @@
|
||||
find -type f -exec $ALGO "./{}" \; | sed "s| \./\./| /|" >> $OUTPUT
|
||||
done
|
||||
|
||||
-# Convert to runtime policy
|
||||
-echo "Converting created allowlist to Keylime runtime policy"
|
||||
-python3 $WORKING_DIR/../keylime/cmd/convert_runtime_policy.py -a $OUTPUT -o $OUTPUT
|
||||
+# when ROOTFS_LOC = '/', the path starts on allowlist ends up with double '//'
|
||||
+#
|
||||
+# Example:
|
||||
+#
|
||||
+# b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c //bar
|
||||
+#
|
||||
+# Replace the unwanted '//' with a single '/'
|
||||
+sed -i 's| /\+| /|g' $ALLOWLIST_DIR/${OUTPUT}
|
||||
+
|
||||
+# When the file name contains newlines or backslashes, the output of sha256sum
|
||||
+# adds a backslash at the beginning of the line.
|
||||
+#
|
||||
+# Example:
|
||||
+#
|
||||
+# $ echo foo > ba\\r
|
||||
+# $ sha256sum ba\\r
|
||||
+# \b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c ba\\r
|
||||
+#
|
||||
+# Remove the unwanted backslash prefix
|
||||
+sed -i 's/^\\//g' $ALLOWLIST_DIR/${OUTPUT}
|
||||
|
||||
# Clean up
|
||||
rm -rf /tmp/ima
|
@ -0,0 +1,44 @@
|
||||
diff --git a/keylime/cloud_verifier_common.py b/keylime/cloud_verifier_common.py
|
||||
index a7399d2..c0f416d 100644
|
||||
--- a/keylime/cloud_verifier_common.py
|
||||
+++ b/keylime/cloud_verifier_common.py
|
||||
@@ -8,7 +8,7 @@ from keylime.agentstates import AgentAttestState, AgentAttestStates, TPMClockInf
|
||||
from keylime.common import algorithms
|
||||
from keylime.db.verifier_db import VerfierMain
|
||||
from keylime.failure import Component, Event, Failure
|
||||
-from keylime.ima import file_signatures
|
||||
+from keylime.ima import file_signatures, ima
|
||||
from keylime.ima.types import RuntimePolicyType
|
||||
from keylime.tpm import tpm_util
|
||||
from keylime.tpm.tpm_main import Tpm
|
||||
@@ -271,7 +271,7 @@ def process_get_status(agent: VerfierMain) -> Dict[str, Any]:
|
||||
logger.debug('The contents of the agent %s attribute "mb_refstate" are %s', agent.agent_id, agent.mb_refstate)
|
||||
|
||||
has_runtime_policy = 0
|
||||
- if agent.ima_policy.generator and agent.ima_policy.generator > 1:
|
||||
+ if agent.ima_policy.generator and agent.ima_policy.generator > ima.RUNTIME_POLICY_GENERATOR.EmptyAllowList:
|
||||
has_runtime_policy = 1
|
||||
|
||||
response = {
|
||||
diff --git a/keylime/cmd/create_policy.py b/keylime/cmd/create_policy.py
|
||||
index 0841d64..086b92a 100755
|
||||
--- a/keylime/cmd/create_policy.py
|
||||
+++ b/keylime/cmd/create_policy.py
|
||||
@@ -6,6 +6,7 @@ import argparse
|
||||
import binascii
|
||||
import collections
|
||||
import copy
|
||||
+import datetime
|
||||
import gzip
|
||||
import json
|
||||
import multiprocessing
|
||||
@@ -580,6 +581,9 @@ def main() -> None:
|
||||
policy["excludes"] = sorted(list(set(policy["excludes"])))
|
||||
policy["ima"]["ignored_keyrings"] = sorted(list(set(policy["ima"]["ignored_keyrings"])))
|
||||
|
||||
+ policy["meta"]["generator"] = ima.RUNTIME_POLICY_GENERATOR.LegacyAllowList
|
||||
+ policy["meta"]["timestamp"] = str(datetime.datetime.now())
|
||||
+
|
||||
try:
|
||||
ima.validate_runtime_policy(policy)
|
||||
except ima.ImaValidationError as ex:
|
@ -0,0 +1,80 @@
|
||||
From add9847988e963fd124863736592fc16cc8c716b Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Berger <stefanb@linux.ibm.com>
|
||||
Date: Tue, 11 Jul 2023 18:03:28 -0400
|
||||
Subject: [PATCH 14/14] tpm_util: Replace a logger.error with an Exception in
|
||||
case of invalid signature
|
||||
|
||||
This fixes a possibly severe issue in 7.2.5 & 7.3.0.
|
||||
|
||||
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
|
||||
---
|
||||
keylime/tpm/tpm_util.py | 6 +-----
|
||||
keylime/tpm/tpm_util_test.py | 21 +++++++++++++++++++++
|
||||
2 files changed, 22 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/keylime/tpm/tpm_util.py b/keylime/tpm/tpm_util.py
|
||||
index ce2ce0f..58a1a04 100644
|
||||
--- a/keylime/tpm/tpm_util.py
|
||||
+++ b/keylime/tpm/tpm_util.py
|
||||
@@ -3,7 +3,6 @@ import string
|
||||
import struct
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
-from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat import backends
|
||||
from cryptography.hazmat.primitives import hashes, hmac, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import ec, padding
|
||||
@@ -155,10 +154,7 @@ def checkquote(
|
||||
digest.update(quoteblob)
|
||||
quote_digest = digest.finalize()
|
||||
|
||||
- try:
|
||||
- verify(pubkey, signature, quote_digest, hashfunc)
|
||||
- except InvalidSignature:
|
||||
- logger.error("Invalid quote signature!")
|
||||
+ verify(pubkey, signature, quote_digest, hashfunc)
|
||||
|
||||
# Check that reported nonce is expected one
|
||||
retDict = tpm2_objects.unmarshal_tpms_attest(quoteblob)
|
||||
diff --git a/keylime/tpm/tpm_util_test.py b/keylime/tpm/tpm_util_test.py
|
||||
index aaf16cd..2c73997 100644
|
||||
--- a/keylime/tpm/tpm_util_test.py
|
||||
+++ b/keylime/tpm/tpm_util_test.py
|
||||
@@ -2,6 +2,7 @@ import base64
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
+from cryptography.exceptions import InvalidSignature
|
||||
from cryptography.hazmat.primitives.asymmetric.ec import (
|
||||
SECP256R1,
|
||||
EllipticCurve,
|
||||
@@ -60,6 +61,26 @@ class TestTpmUtil(unittest.TestCase):
|
||||
except Exception as e:
|
||||
self.fail(f"checkquote failed with {e}")
|
||||
|
||||
+ # test bad input
|
||||
+ bad_quoteblob = bytearray(quoteblob)
|
||||
+ bad_quoteblob[5] ^= 0x1
|
||||
+ with self.assertRaises(InvalidSignature):
|
||||
+ checkquote(aikblob, nonce, sigblob, bad_quoteblob, pcrblob, "sha256")
|
||||
+
|
||||
+ l = list(nonce)
|
||||
+ l[0] = "a"
|
||||
+ bad_nonce = "".join(l)
|
||||
+ with self.assertRaises(Exception):
|
||||
+ checkquote(aikblob, bad_nonce, sigblob, quoteblob, pcrblob, "sha256")
|
||||
+
|
||||
+ bad_pcrblob = bytearray(pcrblob)
|
||||
+ bad_pcrblob[5] ^= 0x1
|
||||
+ with self.assertRaises(Exception):
|
||||
+ checkquote(aikblob, nonce, sigblob, quoteblob, bad_pcrblob, "sha256")
|
||||
+
|
||||
+ with self.assertRaises(ValueError):
|
||||
+ checkquote(aikblob, nonce, sigblob, quoteblob, pcrblob, "sha1")
|
||||
+
|
||||
@staticmethod
|
||||
def not_random(numbytes: int) -> bytes:
|
||||
return b"\x12" * numbytes
|
||||
--
|
||||
2.41.0
|
||||
|
6638
SOURCES/0015-Backport-keylime-policy-tool.patch
Normal file
6638
SOURCES/0015-Backport-keylime-policy-tool.patch
Normal file
File diff suppressed because it is too large
Load Diff
167
SOURCES/0016-Use-TLS-on-revocation-notification-webhook.patch
Normal file
167
SOURCES/0016-Use-TLS-on-revocation-notification-webhook.patch
Normal file
@ -0,0 +1,167 @@
|
||||
From 4bd644b74719fdbb6c521d3d5eb2430d8dc18b36 Mon Sep 17 00:00:00 2001
|
||||
From: Sergio Correia <scorreia@redhat.com>
|
||||
Date: Wed, 5 Feb 2025 16:16:25 +0000
|
||||
Subject: [PATCH 16/16] Use TLS on revocation notification webhook
|
||||
|
||||
---
|
||||
keylime/requests_client.py | 5 ++
|
||||
keylime/revocation_notifier.py | 91 +++++++++++++++++++++++-----------
|
||||
2 files changed, 68 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/keylime/requests_client.py b/keylime/requests_client.py
|
||||
index 85a175c..e993fbc 100644
|
||||
--- a/keylime/requests_client.py
|
||||
+++ b/keylime/requests_client.py
|
||||
@@ -1,3 +1,4 @@
|
||||
+import re
|
||||
import ssl
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
@@ -15,6 +16,10 @@ class RequestsClient:
|
||||
ignore_hostname: bool = True,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
+ # Remove eventual "http?://" from the base url
|
||||
+ if base_url.startswith("http"):
|
||||
+ base_url = re.sub(r"https?://", "", base_url)
|
||||
+
|
||||
if tls_enabled:
|
||||
self.base_url = f"https://{base_url}"
|
||||
else:
|
||||
diff --git a/keylime/revocation_notifier.py b/keylime/revocation_notifier.py
|
||||
index 5cc8b1a..434bf64 100644
|
||||
--- a/keylime/revocation_notifier.py
|
||||
+++ b/keylime/revocation_notifier.py
|
||||
@@ -9,8 +9,9 @@ from typing import Any, Callable, Dict, Optional, Set
|
||||
|
||||
import requests
|
||||
|
||||
-from keylime import config, crypto, json, keylime_logging
|
||||
+from keylime import config, crypto, json, keylime_logging, web_util
|
||||
from keylime.common import retry
|
||||
+from keylime.requests_client import RequestsClient
|
||||
|
||||
logger = keylime_logging.init_logging("revocation_notifier")
|
||||
broker_proc: Optional[Process] = None
|
||||
@@ -109,7 +110,10 @@ def notify(tosend: Dict[str, Any]) -> None:
|
||||
exponential_backoff = config.getboolean("verifier", "exponential_backoff")
|
||||
next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||
logger.debug(
|
||||
- "Unable to publish revocation message %d times, trying again in %f seconds: %s", i, next_retry, e
|
||||
+ "Unable to publish revocation message %d times, trying again in %f seconds: %s",
|
||||
+ i,
|
||||
+ next_retry,
|
||||
+ e,
|
||||
)
|
||||
time.sleep(next_retry)
|
||||
mysock.close()
|
||||
@@ -132,30 +136,50 @@ def notify_webhook(tosend: Dict[str, Any]) -> None:
|
||||
def worker_webhook(tosend: Dict[str, Any], url: str) -> None:
|
||||
interval = config.getfloat("verifier", "retry_interval")
|
||||
exponential_backoff = config.getboolean("verifier", "exponential_backoff")
|
||||
- with requests.Session() as session:
|
||||
- logger.info("Sending revocation event via webhook...")
|
||||
- for i in range(config.getint("verifier", "max_retries")):
|
||||
- next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||
+
|
||||
+ max_retries = config.getint("verifier", "max_retries")
|
||||
+ if max_retries <= 0:
|
||||
+ logger.info("Invalid value found in 'max_retries' option for verifier, using default value")
|
||||
+ max_retries = 5
|
||||
+
|
||||
+ # Get TLS options from the configuration
|
||||
+ (cert, key, trusted_ca, key_password), verify_server_cert = web_util.get_tls_options(
|
||||
+ "verifier", is_client=True, logger=logger
|
||||
+ )
|
||||
+
|
||||
+ # Generate the TLS context using the obtained options
|
||||
+ tls_context = web_util.generate_tls_context(cert, key, trusted_ca, key_password, is_client=True, logger=logger)
|
||||
+
|
||||
+ logger.info("Sending revocation event via webhook to %s ...", url)
|
||||
+ for i in range(max_retries):
|
||||
+ next_retry = retry.retry_time(exponential_backoff, interval, i, logger)
|
||||
+
|
||||
+ with RequestsClient(
|
||||
+ url,
|
||||
+ verify_server_cert,
|
||||
+ tls_context,
|
||||
+ ) as client:
|
||||
try:
|
||||
- response = session.post(url, json=tosend, timeout=5)
|
||||
- if response.status_code in [200, 202]:
|
||||
- break
|
||||
-
|
||||
- logger.debug(
|
||||
- "Unable to publish revocation message %d times via webhook, "
|
||||
- "trying again in %d seconds. "
|
||||
- "Server returned status code: %s",
|
||||
- i,
|
||||
- next_retry,
|
||||
- response.status_code,
|
||||
- )
|
||||
- except requests.exceptions.RequestException as e:
|
||||
- logger.debug(
|
||||
- "Unable to publish revocation message %d times via webhook, trying again in %d seconds: %s",
|
||||
- i,
|
||||
- next_retry,
|
||||
- e,
|
||||
- )
|
||||
+ res = client.post("", json=tosend, timeout=5)
|
||||
+ except requests.exceptions.SSLError as ssl_error:
|
||||
+ if "TLSV1_ALERT_UNKNOWN_CA" in str(ssl_error):
|
||||
+ logger.warning(
|
||||
+ "Keylime does not recognize certificate from peer. Check if verifier 'trusted_server_ca' is configured correctly"
|
||||
+ )
|
||||
+
|
||||
+ raise ssl_error from ssl_error
|
||||
+
|
||||
+ if res and res.status_code in [200, 202]:
|
||||
+ break
|
||||
+
|
||||
+ logger.debug(
|
||||
+ "Unable to publish revocation message %d times via webhook, "
|
||||
+ "trying again in %d seconds. "
|
||||
+ "Server returned status code: %s",
|
||||
+ i + 1,
|
||||
+ next_retry,
|
||||
+ res.status_code,
|
||||
+ )
|
||||
|
||||
time.sleep(next_retry)
|
||||
|
||||
@@ -167,7 +191,11 @@ def notify_webhook(tosend: Dict[str, Any]) -> None:
|
||||
cert_key = None
|
||||
|
||||
|
||||
-def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str, Any]], None], cert_path: str) -> None:
|
||||
+def process_revocation(
|
||||
+ revocation: Dict[str, Any],
|
||||
+ callback: Callable[[Dict[str, Any]], None],
|
||||
+ cert_path: str,
|
||||
+) -> None:
|
||||
global cert_key
|
||||
|
||||
if cert_key is None:
|
||||
@@ -179,10 +207,17 @@ def process_revocation(revocation: Dict[str, Any], callback: Callable[[Dict[str,
|
||||
cert_key = crypto.x509_import_pubkey(certpem)
|
||||
|
||||
if cert_key is None:
|
||||
- logger.warning("Unable to check signature of revocation message: %s not available", cert_path)
|
||||
+ logger.warning(
|
||||
+ "Unable to check signature of revocation message: %s not available",
|
||||
+ cert_path,
|
||||
+ )
|
||||
elif "signature" not in revocation or revocation["signature"] == "none":
|
||||
logger.warning("No signature on revocation message from server")
|
||||
- elif not crypto.rsa_verify(cert_key, revocation["msg"].encode("utf-8"), revocation["signature"].encode("utf-8")):
|
||||
+ elif not crypto.rsa_verify(
|
||||
+ cert_key,
|
||||
+ revocation["msg"].encode("utf-8"),
|
||||
+ revocation["signature"].encode("utf-8"),
|
||||
+ ):
|
||||
logger.error("Invalid revocation message siganture %s", revocation)
|
||||
else:
|
||||
message = json.loads(revocation["msg"])
|
||||
--
|
||||
2.47.1
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
Name: keylime
|
||||
Version: 7.3.0
|
||||
Release: 9%{?dist}
|
||||
Release: 15%{?dist}
|
||||
Summary: Open source TPM software for Bootstrapping and Maintaining Trust
|
||||
|
||||
URL: https://github.com/keylime/keylime
|
||||
@ -28,6 +28,11 @@ Patch: 0008-verifier-should-read-parameters-from-verifier.conf-o.patch
|
||||
Patch: 0009-CVE-2023-38201.patch
|
||||
Patch: 0010-CVE-2023-38200.patch
|
||||
Patch: 0011-Automatically-update-agent-API-version.patch
|
||||
Patch: 0012-Restore-create-allowlist.patch
|
||||
Patch: 0013-Set-generator-and-timestamp-in-create-policy.patch
|
||||
Patch: 0014-tpm_util-Replace-a-logger.error-with-an-Exception-in.patch
|
||||
Patch: 0015-Backport-keylime-policy-tool.patch
|
||||
Patch: 0016-Use-TLS-on-revocation-notification-webhook.patch
|
||||
|
||||
License: ASL 2.0 and MIT
|
||||
|
||||
@ -100,6 +105,7 @@ Requires: python3-lark-parser
|
||||
Requires: python3-pyasn1
|
||||
Requires: python3-pyasn1-modules
|
||||
Requires: python3-jsonschema
|
||||
Requires: python3-psutil
|
||||
Requires: tpm2-tools
|
||||
Requires: openssl
|
||||
|
||||
@ -183,13 +189,19 @@ done
|
||||
|
||||
# Ship some scripts.
|
||||
mkdir -p %{buildroot}/%{_datadir}/%{srcname}/scripts
|
||||
for s in create_runtime_policy.sh \
|
||||
create_mb_refstate \
|
||||
for s in create_mb_refstate \
|
||||
ek-openssl-verify; do
|
||||
install -Dpm 755 scripts/${s} \
|
||||
%{buildroot}/%{_datadir}/%{srcname}/scripts/${s}
|
||||
done
|
||||
|
||||
# On RHEL 9.3, install create_runtime_policy.sh as create_allowlist.sh
|
||||
# The convert_runtime_policy.py script to convert allowlist and excludelist into
|
||||
# runtime policy is not called anymore.
|
||||
# See: https://issues.redhat.com/browse/RHEL-11866
|
||||
install -Dpm 755 scripts/create_runtime_policy.sh \
|
||||
%{buildroot}/%{_datadir}/%{srcname}/scripts/create_allowlist.sh
|
||||
|
||||
# Ship configuration templates.
|
||||
cp -r ./templates %{buildroot}%{_datadir}/%{srcname}/templates/
|
||||
|
||||
@ -339,6 +351,7 @@ fi
|
||||
%{_bindir}/keylime_create_policy
|
||||
%{_bindir}/keylime_sign_runtime_policy
|
||||
%{_bindir}/keylime_userdata_encrypt
|
||||
%{_bindir}/keylime-policy
|
||||
|
||||
%files base
|
||||
%license LICENSE
|
||||
@ -353,7 +366,7 @@ fi
|
||||
%attr(400,%{srcname},%{srcname}) %{_sharedstatedir}/%{srcname}/tpm_cert_store/*.pem
|
||||
%{_tmpfilesdir}/%{srcname}.conf
|
||||
%{_sysusersdir}/%{srcname}.conf
|
||||
%{_datadir}/%{srcname}/scripts/create_runtime_policy.sh
|
||||
%{_datadir}/%{srcname}/scripts/create_allowlist.sh
|
||||
%{_datadir}/%{srcname}/scripts/ek-openssl-verify
|
||||
%{_datadir}/%{srcname}/templates
|
||||
%{_bindir}/keylime_upgrade_config
|
||||
@ -362,6 +375,37 @@ fi
|
||||
%license LICENSE
|
||||
|
||||
%changelog
|
||||
* Wed Feb 05 2025 Sergio Correia <scorreia@redhat.com> - 7.3.0-15
|
||||
- Use TLS on revocation notification webhook
|
||||
- Include system installed CA certificates when verifying webhook
|
||||
server certificate
|
||||
- Include the CA certificates added via configuration file option
|
||||
'trusted_server_ca'
|
||||
Resolves: RHEL-78057
|
||||
Resolves: RHEL-78313
|
||||
Resolves: RHEL-78316
|
||||
|
||||
* Fri Jan 10 2025 Sergio Correia <scorreia@redhat.com> - 7.3.0-14
|
||||
- Backport keylime-policy tool
|
||||
Resolves: RHEL-75797
|
||||
|
||||
* Fri Jan 05 2024 Sergio Correia <scorreia@redhat.com> - 7.3.0-13
|
||||
- Backport fix for CVE-2023-3674
|
||||
Resolves: RHEL-21013
|
||||
|
||||
* Tue Oct 17 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 7.3.0-12
|
||||
- Set the generator and timestamp in create_policy.py
|
||||
Related: RHEL-11866
|
||||
|
||||
* Mon Oct 09 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 7.3.0-11
|
||||
- Suppress unnecessary error message
|
||||
Related: RHEL-11866
|
||||
|
||||
* Fri Oct 06 2023 Anderson Toshiyuki Sasaki <ansasaki@redhat.com> - 7.3.0-10
|
||||
- Restore allowlist generation script
|
||||
Resolves: RHEL-11866
|
||||
Resolves: RHEL-11867
|
||||
|
||||
* Wed Sep 06 2023 Sergio Correia <scorreia@redhat.com> - 7.3.0-9
|
||||
- Rebuild for properly tagging the resulting build
|
||||
Resolves: RHEL-1898
|
||||
|
Loading…
Reference in New Issue
Block a user