libdnf/CVE-2021-3445.patch
2021-06-08 19:54:28 +08:00

118 lines
3.6 KiB
Diff

From 930f2582f91077b3f338b84cf9567559d52713de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
Date: Mon, 29 Mar 2021 09:22:09 +0200
Subject: [PATCH] Hardening: add signature check with rpmcliVerifySignatures
This api is not ideal but works for now. We don't have to set
installroot for the used transaction because we set keyring which is
used to retrieve the keys.
= changelog =
msg: Hardening: add signature check with rpmcliVerifySignatures
type: security
resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1932079
CVE-2021-3445
RhBug:1932079
RhBug:1932089
RhBug:1932090
Related: CVE-2021-3421, CVE-2021-20271
---
libdnf/dnf-keyring.cpp | 52 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/libdnf/dnf-keyring.cpp b/libdnf/dnf-keyring.cpp
index eec58c69ea..62a6248cb8 100644
--- a/libdnf/dnf-keyring.cpp
+++ b/libdnf/dnf-keyring.cpp
@@ -34,6 +34,8 @@
#include <glib.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmcli.h>
#include "catch-error.hpp"
#include "dnf-types.h"
@@ -216,6 +218,26 @@ dnf_keyring_add_public_keys(rpmKeyring keyring, GError **error) try
return TRUE;
} CATCH_TO_GERROR(FALSE)
+static int
+rpmcliverifysignatures_log_handler_cb(rpmlogRec rec, rpmlogCallbackData data)
+{
+ GString **string =(GString **) data;
+
+ /* create string if required */
+ if (*string == NULL)
+ *string = g_string_new("");
+
+ /* if text already exists, join them */
+ if ((*string)->len > 0)
+ g_string_append(*string, ": ");
+ g_string_append(*string, rpmlogRecMessage(rec));
+
+ /* remove the trailing /n which rpm does */
+ if ((*string)->len > 0)
+ g_string_truncate(*string,(*string)->len - 1);
+ return 0;
+}
+
/**
* dnf_keyring_check_untrusted_file:
*/
@@ -232,6 +254,10 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring,
rpmtd td = NULL;
rpmts ts = NULL;
+ char *path = g_strdup(filename);
+ char *path_array[2] = {path, NULL};
+ g_autoptr(GString) rpm_error = NULL;
+
/* open the file for reading */
fd = Fopen(filename, "r.fdio");
if (fd == NULL) {
@@ -252,9 +278,27 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring,
goto out;
}
- /* we don't want to abort on missing keys */
ts = rpmtsCreate();
- rpmtsSetVSFlags(ts, _RPMVSF_NOSIGNATURES);
+
+ if (rpmtsSetKeyring(ts, keyring) < 0) {
+ g_set_error_literal(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, "failed to set keyring");
+ goto out;
+ }
+ rpmtsSetVfyLevel(ts, RPMSIG_SIGNATURE_TYPE);
+ rpmlogSetCallback(rpmcliverifysignatures_log_handler_cb, &rpm_error);
+
+ // rpm doesn't provide any better API call than rpmcliVerifySignatures (which is for CLI):
+ // - use path_array as input argument
+ // - gather logs via callback because we don't want to print anything if check is successful
+ if (rpmcliVerifySignatures(ts, (char * const*) path_array)) {
+ g_set_error(error,
+ DNF_ERROR,
+ DNF_ERROR_GPG_SIGNATURE_INVALID,
+ "%s could not be verified.\n%s",
+ filename,
+ (rpm_error ? rpm_error->str : "UNKNOWN ERROR"));
+ goto out;
+ }
/* read in the file */
rc = rpmReadPackageFile(ts, fd, filename, &hdr);
@@ -318,6 +362,10 @@ dnf_keyring_check_untrusted_file(rpmKeyring keyring,
g_debug("%s has been verified as trusted", filename);
ret = TRUE;
out:
+ rpmlogSetCallback(NULL, NULL);
+
+ if (path != NULL)
+ g_free(path);
if (dig != NULL)
pgpFreeDig(dig);
if (td != NULL) {