Skip to content

Commit

Permalink
Fix IMA signature lengths assumed constant (#1833, RhBug:2018937)
Browse files Browse the repository at this point in the history
At least ECDSA and RSA signatures can vary in length, but the IMA code
assumes constant lengths and thus may either place invalid signatures on
disk from either truncating or overshooting, and segfault if the stars are
just so.

Luckily the signatures are stored as strings so we can calculate the
actual lengths at runtime and ignore the stored constant length info.
Extend hex2bin() to optionally calculate the lengths and maximum,
and use these for returning IMA data from the rpmfi(les) API.

Additionally update the signing code to store the largest IMA signature
length rather than what happened to be last to be on the safe side.
We can't rely on this value due to invalid packages being out there,
but then we need to calculate the lengths on rpmfiles populate so there's
not a lot to gain anyhow.

Fixes: #1833
  • Loading branch information
pmatilai committed Dec 13, 2021
1 parent 0c1ad36 commit 1699a8b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 10 deletions.
43 changes: 34 additions & 9 deletions lib/rpmfi.c
Expand Up @@ -116,7 +116,8 @@ struct rpmfiles_s {
struct fingerPrint_s * fps; /*!< File fingerprint(s). */

int digestalgo; /*!< File digest algorithm */
int signaturelength; /*!< File signature length */
int *signaturelengths; /*!< File signature lengths */
int signaturemaxlen; /*!< Largest file signature length */
int veritysiglength; /*!< Verity signature length */
uint16_t verityalgo; /*!< Verity algorithm */
unsigned char * digests; /*!< File digests in binary. */
Expand Down Expand Up @@ -579,9 +580,9 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)

if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
if (fi->signatures != NULL)
signature = fi->signatures + (fi->signaturelength * ix);
signature = fi->signatures + (fi->signaturemaxlen * ix);
if (len)
*len = fi->signaturelength;
*len = fi->signaturelengths[ix];
}
return signature;
}
Expand Down Expand Up @@ -1277,6 +1278,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
fi->flangs = _free(fi->flangs);
fi->digests = _free(fi->digests);
fi->signatures = _free(fi->signatures);
fi->signaturelengths = _free(fi->signaturelengths);
fi->veritysigs = _free(fi->veritysigs);
fi->fcaps = _free(fi->fcaps);

Expand Down Expand Up @@ -1507,15 +1509,38 @@ static void rpmfilesBuildNLink(rpmfiles fi, Header h)
}

/* Convert a tag of hex strings to binary presentation */
static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
/* If lengths is non-NULL, assume variable length strings */
static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len,
int **lengths, int *maxlen)
{
struct rpmtd_s td;
uint8_t *bin = NULL;

if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) == num) {
uint8_t *t = bin = xmalloc(num * len);
const char *s;

/* Figure string sizes + max length for allocation purposes */
if (lengths) {
int maxl = 0;
int *lens = xmalloc(num * sizeof(*lens));
int i = 0;

while ((s = rpmtdNextString(&td))) {
lens[i] = strlen(s) / 2;
if (lens[i] > maxl)
maxl = lens[i];
i++;
}

*lengths = lens;
*maxlen = maxl;
len = maxl;

/* Reinitialize iterator for next round */
rpmtdInit(&td);
}

uint8_t *t = bin = xmalloc(num * len);
while ((s = rpmtdNextString(&td))) {
if (*s == '\0') {
memset(t, 0, len);
Expand Down Expand Up @@ -1648,15 +1673,15 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
/* grab hex digests from header and store in binary format */
if (!(flags & RPMFI_NOFILEDIGESTS)) {
size_t diglen = rpmDigestLength(fi->digestalgo);
fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen);
fi->digests = hex2bin(h, RPMTAG_FILEDIGESTS, totalfc, diglen,
NULL, NULL);
}

fi->signatures = NULL;
/* grab hex signatures from header and store in binary format */
if (!(flags & RPMFI_NOFILESIGNATURES)) {
fi->signaturelength = headerGetNumber(h, RPMTAG_FILESIGNATURELENGTH);
fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES,
totalfc, fi->signaturelength);
fi->signatures = hex2bin(h, RPMTAG_FILESIGNATURES, totalfc, 0,
&fi->signaturelengths, &fi->signaturemaxlen);
}

fi->veritysigs = NULL;
Expand Down
5 changes: 4 additions & 1 deletion sign/rpmsignfiles.c
Expand Up @@ -98,8 +98,9 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
td.count = 1;

while (rpmfiNext(fi) >= 0) {
uint32_t slen;
digest = rpmfiFDigest(fi, NULL, NULL);
signature = signFile(algoname, digest, diglen, key, keypass, &siglen);
signature = signFile(algoname, digest, diglen, key, keypass, &slen);
if (!signature) {
rpmlog(RPMLOG_ERR, _("signFile failed\n"));
goto exit;
Expand All @@ -110,6 +111,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
goto exit;
}
signature = _free(signature);
if (slen > siglen)
siglen = slen;
}

if (siglen > 0) {
Expand Down
1 change: 1 addition & 0 deletions tests/Makefile.am
Expand Up @@ -101,6 +101,7 @@ EXTRA_DIST += data/RPMS/hello-2.0-1.i686.rpm
EXTRA_DIST += data/RPMS/hello-2.0-1.x86_64.rpm
EXTRA_DIST += data/RPMS/hello-2.0-1.x86_64-signed.rpm
EXTRA_DIST += data/RPMS/hlinktest-1.0-1.noarch.rpm
EXTRA_DIST += data/RPMS/imatest-1.0-1.fc34.noarch.rpm
EXTRA_DIST += data/SRPMS/foo-1.0-1.src.rpm
EXTRA_DIST += data/SRPMS/hello-1.0-1.src.rpm
EXTRA_DIST += data/SOURCES/hello.c
Expand Down
Binary file added tests/data/RPMS/imatest-1.0-1.fc34.noarch.rpm
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/rpmpython.at
Expand Up @@ -602,6 +602,17 @@ for f in fi:
],
[])

RPMPY_TEST([file sets 1],[
ts = rpm.ts()
h = ts.hdrFromFdno('${RPMDATA}/RPMS/imatest-1.0-1.fc34.noarch.rpm')
files = rpm.files(h)
for f in files:
myprint('%s: %s' % (f.name, f.imasig.hex()))
],
[/usr/share/example1: 030204a598255400483046022100e5117bdafa73baaeb1f1dc46ecaa46981a62d417745a33532572b63dc6d95d16022100c789107ac5b91e2d915e1df3c7b78414f6b3f50899d44c1de381d0e938dfc82b
/usr/share/example2: 030204a598255400473045022100c10943795bff5d9c0db53dd4f8e4b845615fd08a2be295c30a80f5bdb4e6a41302203038840cc6abaab92acb56cb3e3ce520b17f22ff7444a8d5d0f703a44d5307a3
],
[])
RPMPY_TEST([string pool 1],[
p = rpm.strpool()
for s in ['foo', 'bar', 'foo', 'zoo']:
Expand Down

0 comments on commit 1699a8b

Please sign in to comment.