|
|
3f3ddd |
From 1f63621d098741158b5e1e7158cc570a415d88cd Mon Sep 17 00:00:00 2001
|
|
|
3f3ddd |
From: Panu Matilainen <pmatilai@redhat.com>
|
|
|
3f3ddd |
Date: Mon, 29 Nov 2021 14:01:39 +0200
|
|
|
3f3ddd |
Subject: [PATCH] Fix IMA signature lengths assumed constant (#1833,
|
|
|
3f3ddd |
RhBug:2018937)
|
|
|
3f3ddd |
|
|
|
3f3ddd |
At least ECDSA and RSA signatures can vary in length, but the IMA code
|
|
|
3f3ddd |
assumes constant lengths and thus may either place invalid signatures on
|
|
|
3f3ddd |
disk from either truncating or overshooting, and segfault if the stars are
|
|
|
3f3ddd |
just so.
|
|
|
3f3ddd |
|
|
|
3f3ddd |
Luckily the signatures are stored as strings so we can calculate the
|
|
|
3f3ddd |
actual lengths at runtime and ignore the stored constant length info.
|
|
|
3f3ddd |
Extend hex2bin() to optionally calculate the lengths and maximum,
|
|
|
3f3ddd |
and use these for returning IMA data from the rpmfi(les) API.
|
|
|
3f3ddd |
|
|
|
3f3ddd |
Additionally update the signing code to store the largest IMA signature
|
|
|
3f3ddd |
length rather than what happened to be last to be on the safe side.
|
|
|
3f3ddd |
We can't rely on this value due to invalid packages being out there,
|
|
|
3f3ddd |
but then we need to calculate the lengths on rpmfiles populate so there's
|
|
|
3f3ddd |
not a lot to gain anyhow.
|
|
|
3f3ddd |
|
|
|
3f3ddd |
Fixes: #1833
|
|
|
3f3ddd |
|
|
|
3f3ddd |
Backported for 4.16.1.3 and combined with:
|
|
|
3f3ddd |
31e9daf823f7052135d1decc0802b6fa775a88c5 (fix-up)
|
|
|
3f3ddd |
0c1ad364d65c4144ff71c376e0b49fbc322b686d (python bindings)
|
|
|
3f3ddd |
|
|
|
3f3ddd |
Note that the test case has been removed due to it including a binary
|
|
|
3f3ddd |
file (test package) for which we'd have to use -Sgit with %autopatch and
|
|
|
3f3ddd |
thus depend on git-core at build time. Nevertheless, we do have this BZ
|
|
|
3f3ddd |
covered in our internal test suite, so no need for it anyway.
|
|
|
3f3ddd |
---
|
|
|
3f3ddd |
lib/rpmfi.c | 59 +++++++++++++++++++++++++++++++++-----------
|
|
|
3f3ddd |
python/rpmfiles-py.c | 18 ++++++++++++++
|
|
|
3f3ddd |
sign/rpmsignfiles.c | 5 +++-
|
|
|
3f3ddd |
3 files changed, 67 insertions(+), 15 deletions(-)
|
|
|
3f3ddd |
|
|
|
3f3ddd |
diff --git a/lib/rpmfi.c b/lib/rpmfi.c
|
|
|
3f3ddd |
index af428468c..ed8927fd5 100644
|
|
|
3f3ddd |
--- a/lib/rpmfi.c
|
|
|
3f3ddd |
+++ b/lib/rpmfi.c
|
|
|
3f3ddd |
@@ -115,7 +115,8 @@ struct rpmfiles_s {
|
|
|
3f3ddd |
struct fingerPrint_s * fps; /*!< File fingerprint(s). */
|
|
|
3f3ddd |
|
|
|
3f3ddd |
int digestalgo; /*!< File digest algorithm */
|
|
|
3f3ddd |
- int signaturelength; /*!< File signature length */
|
|
|
3f3ddd |
+ int *signaturelengths; /*!< File signature lengths */
|
|
|
3f3ddd |
+ int signaturemaxlen; /*!< Largest file signature length */
|
|
|
3f3ddd |
unsigned char * digests; /*!< File digests in binary. */
|
|
|
3f3ddd |
unsigned char * signatures; /*!< File signatures in binary. */
|
|
|
3f3ddd |
|
|
|
3f3ddd |
@@ -575,9 +576,9 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
|
|
|
3f3ddd |
|
|
|
3f3ddd |
if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
|
|
|
3f3ddd |
if (fi->signatures != NULL)
|
|
|
3f3ddd |
- signature = fi->signatures + (fi->signaturelength * ix);
|
|
|
3f3ddd |
+ signature = fi->signatures + (fi->signaturemaxlen * ix);
|
|
|
3f3ddd |
if (len)
|
|
|
3f3ddd |
- *len = fi->signaturelength;
|
|
|
3f3ddd |
+ *len = fi->signaturelengths ? fi->signaturelengths[ix] : 0;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
return signature;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
@@ -1257,6 +1258,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
|
|
|
3f3ddd |
fi->flangs = _free(fi->flangs);
|
|
|
3f3ddd |
fi->digests = _free(fi->digests);
|
|
|
3f3ddd |
fi->signatures = _free(fi->signatures);
|
|
|
3f3ddd |
+ fi->signaturelengths = _free(fi->signaturelengths);
|
|
|
3f3ddd |
fi->fcaps = _free(fi->fcaps);
|
|
|
3f3ddd |
|
|
|
3f3ddd |
fi->cdict = _free(fi->cdict);
|
|
|
3f3ddd |
@@ -1486,23 +1488,52 @@ err:
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
|
|
|
3f3ddd |
/* Convert a tag of hex strings to binary presentation */
|
|
|
3f3ddd |
-static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
|
|
|
3f3ddd |
+/* If lengths is non-NULL, assume variable length strings */
|
|
|
3f3ddd |
+static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len,
|
|
|
3f3ddd |
+ int **lengths, int *maxlen)
|
|
|
3f3ddd |
{
|
|
|
3f3ddd |
struct rpmtd_s td;
|
|
|
3f3ddd |
uint8_t *bin = NULL;
|
|
|
3f3ddd |
|
|
|
3f3ddd |
if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
|
|
|
3f3ddd |
- uint8_t *t = bin = xmalloc(num * len);
|
|
|
3f3ddd |
const char *s;
|
|
|
3f3ddd |
+ int maxl = 0;
|
|
|
3f3ddd |
+ int *lens = NULL;
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
+ /* Figure string sizes + max length for allocation purposes */
|
|
|
3f3ddd |
+ if (lengths) {
|
|
|
3f3ddd |
+ int i = 0;
|
|
|
3f3ddd |
+ lens = xmalloc(num * sizeof(*lens));
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
+ while ((s = rpmtdNextString(&td))) {
|
|
|
3f3ddd |
+ lens[i] = strlen(s) / 2;
|
|
|
3f3ddd |
+ if (lens[i] > maxl)
|
|
|
3f3ddd |
+ maxl = lens[i];
|
|
|
3f3ddd |
+ i++;
|
|
|
3f3ddd |
+ }
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
+ *lengths = lens;
|
|
|
3f3ddd |
+ *maxlen = maxl;
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
+ /* Reinitialize iterator for next round */
|
|
|
3f3ddd |
+ rpmtdInit(&td);
|
|
|
3f3ddd |
+ } else {
|
|
|
3f3ddd |
+ maxl = len;
|
|
|
3f3ddd |
+ }
|
|
|
3f3ddd |
|
|
|
3f3ddd |
+ uint8_t *t = bin = xmalloc(num * maxl);
|
|
|
3f3ddd |
+ int i = 0;
|
|
|
3f3ddd |
while ((s = rpmtdNextString(&td))) {
|
|
|
3f3ddd |
if (*s == '\0') {
|
|
|
3f3ddd |
- memset(t, 0, len);
|
|
|
3f3ddd |
- t += len;
|
|
|
3f3ddd |
- continue;
|
|
|
3f3ddd |
+ memset(t, 0, maxl);
|
|
|
3f3ddd |
+ } else {
|
|
|
3f3ddd |
+ if (lens)
|
|
|
3f3ddd |
+ len = lens[i];
|
|
|
3f3ddd |
+ for (int j = 0; j < len; j++, s += 2)
|
|
|
3f3ddd |
+ t[j] = (rnibble(s[0]) << 4) | rnibble(s[1]);
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
- for (int j = 0; j < len; j++, t++, s += 2)
|
|
|
3f3ddd |
- *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
|
|
|
3f3ddd |
+ t += maxl;
|
|
|
3f3ddd |
+ i++;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
rpmtdFreeData(&td);
|
|
|
3f3ddd |
@@ -1570,15 +1601,15 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
|
|
|
3f3ddd |
/* grab hex digests from header and store in binary format */
|
|
|
3f3ddd |
if (!(flags & RPMFI_NOFILEDIGESTS)) {
|
|
|
3f3ddd |
size_t diglen = rpmDigestLength(fi->digestalgo);
|
|
|
3f3ddd |
- fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen);
|
|
|
3f3ddd |
+ fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen,
|
|
|
3f3ddd |
+ NULL, NULL);
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
|
|
|
3f3ddd |
fi->signatures = NULL;
|
|
|
3f3ddd |
/* grab hex signatures from header and store in binary format */
|
|
|
3f3ddd |
if (!(flags & RPMFI_NOFILESIGNATURES)) {
|
|
|
3f3ddd |
- fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
|
|
|
3f3ddd |
- fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
|
|
|
3f3ddd |
- totalfc, fi->signaturelength);
|
|
|
3f3ddd |
+ fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES, totalfc, 0,
|
|
|
3f3ddd |
+ &fi->signaturelengths, &fi->signaturemaxlen);
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
|
|
|
3f3ddd |
/* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
|
|
|
3f3ddd |
diff --git a/python/rpmfiles-py.c b/python/rpmfiles-py.c
|
|
|
3f3ddd |
index 27666021d..48189a0ac 100644
|
|
|
3f3ddd |
--- a/python/rpmfiles-py.c
|
|
|
3f3ddd |
+++ b/python/rpmfiles-py.c
|
|
|
3f3ddd |
@@ -152,6 +152,22 @@ static PyObject *rpmfile_digest(rpmfileObject *s)
|
|
|
3f3ddd |
Py_RETURN_NONE;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
|
|
|
3f3ddd |
+static PyObject *bytebuf(const unsigned char *buf, size_t len)
|
|
|
3f3ddd |
+{
|
|
|
3f3ddd |
+ if (buf) {
|
|
|
3f3ddd |
+ PyObject *o = PyBytes_FromStringAndSize((const char *)buf, len);
|
|
|
3f3ddd |
+ return o;
|
|
|
3f3ddd |
+ }
|
|
|
3f3ddd |
+ Py_RETURN_NONE;
|
|
|
3f3ddd |
+}
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
+static PyObject *rpmfile_imasig(rpmfileObject *s)
|
|
|
3f3ddd |
+{
|
|
|
3f3ddd |
+ size_t len = 0;
|
|
|
3f3ddd |
+ const unsigned char *sig = rpmfilesFSignature(s->files, s->ix, &len;;
|
|
|
3f3ddd |
+ return bytebuf(sig, len);
|
|
|
3f3ddd |
+}
|
|
|
3f3ddd |
+
|
|
|
3f3ddd |
static PyObject *rpmfile_class(rpmfileObject *s)
|
|
|
3f3ddd |
{
|
|
|
3f3ddd |
return utf8FromString(rpmfilesFClass(s->files, s->ix));
|
|
|
3f3ddd |
@@ -278,6 +294,8 @@ static PyGetSetDef rpmfile_getseters[] = {
|
|
|
3f3ddd |
"language the file provides (typically for doc files)" },
|
|
|
3f3ddd |
{ "caps", (getter) rpmfile_caps, NULL,
|
|
|
3f3ddd |
"file capabilities" },
|
|
|
3f3ddd |
+ { "imasig", (getter) rpmfile_imasig, NULL,
|
|
|
3f3ddd |
+ "IMA signature" },
|
|
|
3f3ddd |
{ NULL, NULL, NULL, NULL }
|
|
|
3f3ddd |
};
|
|
|
3f3ddd |
|
|
|
3f3ddd |
diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
|
|
|
3f3ddd |
index b143c5b9b..6f39db6be 100644
|
|
|
3f3ddd |
--- a/sign/rpmsignfiles.c
|
|
|
3f3ddd |
+++ b/sign/rpmsignfiles.c
|
|
|
3f3ddd |
@@ -98,8 +98,9 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
|
|
|
3f3ddd |
td.count = 1;
|
|
|
3f3ddd |
|
|
|
3f3ddd |
while (rpmfiNext(fi) >= 0) {
|
|
|
3f3ddd |
+ uint32_t slen;
|
|
|
3f3ddd |
digest = rpmfiFDigest(fi, NULL, NULL);
|
|
|
3f3ddd |
- signature = signFile(algoname, digest, diglen, key, keypass, &siglen);
|
|
|
3f3ddd |
+ signature = signFile(algoname, digest, diglen, key, keypass, &slen);
|
|
|
3f3ddd |
if (!signature) {
|
|
|
3f3ddd |
rpmlog(RPMLOG_ERR, _("signFile failed\n"));
|
|
|
3f3ddd |
goto exit;
|
|
|
3f3ddd |
@@ -110,6 +111,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
|
|
|
3f3ddd |
goto exit;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
signature = _free(signature);
|
|
|
3f3ddd |
+ if (slen > siglen)
|
|
|
3f3ddd |
+ siglen = slen;
|
|
|
3f3ddd |
}
|
|
|
3f3ddd |
|
|
|
3f3ddd |
if (siglen > 0) {
|
|
|
3f3ddd |
--
|
|
|
3f3ddd |
2.33.1
|
|
|
3f3ddd |
|