alexk / rpms / rpm

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