Michal Domonkos 0b3e36
From b66422161d68ed7f7b1cb30e4db900bf42bed146 Mon Sep 17 00:00:00 2001
Michal Domonkos e2e5e2
From: Panu Matilainen <pmatilai@redhat.com>
Michal Domonkos e2e5e2
Date: Mon, 29 Nov 2021 14:01:39 +0200
Michal Domonkos 0b3e36
Subject: [PATCH 1/4] Add Python bindings for rpmfilesFSignature()
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
Only, use more descriptive names than the C-side counterparts.
Michal Domonkos 0b3e36
Python has nice facilities for dealing with binary data so return it
Michal Domonkos 0b3e36
as such rather than converting to hex.
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
Backported for 4.16.1.3 (removed rpmfilesVSignature()).
Michal Domonkos 0b3e36
---
Michal Domonkos 0b3e36
 python/rpmfiles-py.c | 18 ++++++++++++++++++
Michal Domonkos 0b3e36
 1 file changed, 18 insertions(+)
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c
Michal Domonkos 0b3e36
index 27666021d..48189a0ac 100644
Michal Domonkos 0b3e36
--- a/python/rpmfiles-py.c
Michal Domonkos 0b3e36
+++ b/python/rpmfiles-py.c
Michal Domonkos 0b3e36
@@ -152,6 +152,22 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
Michal Domonkos 0b3e36
     Py_RETURN_NONE;
Michal Domonkos 0b3e36
 }
Michal Domonkos 0b3e36
 
Michal Domonkos 0b3e36
+static PyObject *bytebuf(const unsigned char *buf, size_t len)
Michal Domonkos 0b3e36
+{
Michal Domonkos 0b3e36
+    if (buf) {
Michal Domonkos 0b3e36
+	PyObject *o = PyBytes_FromStringAndSize((const char *)buf, len);
Michal Domonkos 0b3e36
+	return o;
Michal Domonkos 0b3e36
+    }
Michal Domonkos 0b3e36
+    Py_RETURN_NONE;
Michal Domonkos 0b3e36
+}
Michal Domonkos 0b3e36
+
Michal Domonkos 0b3e36
+static PyObject *rpmfile_imasig(rpmfileObject *s)
Michal Domonkos 0b3e36
+{
Michal Domonkos 0b3e36
+    size_t len = 0;
Michal Domonkos 0b3e36
+    const unsigned char *sig = rpmfilesFSignature(s->files, s->ix, &len;;
Michal Domonkos 0b3e36
+    return bytebuf(sig, len);
Michal Domonkos 0b3e36
+}
Michal Domonkos 0b3e36
+
Michal Domonkos 0b3e36
 static PyObject *rpmfile_class(rpmfileObject *s)
Michal Domonkos 0b3e36
 {
Michal Domonkos 0b3e36
     return utf8FromString(rpmfilesFClass(s->files, s->ix));
Michal Domonkos 0b3e36
@@ -278,6 +294,8 @@ static PyGetSetDef rpmfile_getseters[] = {
Michal Domonkos 0b3e36
       "language the file provides (typically for doc files)" },
Michal Domonkos 0b3e36
     { "caps",		(getter) rpmfile_caps,		NULL,
Michal Domonkos 0b3e36
       "file capabilities" },
Michal Domonkos 0b3e36
+    { "imasig",	(getter) rpmfile_imasig,	NULL,
Michal Domonkos 0b3e36
+      "IMA signature" },
Michal Domonkos 0b3e36
     { NULL, NULL, NULL, NULL }
Michal Domonkos 0b3e36
 };
Michal Domonkos 0b3e36
 
Michal Domonkos 0b3e36
-- 
Michal Domonkos 0b3e36
2.35.1
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
From 9c4622998d3d0666edbea3ed1ae518502c3ed987 Mon Sep 17 00:00:00 2001
Michal Domonkos 0b3e36
From: Panu Matilainen <pmatilai@redhat.com>
Michal Domonkos 0b3e36
Date: Mon, 7 Feb 2022 11:52:55 +0200
Michal Domonkos 0b3e36
Subject: [PATCH 2/4] Add a testcase for --dump query
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
---
Michal Domonkos 0b3e36
 tests/rpmquery.at | 18 ++++++++++++++++++
Michal Domonkos 0b3e36
 1 file changed, 18 insertions(+)
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
diff --git a/tests/rpmquery.at b/tests/rpmquery.at
Michal Domonkos 0b3e36
index 9a4f1cb76..9bd391ac5 100644
Michal Domonkos 0b3e36
--- a/tests/rpmquery.at
Michal Domonkos 0b3e36
+++ b/tests/rpmquery.at
Michal Domonkos 0b3e36
@@ -83,6 +83,24 @@ hello.spec
Michal Domonkos 0b3e36
 [ignore])
Michal Domonkos 0b3e36
 AT_CLEANUP
Michal Domonkos 0b3e36
 
Michal Domonkos 0b3e36
+AT_SETUP([rpm -qp --dump])
Michal Domonkos 0b3e36
+AT_KEYWORDS([query])
Michal Domonkos 0b3e36
+AT_CHECK([
Michal Domonkos 0b3e36
+RPMDB_INIT
Michal Domonkos 0b3e36
+runroot rpm \
Michal Domonkos 0b3e36
+  -qp --dump \
Michal Domonkos 0b3e36
+  /data/RPMS/hello-2.0-1.x86_64.rpm
Michal Domonkos 0b3e36
+],
Michal Domonkos 0b3e36
+[0],
Michal Domonkos 0b3e36
+[/usr/bin/hello 7120 1489670606 c89fa87aeb1143969c0b6be9334b21d932f77f74e8f60120b5de316406369cf0 0100751 root root 0 0 0 X
Michal Domonkos 0b3e36
+/usr/share/doc/hello-2.0 4096 1489670606 0000000000000000000000000000000000000000000000000000000000000000 040755 root root 0 0 0 X
Michal Domonkos 0b3e36
+/usr/share/doc/hello-2.0/COPYING 48 908894882 fac3b28492ecdc16da172a6f1a432ceed356ca4d9248157b2a962b395e37b3b0 0100644 root root 0 1 0 X
Michal Domonkos 0b3e36
+/usr/share/doc/hello-2.0/FAQ 36 908895030 678b87e217a415f05e43460e2c7b668245b412e2b4f18a75aa7399d9774ed0b4 0100644 root root 0 1 0 X
Michal Domonkos 0b3e36
+/usr/share/doc/hello-2.0/README 39 908884468 d63fdc6c986106f57230f217d36b2395d83ecf491d2b7187af714dc8db9629e9 0100644 root root 0 1 0 X
Michal Domonkos 0b3e36
+],
Michal Domonkos 0b3e36
+[])
Michal Domonkos 0b3e36
+AT_CLEANUP
Michal Domonkos 0b3e36
+
Michal Domonkos 0b3e36
 # ------------------------------
Michal Domonkos 0b3e36
 AT_SETUP([rpmspec -q])
Michal Domonkos 0b3e36
 AT_KEYWORDS([query])
Michal Domonkos 0b3e36
-- 
Michal Domonkos 0b3e36
2.35.1
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
From 9b2bc10881db7691439005fd74ea53d75b15ac76 Mon Sep 17 00:00:00 2001
Michal Domonkos 0b3e36
From: Panu Matilainen <pmatilai@redhat.com>
Michal Domonkos 0b3e36
Date: Thu, 10 Feb 2022 11:15:04 +0200
Michal Domonkos 0b3e36
Subject: [PATCH 3/4] Ensure sane string lengths for file digests from header
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
---
Michal Domonkos 0b3e36
 lib/rpmfi.c | 4 ++++
Michal Domonkos 0b3e36
 1 file changed, 4 insertions(+)
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
Michal Domonkos 0b3e36
index af428468c..2dffab3aa 100644
Michal Domonkos 0b3e36
--- a/lib/rpmfi.c
Michal Domonkos 0b3e36
+++ b/lib/rpmfi.c
Michal Domonkos 0b3e36
@@ -1501,6 +1501,10 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
Michal Domonkos 0b3e36
 		t += len;
Michal Domonkos 0b3e36
 		continue;
Michal Domonkos 0b3e36
 	    }
Michal Domonkos 0b3e36
+	    if (strlen(s) != len * 2) {
Michal Domonkos 0b3e36
+		bin = rfree(bin);
Michal Domonkos 0b3e36
+		break;
Michal Domonkos 0b3e36
+	    }
Michal Domonkos 0b3e36
 	    for (int j = 0; j < len; j++, t++, s += 2)
Michal Domonkos 0b3e36
 		*t = (rnibble(s[0]) << 4) | rnibble(s[1]);
Michal Domonkos 0b3e36
 	}
Michal Domonkos 0b3e36
-- 
Michal Domonkos 0b3e36
2.35.1
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
From ddfed9e1842a1b60a8c40de3a18add6f6d68c515 Mon Sep 17 00:00:00 2001
Michal Domonkos 0b3e36
From: Panu Matilainen <pmatilai@redhat.com>
Michal Domonkos 0b3e36
Date: Mon, 29 Nov 2021 14:01:39 +0200
Michal Domonkos 0b3e36
Subject: [PATCH 4/4] Fix IMA signature fubar, take III (#1833, RhBug:2018937)
Michal Domonkos e2e5e2
Michal Domonkos e2e5e2
At least ECDSA and RSA signatures can vary in length, but the IMA code
Michal Domonkos e2e5e2
assumes constant lengths and thus may either place invalid signatures on
Michal Domonkos e2e5e2
disk from either truncating or overshooting, and segfault if the stars are
Michal Domonkos e2e5e2
just so.
Michal Domonkos e2e5e2
Michal Domonkos 0b3e36
As we can't assume static lengths and attempts to use maximum length
Michal Domonkos 0b3e36
have proven problematic for other reasons, use a data structure that
Michal Domonkos 0b3e36
can actually handle variable length data properly: store offsets into
Michal Domonkos 0b3e36
the decoded binary blob and use them to calculate lengths when needed,
Michal Domonkos 0b3e36
empty data is simply consequtive identical offsets. This avoids a whole
Michal Domonkos 0b3e36
class of silly overflow issues with multiplying, makes zero-length data
Michal Domonkos 0b3e36
actually presentable in the data structure and saves memory too.
Michal Domonkos 0b3e36
Michal Domonkos 0b3e36
Add tests to show behavior with variable length signatures and missing
Michal Domonkos 0b3e36
signatures.
Michal Domonkos e2e5e2
Michal Domonkos e2e5e2
Additionally update the signing code to store the largest IMA signature
Michal Domonkos e2e5e2
length rather than what happened to be last to be on the safe side.
Michal Domonkos e2e5e2
We can't rely on this value due to invalid packages being out there,
Michal Domonkos e2e5e2
but then we need to calculate the lengths on rpmfiles populate so there's
Michal Domonkos e2e5e2
not a lot to gain anyhow.
Michal Domonkos e2e5e2
Michal Domonkos e2e5e2
Fixes: #1833
Michal Domonkos e2e5e2
Michal Domonkos 0b3e36
Backported for 4.16.1.3.  Note that the test case has been removed due
Michal Domonkos 0b3e36
to it including a binary file (test package) for which we'd have to use
Michal Domonkos 0b3e36
-Sgit with %autopatch and thus depend on git-core at build time.
Michal Domonkos 0b3e36
Nevertheless, we do have this BZ covered in our internal test suite, so
Michal Domonkos 0b3e36
no need for it anyway.
Michal Domonkos e2e5e2
---
Michal Domonkos 0b3e36
 lib/rpmfi.c         | 61 +++++++++++++++++++++++++++++++++++++++------
Michal Domonkos 0b3e36
 sign/rpmsignfiles.c |  5 +++-
Michal Domonkos 0b3e36
 2 files changed, 58 insertions(+), 8 deletions(-)
Michal Domonkos e2e5e2
Michal Domonkos e2e5e2
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
Michal Domonkos 0b3e36
index 2dffab3aa..77e73442c 100644
Michal Domonkos e2e5e2
--- a/lib/rpmfi.c
Michal Domonkos e2e5e2
+++ b/lib/rpmfi.c
Michal Domonkos 0b3e36
@@ -115,7 +115,7 @@ struct rpmfiles_s {
Michal Domonkos e2e5e2
     struct fingerPrint_s * fps;	/*!< File fingerprint(s). */
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
     int digestalgo;		/*!< File digest algorithm */
Michal Domonkos e2e5e2
-    int signaturelength;	/*!< File signature length */
Michal Domonkos 0b3e36
+    uint32_t *signatureoffs;	/*!< File signature offsets */
Michal Domonkos e2e5e2
     unsigned char * digests;	/*!< File digests in binary. */
Michal Domonkos e2e5e2
     unsigned char * signatures; /*!< File signatures in binary. */
Michal Domonkos e2e5e2
 
Michal Domonkos 0b3e36
@@ -574,10 +574,15 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
Michal Domonkos 0b3e36
     const unsigned char *signature = NULL;
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
     if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
Michal Domonkos 0b3e36
-	if (fi->signatures != NULL)
Michal Domonkos e2e5e2
-	    signature = fi->signatures + (fi->signaturelength * ix);
Michal Domonkos 0b3e36
+	size_t slen = 0;
Michal Domonkos 0b3e36
+	if (fi->signatures != NULL && fi->signatureoffs != NULL) {
Michal Domonkos 0b3e36
+	    uint32_t off = fi->signatureoffs[ix];
Michal Domonkos 0b3e36
+	    slen = fi->signatureoffs[ix+1] - off;
Michal Domonkos 0b3e36
+	    if (slen > 0)
Michal Domonkos 0b3e36
+		signature = fi->signatures + off;
Michal Domonkos 0b3e36
+	}
Michal Domonkos e2e5e2
 	if (len)
Michal Domonkos e2e5e2
-	    *len = fi->signaturelength;
Michal Domonkos 0b3e36
+	    *len = slen;
Michal Domonkos e2e5e2
     }
Michal Domonkos e2e5e2
     return signature;
Michal Domonkos e2e5e2
 }
Michal Domonkos 0b3e36
@@ -1257,6 +1262,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
Michal Domonkos e2e5e2
 	fi->flangs = _free(fi->flangs);
Michal Domonkos e2e5e2
 	fi->digests = _free(fi->digests);
Michal Domonkos e2e5e2
 	fi->signatures = _free(fi->signatures);
Michal Domonkos 0b3e36
+	fi->signatureoffs = _free(fi->signatureoffs);
Michal Domonkos e2e5e2
 	fi->fcaps = _free(fi->fcaps);
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
 	fi->cdict = _free(fi->cdict);
Michal Domonkos 0b3e36
@@ -1485,6 +1491,48 @@ err:
Michal Domonkos 0b3e36
     return;
Michal Domonkos e2e5e2
 }
Michal Domonkos e2e5e2
 
Michal Domonkos 0b3e36
+/*
Michal Domonkos 0b3e36
+ * Convert a tag of variable len hex strings to binary presentation,
Michal Domonkos 0b3e36
+ * accessed via offsets to a contiguous binary blob. Empty values
Michal Domonkos 0b3e36
+ * are represented by identical consequtive offsets. The offsets array
Michal Domonkos 0b3e36
+ * always has one extra element to allow calculating the size of the
Michal Domonkos 0b3e36
+ * last element.
Michal Domonkos 0b3e36
+ */
Michal Domonkos 0b3e36
+static uint8_t *hex2binv(Header h, rpmTagVal tag, rpm_count_t num,
Michal Domonkos 0b3e36
+			uint32_t **offsetp)
Michal Domonkos 0b3e36
+{
Michal Domonkos 0b3e36
+    struct rpmtd_s td;
Michal Domonkos 0b3e36
+    uint8_t *bin = NULL;
Michal Domonkos 0b3e36
+    uint32_t *offs = NULL;
Michal Domonkos 43a9b0
+
Michal Domonkos 0b3e36
+    if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
Michal Domonkos 0b3e36
+	const char *s;
Michal Domonkos 0b3e36
+	int i = 0;
Michal Domonkos 0b3e36
+	uint8_t *t = bin = xmalloc(((rpmtdSize(&td) / 2) + 1));
Michal Domonkos 0b3e36
+	offs = xmalloc((num + 1) * sizeof(*offs));
Michal Domonkos e2e5e2
+
Michal Domonkos 0b3e36
+	while ((s = rpmtdNextString(&td))) {
Michal Domonkos 0b3e36
+	    uint32_t slen = strlen(s);
Michal Domonkos 0b3e36
+	    uint32_t len = slen / 2;
Michal Domonkos 0b3e36
+	    if (slen % 2) {
Michal Domonkos 0b3e36
+		bin = rfree(bin);
Michal Domonkos 0b3e36
+		offs = rfree(offs);
Michal Domonkos 0b3e36
+		goto exit;
Michal Domonkos e2e5e2
+	    }
Michal Domonkos 0b3e36
+	    offs[i] = t - bin;
Michal Domonkos 0b3e36
+	    for (int j = 0; j < len; j++, t++, s += 2)
Michal Domonkos 0b3e36
+		*t = (rnibble(s[0]) << 4) | rnibble(s[1]);
Michal Domonkos 0b3e36
+	    i++;
Michal Domonkos 0b3e36
+	}
Michal Domonkos 0b3e36
+	offs[i] = t - bin;
Michal Domonkos 0b3e36
+	*offsetp = offs;
Michal Domonkos 0b3e36
+    }
Michal Domonkos e2e5e2
+
Michal Domonkos 0b3e36
+exit:
Michal Domonkos 0b3e36
+    rpmtdFreeData(&td);
Michal Domonkos 0b3e36
+    return bin;
Michal Domonkos 0b3e36
+}
Michal Domonkos e2e5e2
+
Michal Domonkos 0b3e36
 /* Convert a tag of hex strings to binary presentation */
Michal Domonkos 0b3e36
 static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
Michal Domonkos 0b3e36
 {
Michal Domonkos 0b3e36
@@ -1580,9 +1628,8 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
Michal Domonkos e2e5e2
     fi->signatures = NULL;
Michal Domonkos e2e5e2
     /* grab hex signatures from header and store in binary format */
Michal Domonkos e2e5e2
     if (!(flags & RPMFI_NOFILESIGNATURES)) {
Michal Domonkos e2e5e2
-	fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
Michal Domonkos e2e5e2
-	fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
Michal Domonkos e2e5e2
-				 totalfc, fi->signaturelength);
Michal Domonkos 0b3e36
+	fi->signatures = hex2binv(h, RPMTAG_FILESIGNATURES,
Michal Domonkos 0b3e36
+				 totalfc, &fi->signatureoffs);
Michal Domonkos e2e5e2
     }
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
Michal Domonkos e2e5e2
diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
Michal Domonkos 0b3e36
index b143c5b9b..372ba634c 100644
Michal Domonkos e2e5e2
--- a/sign/rpmsignfiles.c
Michal Domonkos e2e5e2
+++ b/sign/rpmsignfiles.c
Michal Domonkos e2e5e2
@@ -98,8 +98,9 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
Michal Domonkos e2e5e2
     td.count = 1;
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
     while (rpmfiNext(fi) >= 0) {
Michal Domonkos 0b3e36
+	uint32_t slen = 0;
Michal Domonkos e2e5e2
 	digest = rpmfiFDigest(fi, NULL, NULL);
Michal Domonkos e2e5e2
-	signature = signFile(algoname, digest, diglen, key, keypass, &siglen);
Michal Domonkos e2e5e2
+	signature = signFile(algoname, digest, diglen, key, keypass, &slen);
Michal Domonkos e2e5e2
 	if (!signature) {
Michal Domonkos e2e5e2
 	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));
Michal Domonkos e2e5e2
 	    goto exit;
Michal Domonkos e2e5e2
@@ -110,6 +111,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
Michal Domonkos e2e5e2
 	    goto exit;
Michal Domonkos e2e5e2
 	}
Michal Domonkos e2e5e2
 	signature = _free(signature);
Michal Domonkos e2e5e2
+	if (slen > siglen)
Michal Domonkos e2e5e2
+	    siglen = slen;
Michal Domonkos e2e5e2
     }
Michal Domonkos e2e5e2
 
Michal Domonkos e2e5e2
     if (siglen > 0) {
Michal Domonkos e2e5e2
-- 
Michal Domonkos 0b3e36
2.35.1
Michal Domonkos e2e5e2