From b9895fbc76a73c5cef2ecd12f2453158310025c4 Mon Sep 17 00:00:00 2001 From: iliasabk Date: Wed, 16 Sep 2026 15:31:53 +0200 Subject: [PATCH] Fix shift-exponent UB in PGX decoder 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/jasper#414. --- src/libjasper/pgx/pgx_dec.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libjasper/pgx/pgx_dec.c b/src/libjasper/pgx/pgx_dec.c index 351312a4..10732c9d 100644 --- a/src/libjasper/pgx/pgx_dec.c +++ b/src/libjasper/pgx/pgx_dec.c @@ -299,7 +299,7 @@ static int pgx_gethdr(jas_stream_t *in, pgx_hdr_t *hdr) jas_logerrorf("cannot get height\n"); goto error; } - if (hdr->prec > 32) { + if (hdr->prec < 1 || hdr->prec > 32) { jas_logerrorf("unsupported precision (%d)\n", hdr->prec); goto error; } @@ -369,7 +369,7 @@ static int_fast32_t pgx_getword(jas_stream_t *in, bool bigendian, int prec) j = bigendian ? (wordsize - 1 - i) : i; val = val | ((c & 0xffU) << (8 * j)); } - val &= (JAS_CAST(uint_fast32_t, 1) << prec) - 1; + val &= (JAS_CAST(uint_fast64_t, 1) << prec) - 1; return val; error: @@ -524,7 +524,8 @@ static int pgx_getuint32(jas_stream_t *in, uint_fast32_t *val) static jas_seqent_t pgx_wordtoint(uint_fast32_t v, int prec, bool sgnd) { jas_seqent_t ret; - v &= (1 << prec) - 1; - ret = (sgnd && (v & (1 << (prec - 1)))) ? (v - (1 << prec)) : v; + v &= JAS_CAST(uint_fast32_t, JAS_POW2_X(uint_fast64_t, prec) - 1); + ret = (sgnd && (v & JAS_POW2_X(uint_fast32_t, prec - 1))) ? + JAS_CAST(jas_seqent_t, v) - JAS_POW2_X(jas_seqent_t, prec) : v; return ret; }