Fix base64 decoding on platforms where char is unsigned - #79
Open
eastagiletracker wants to merge 1 commit into
Open
Fix base64 decoding on platforms where char is unsigned#79eastagiletracker wants to merge 1 commit into
eastagiletracker wants to merge 1 commit into
Conversation
base64_decode_value() stored its decoding table in a plain char array and
returned its sentinels (-1 for a non-alphabet octet, -2 for '=') through a
char. On AArch64, ppc64 and s390x, where char is unsigned by default, those
sentinels come back as 255 and 254, so the "while (fragment < 0)" loops in
base64_decode_block() never skip padding or embedded whitespace. The skipped
octets are folded into the output instead, so wdns_str_to_rdata() returns
longer, corrupted rdata for every base64-encoded type (DNSKEY, CDNSKEY,
OPENPGPKEY, RRSIG, ...).
Use a signed char table, compute the table offset in an int, and hold the
fragment in an int so the sentinels survive. Also make the bounds check
reject an offset equal to the table size: '{' produced offset 80 on an
80-element table, a one-past-the-end read that decoded as a valid value.
Add t/test-b64_decode covering the sentinels, padding and embedded
whitespace.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR proposes fixing base64 decoding on platforms where
charis unsigned, which corrupts DNSKEY, CDNSKEY, RRSIG and OPENPGPKEY rdata on AArch64 (fixes #70). We include this PR work along with a full history of your repo at https://eastagiletracker.com/projects/387. You can sign in with your GitHub ID to claim ownership of the project.The defect
base64_decode_value()inlibmy/b64_decode.ckeeps its decoding table in a plainchararray and signals "not a base64 alphabet octet" by returning a negative sentinel (-1, and-2for=). On AArch64, ppc64le and s390x, wherecharis unsigned by default, those sentinels come back as255and254. The fourwhile (fragment < 0)loops inbase64_decode_block()therefore never skip anything: padding and the whitespace that separates presentation-format key chunks are folded into the output as if they were real base64 digits.wdns_str_to_rdata()(wdns/str_to_rdata_ubuf.c:93) is the direct caller, so every base64-encoded rdata type comes back longer and silently wrong — thelen 140 != 134and trailing>byte in the report.While confirming that, I also found a one-past-the-end read in the same bounds check:
value_in > decoding_sizeadmitsvalue_in == 80on an 80-element table. The character{hits it, and on this machine it read back65, so{decodes as a valid base64 value instead of being rejected. That one is not platform-dependent.The change
decoding[]becomessigned char, the table offset is computed in anintfrom(unsigned char) value_in,fragmentbecomes anint, and the bounds check uses>=. Behavior on signed-charplatforms is unchanged: for octets>= 0x80the old code went negative before the comparison and returned-1, and the new code produces an offset>= 80and returns-1as well.Reproduction at current HEAD
AArch64's ABI is
unsigned char, so-funsigned-charreproduces it on any host. Onmaster(c308fe8):That is the same 5-pass/2-fail split as the report, with the same failing cases:
Verification
A new
t/test-b64_decodecovers the sentinels,=padding and embedded whitespace, following the patternt/test-fast_inet_ntopuses forlibmycode. It is red on the unpatched tree in both configurations — 11 failures under-funsigned-char, and 1 failure in a default build from the{out-of-bounds read:With the patch applied, both configurations are fully green and nothing that passed before regressed:
The real consumer path is covered by your own suite:
t/test-str_to_rdataandt/test-rdataround-trip DNSKEY, CDNSKEY, RRSIG and OPENPGPKEY throughwdns_str_to_rdata(), and both go from failing to passing under-funsigned-char.No public signature, dependency or build setting changed. I left
ChangeLogalone to avoid colliding with #78.How this was managed
We imported your issues and pull requests into a live agile board — 78 stories and 1 label — and worked this change on the story for issue #70: https://eastagiletracker.com/projects/387/stories/260343. The board itself is at https://eastagiletracker.com/projects/387.
If you'd rather not receive contributions like this, reply
no-more-prson this pull request and we won't open any further ones on your repositories.Lawrence W. Sinclair
CEO / East Agile
linkedin.com/in/lwsinclair/
eastagile.com