|
Richard Phibel |
3de522 |
From 07f1d3132f0c7b7ecb69a47a9930edb534a9250e Mon Sep 17 00:00:00 2001
|
|
Richard Phibel |
3de522 |
From: Panu Matilainen <pmatilai@redhat.com>
|
|
Richard Phibel |
3de522 |
Date: Mon, 7 Feb 2022 13:38:48 +0200
|
|
Richard Phibel |
3de522 |
Subject: [PATCH] Fix IMA signature fubar, take III (#1833, RhBug:2018937)
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
At least ECDSA and RSA signatures can vary in length, but the IMA code
|
|
Richard Phibel |
3de522 |
assumes constant lengths and thus may either place invalid signatures on
|
|
Richard Phibel |
3de522 |
disk from either truncating or overshooting, and segfault if the stars are
|
|
Richard Phibel |
3de522 |
just so.
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
As we can't assume static lengths and attempts to use maximum length
|
|
Richard Phibel |
3de522 |
have proven problematic for other reasons, use a data structure that
|
|
Richard Phibel |
3de522 |
can actually handle variable length data properly: store offsets into
|
|
Richard Phibel |
3de522 |
the decoded binary blob and use them to calculate lengths when needed,
|
|
Richard Phibel |
3de522 |
empty data is simply consequtive identical offsets. This avoids a whole
|
|
Richard Phibel |
3de522 |
class of silly overflow issues with multiplying, makes zero-length data
|
|
Richard Phibel |
3de522 |
actually presentable in the data structure and saves memory too.
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
Add tests to show behavior with variable length signatures and missing
|
|
Richard Phibel |
3de522 |
signatures.
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
Additionally update the signing code to store the largest IMA signature
|
|
Richard Phibel |
3de522 |
length rather than what happened to be last to be on the safe side.
|
|
Richard Phibel |
3de522 |
We can't rely on this value due to invalid packages being out there,
|
|
Richard Phibel |
3de522 |
but then we need to calculate the lengths on rpmfiles populate so there's
|
|
Richard Phibel |
3de522 |
not a lot to gain anyhow.
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
Fixes: #1833
|
|
Richard Phibel |
3de522 |
---
|
|
Richard Phibel |
3de522 |
lib/rpmfi.c | 61 +++++++++++++++++++++++++++++++++++++++------
|
|
Richard Phibel |
3de522 |
sign/rpmsignfiles.c | 5 +++-
|
|
Richard Phibel |
3de522 |
2 files changed, 58 insertions(+), 8 deletions(-)
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
|
|
Richard Phibel |
3de522 |
index 439179689..4673fbb85 100644
|
|
Richard Phibel |
3de522 |
--- a/lib/rpmfi.c
|
|
Richard Phibel |
3de522 |
+++ b/lib/rpmfi.c
|
|
Richard Phibel |
3de522 |
@@ -116,7 +116,7 @@ struct rpmfiles_s {
|
|
Richard Phibel |
3de522 |
struct fingerPrint_s * fps; /*!< File fingerprint(s). */
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
int digestalgo; /*!< File digest algorithm */
|
|
Richard Phibel |
3de522 |
- int signaturelength; /*!< File signature length */
|
|
Richard Phibel |
3de522 |
+ uint32_t *signatureoffs; /*!< File signature offsets */
|
|
Richard Phibel |
3de522 |
int veritysiglength; /*!< Verity signature length */
|
|
Richard Phibel |
3de522 |
uint16_t verityalgo; /*!< Verity algorithm */
|
|
Richard Phibel |
3de522 |
unsigned char * digests; /*!< File digests in binary. */
|
|
Richard Phibel |
3de522 |
@@ -566,10 +566,15 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
|
|
Richard Phibel |
3de522 |
const unsigned char *signature = NULL;
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
|
|
Richard Phibel |
3de522 |
- if (fi->signatures != NULL)
|
|
Richard Phibel |
3de522 |
- signature = fi->signatures + (fi->signaturelength * ix);
|
|
Richard Phibel |
3de522 |
+ size_t slen = 0;
|
|
Richard Phibel |
3de522 |
+ if (fi->signatures != NULL && fi->signatureoffs != NULL) {
|
|
Richard Phibel |
3de522 |
+ uint32_t off = fi->signatureoffs[ix];
|
|
Richard Phibel |
3de522 |
+ slen = fi->signatureoffs[ix+1] - off;
|
|
Richard Phibel |
3de522 |
+ if (slen > 0)
|
|
Richard Phibel |
3de522 |
+ signature = fi->signatures + off;
|
|
Richard Phibel |
3de522 |
+ }
|
|
Richard Phibel |
3de522 |
if (len)
|
|
Richard Phibel |
3de522 |
- *len = fi->signaturelength;
|
|
Richard Phibel |
3de522 |
+ *len = slen;
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
return signature;
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
@@ -1242,6 +1247,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
|
|
Richard Phibel |
3de522 |
fi->flangs = _free(fi->flangs);
|
|
Richard Phibel |
3de522 |
fi->digests = _free(fi->digests);
|
|
Richard Phibel |
3de522 |
fi->signatures = _free(fi->signatures);
|
|
Richard Phibel |
3de522 |
+ fi->signatureoffs = _free(fi->signatureoffs);
|
|
Richard Phibel |
3de522 |
fi->veritysigs = _free(fi->veritysigs);
|
|
Richard Phibel |
3de522 |
fi->fcaps = _free(fi->fcaps);
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
@@ -1471,6 +1477,48 @@ err:
|
|
Richard Phibel |
3de522 |
return;
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
+/*
|
|
Richard Phibel |
3de522 |
+ * Convert a tag of variable len hex strings to binary presentation,
|
|
Richard Phibel |
3de522 |
+ * accessed via offsets to a contiguous binary blob. Empty values
|
|
Richard Phibel |
3de522 |
+ * are represented by identical consequtive offsets. The offsets array
|
|
Richard Phibel |
3de522 |
+ * always has one extra element to allow calculating the size of the
|
|
Richard Phibel |
3de522 |
+ * last element.
|
|
Richard Phibel |
3de522 |
+ */
|
|
Richard Phibel |
3de522 |
+static uint8_t *hex2binv(Header h, rpmTagVal tag, rpm_count_t num,
|
|
Richard Phibel |
3de522 |
+ uint32_t **offsetp)
|
|
Richard Phibel |
3de522 |
+{
|
|
Richard Phibel |
3de522 |
+ struct rpmtd_s td;
|
|
Richard Phibel |
3de522 |
+ uint8_t *bin = NULL;
|
|
Richard Phibel |
3de522 |
+ uint32_t *offs = NULL;
|
|
Richard Phibel |
3de522 |
+
|
|
Richard Phibel |
3de522 |
+ if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
|
|
Richard Phibel |
3de522 |
+ const char *s;
|
|
Richard Phibel |
3de522 |
+ int i = 0;
|
|
Richard Phibel |
3de522 |
+ uint8_t *t = bin = xmalloc(((rpmtdSize(&td) / 2) + 1));
|
|
Richard Phibel |
3de522 |
+ offs = xmalloc((num + 1) * sizeof(*offs));
|
|
Richard Phibel |
3de522 |
+
|
|
Richard Phibel |
3de522 |
+ while ((s = rpmtdNextString(&td))) {
|
|
Richard Phibel |
3de522 |
+ uint32_t slen = strlen(s);
|
|
Richard Phibel |
3de522 |
+ uint32_t len = slen / 2;
|
|
Richard Phibel |
3de522 |
+ if (slen % 2) {
|
|
Richard Phibel |
3de522 |
+ bin = rfree(bin);
|
|
Richard Phibel |
3de522 |
+ offs = rfree(offs);
|
|
Richard Phibel |
3de522 |
+ goto exit;
|
|
Richard Phibel |
3de522 |
+ }
|
|
Richard Phibel |
3de522 |
+ offs[i] = t - bin;
|
|
Richard Phibel |
3de522 |
+ for (int j = 0; j < len; j++, t++, s += 2)
|
|
Richard Phibel |
3de522 |
+ *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
|
|
Richard Phibel |
3de522 |
+ i++;
|
|
Richard Phibel |
3de522 |
+ }
|
|
Richard Phibel |
3de522 |
+ offs[i] = t - bin;
|
|
Richard Phibel |
3de522 |
+ *offsetp = offs;
|
|
Richard Phibel |
3de522 |
+ }
|
|
Richard Phibel |
3de522 |
+
|
|
Richard Phibel |
3de522 |
+exit:
|
|
Richard Phibel |
3de522 |
+ rpmtdFreeData(&td);
|
|
Richard Phibel |
3de522 |
+ return bin;
|
|
Richard Phibel |
3de522 |
+}
|
|
Richard Phibel |
3de522 |
+
|
|
Richard Phibel |
3de522 |
/* Convert a tag of hex strings to binary presentation */
|
|
Richard Phibel |
3de522 |
static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
|
|
Richard Phibel |
3de522 |
{
|
|
Richard Phibel |
3de522 |
@@ -1623,9 +1671,8 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
|
|
Richard Phibel |
3de522 |
fi->signatures = NULL;
|
|
Richard Phibel |
3de522 |
/* grab hex signatures from header and store in binary format */
|
|
Richard Phibel |
3de522 |
if (!(flags & RPMFI_NOFILESIGNATURES)) {
|
|
Richard Phibel |
3de522 |
- fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
|
|
Richard Phibel |
3de522 |
- fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
|
|
Richard Phibel |
3de522 |
- totalfc, fi->signaturelength);
|
|
Richard Phibel |
3de522 |
+ fi->signatures = hex2binv(h, RPMTAG_FILESIGNATURES,
|
|
Richard Phibel |
3de522 |
+ totalfc, &fi->signatureoffs);
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
fi->veritysigs = NULL;
|
|
Richard Phibel |
3de522 |
diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
|
|
Richard Phibel |
3de522 |
index b143c5b9b..372ba634c 100644
|
|
Richard Phibel |
3de522 |
--- a/sign/rpmsignfiles.c
|
|
Richard Phibel |
3de522 |
+++ b/sign/rpmsignfiles.c
|
|
Richard Phibel |
3de522 |
@@ -98,8 +98,9 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
|
|
Richard Phibel |
3de522 |
td.count = 1;
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
while (rpmfiNext(fi) >= 0) {
|
|
Richard Phibel |
3de522 |
+ uint32_t slen = 0;
|
|
Richard Phibel |
3de522 |
digest = rpmfiFDigest(fi, NULL, NULL);
|
|
Richard Phibel |
3de522 |
- signature = signFile(algoname, digest, diglen, key, keypass, &siglen);
|
|
Richard Phibel |
3de522 |
+ signature = signFile(algoname, digest, diglen, key, keypass, &slen);
|
|
Richard Phibel |
3de522 |
if (!signature) {
|
|
Richard Phibel |
3de522 |
rpmlog(RPMLOG_ERR, _("signFile failed\n"));
|
|
Richard Phibel |
3de522 |
goto exit;
|
|
Richard Phibel |
3de522 |
@@ -110,6 +111,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
|
|
Richard Phibel |
3de522 |
goto exit;
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
signature = _free(signature);
|
|
Richard Phibel |
3de522 |
+ if (slen > siglen)
|
|
Richard Phibel |
3de522 |
+ siglen = slen;
|
|
Richard Phibel |
3de522 |
}
|
|
Richard Phibel |
3de522 |
|
|
Richard Phibel |
3de522 |
if (siglen > 0) {
|
|
Richard Phibel |
3de522 |
--
|
|
Richard Phibel |
3de522 |
2.40.1
|
|
Richard Phibel |
3de522 |
|