Skip to content

Fix shift-exponent UB in PGX decoder - #427

Open
iliasabk wants to merge 1 commit into
jasper-software:masterfrom
iliasabk:fix/pgx-shift-ub
Open

iliasabk wants to merge 1 commit into
jasper-software:masterfrom
iliasabk:fix/pgx-shift-ub

Conversation

@iliasabk

Copy link
Copy Markdown

Summary

Fixes #414 — crafted .pgx headers trigger undefined behavior at two sites:

  • pgx_getword(): val &= (JAS_CAST(uint_fast32_t, 1) << prec) - 1 — for prec = 32 the shift exponent is out of range for 32-bit uint_fast32_t
  • pgx_wordtoint(): (1 << prec), (1 << (prec - 1)) — same problem for prec = 32, and prec = 0 shifts by -1

Fix

  • Mask and sign-extension math now use uint_fast64_t/jas_seqent_t, mirroring the bitstoint() fix pattern
  • Header validation now rejects prec < 1 (a zero-bit precision is meaningless and previously slipped through to the prec - 1 shift)

Testing

Reproduced with the PoC attached to #414 under UBSan:

pgx_dec.c:372:37: runtime error: shift exponent 32 is too large for 32-bit type 'uint_fast32_t'
pgx_dec.c:527:10: runtime error: shift exponent 32 is too large for 32-bit type 'int'

After the patch: no sanitizer report; malformed input is rejected cleanly.

pgx_getword() and pgx_wordtoint() compute (1 << prec) and
(1 << (prec - 1)) in 32-bit types. For prec = 32 (and prec = 0 in
wordtoint's sign test) the shift exponent is out of range: undefined
behavior, reproducible with a crafted .pgx under UBSan.

Use uint_fast64_t for the mask and jas_seqent_t for the sign
extension, and reject prec = 0 in the header validation since a
zero-bit precision is meaningless (it also fed the prec - 1 shift).

Fixes jasper-software#414.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pgx_dec.c: shift exponent UB in pgx_wordtoint() (reopen of #334 with PoC)

1 participant