New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix IMA signature lengths assumed constant (#1833, RhBug:2018937) #1844
Fix IMA signature lengths assumed constant (#1833, RhBug:2018937) #1844
Conversation
Should there be tests for this too? |
In a better world, yes of course. It's just that we don't have any good means to test it, because our test-suite expects to run non-root so applying IMA signatures is a non-starter, and plugins are disabled in the test-suite due to other artifacts. Even testing signing is pending for somebody to sit down and figure how to do it in the environment. One could test the API returns of course, but this stuff isn't exposed to Python bindings, sigh. |
RSA sigs can also vary in length. Leading zeros of the exponentiation result will be stripped, so there's a 1/256 chance that the sig is smaller than expected. |
Oh, right. Remember running into those "missing zeros" on occasion... |
ee305ab
to
8fa91f3
Compare
Rebased on top of #1847 for access to the data from Python, test added and commit message adjusted to list RSA as variable length too. |
@pmatilai This PR is behaving oddly, it shows me the Python data access commit even though that's already present in git master. Perhaps you need to rebase again? |
8fa91f3
to
feb9b52
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall but see inline comment.
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually correct, given that the lengths can now vary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a proof that this cannot overflow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this should have just been signaturelengths[ix]
but somehow got missed. Or I'm missing something (non)obvious here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is an integer overflow with potentially bad consequences.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rpmfi.c is likely one big integer overflow if you go looking, the overall assumption in the codebase (in this file and basically everywhere) is that they don't overflow. Which is why I'm not going to bother with this one either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said a limit on signature lengths would be another approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The header is size-capped to 256MB, there's a limit for you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...and here's another: #1858
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually correct, given that the lengths can now vary?
So @dmnks actually did point out the flaw in this patch but it got lost in all the noise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...except that this isn't the flaw, only pointing to the general direction. The real flaw is in the part of hex2bin() that's not touched in this patch so it's hard to spot.
lib/rpmfi.c
Outdated
@@ -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 length */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cosmetic but the comment should be pluralized too 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a few areas where I would like to see a proof of no integer overflow.
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a proof that this cannot overflow?
/* Figure string sizes + max length for allocation purposes */ | ||
if (lengths) { | ||
int maxl = 0; | ||
int *lens = xmalloc(num * sizeof(*lens)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int *lens = xmalloc(num * sizeof(*lens)); | |
int *lens = xcalloc(num, sizeof(*lens)); |
This is safer in the event of an overflow.
int i = 0; | ||
|
||
while ((s = rpmtdNextString(&td))) { | ||
lens[i] = strlen(s) / 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if strlen(s)
is odd? That should be an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the assumption here is that a hex string will always be even (one byte is represented by two chars), but otherwise yeah, we should probably have a check here as we can't fully control the input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, these tags should be sanity checked along everything else in the signature header, but that doesn't currently happen for data that is not used for content checking. The same goes for fsverity signatures. Not that it matters a whole lot, the signature will be invalid in that case anyhow.
, RhBug:2018937) 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: rpm-software-management#1833
feb9b52
to
1699a8b
Compare
FWIW, there appear to be other flaws in the patch, as in segfaults in some circumstances. Will fix of course once I manage to reproduce, but just goes to show that reviews should be concentrating on the actual change. Not theory. |
Yep, this PR was utter garbage. Anybody needing to cherry-pick the IMA fix, be sure to include commit 31e9daf too. |
ECDSA 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