jas_matrix_bindsub_asan.log
Describe the bug
jas_matrix_bindsub is a public API function declared with JAS_EXPORT, and it is also reachable through the inline wrappers jas_matrix_bindrow and jas_matrix_bindcol declared in the public header.
The function accepts caller-supplied row/column indices and uses them to index into mat1->rows_ with no validation against mat1->numrows_ / mat1->numcols_.
I found this with KLEE symbolic execution of src/libjasper/base/jas_seq.c and reproduced it under AddressSanitizer.
It is present in upstream master as of June 1, 2026.
Out-of-bounds row-pointer read at jas_seq.c:242
// src/libjasper/base/jas_seq.c:241-243, inside jas_matrix_bindsub
for (i = 0; i < mat0->numrows_; ++i) {
mat0->rows_[i] = mat1->rows_[r0 + i] + c0; // <-- ASan: heap-buffer-overflow / SEGV
}
r0, r1, c0, c1 are passed straight through from the caller (a jas_matind_t, i.e. signed integer).
With r0 + i >= mat1->numrows_ the load reads past the end of the mat1->rows_ pointer array; the read value, which is an invalid row pointer, is then stored into mat0->rows_[i], so any subsequent matrix-element accessor on mat0 dereferences it.
The sibling entry jas_seq2d_bindsub (jas_seq.c:206) does validate its inputs before forwarding to jas_matrix_bindsub, but the public inline wrappers in src/libjasper/include/jasper/jas_seq.h do not:
// src/libjasper/base/jas_seq.c:209-212, inside jas_seq2d_bindsub
if (xstart < s1->xstart_ || ystart < s1->ystart_ ||
xend > s1->xend_ || yend > s1->yend_) {
return -1;
}
By contrast, the public inline wrapper used by the PoC forwards its caller-supplied row index directly:
// src/libjasper/include/jasper/jas_seq.h:316-319
static inline int jas_matrix_bindrow(jas_matrix_t *mat0, jas_matrix_t *mat1, jas_matind_t r)
{
return jas_matrix_bindsub(mat0, mat1, r, 0, r, mat1->numcols_ - 1);
}
The centralized fix belongs in jas_matrix_bindsub because callers can also invoke that exported function directly.
To Reproduce
Standalone reproducer using only the public headers.
After cloning JasPer, save this as jasper/poc_jas_matrix_bindsub.c in the root of the JasPer source checkout:
#include <jasper/jasper.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
int near = (argc > 1) && (strcmp(argv[1], "--near") == 0);
if (jas_init()) return 1;
jas_matrix_t *m = jas_matrix_create(4, 4);
jas_matrix_t *out = jas_matrix_create(1, 1);
if (!m || !out) return 1;
jas_matind_t r = near ? 8 : 1000000;
fprintf(stderr, "[poc] jas_matrix_bindrow(out, m{4x4}, r=%ld)\n", (long)r);
int rc = jas_matrix_bindrow(out, m, r);
fprintf(stderr, "[poc] bindrow returned %d\n", rc);
if (rc == 0) {
fprintf(stderr, "[poc] jas_matrix_get(out, 0, 0)\n");
jas_seqent_t v = jas_matrix_get(out, 0, 0);
fprintf(stderr, "[poc] value=%ld (should not reach this under ASan)\n", (long)v);
}
jas_matrix_destroy(m);
jas_matrix_destroy(out);
jas_cleanup();
return 0;
}
For r = 8, AddressSanitizer reports the out-of-bounds read while jas_matrix_bindrow is executing; the follow-on jas_matrix_get call is not required to trigger this report.
The following commands reproduce the issue from a clean checkout.
Run them from the root of the JasPer source checkout.
The build directory is created next to the checkout because JasPer rejects build directories located inside its source tree:
git clone https://github.com/jasper-software/jasper.git
cd jasper
git checkout 5ce57f67e0011e0d2483992a5d77a092b1b64eb7
cmake -S . -B ../jas_repro_build -DCMAKE_BUILD_TYPE=Debug -DJAS_ENABLE_SHARED=ON -DJAS_ENABLE_PROGRAMS=OFF -DJAS_ENABLE_DOC=OFF -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g -O0" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build ../jas_repro_build --target libjasper -j
gcc -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer -I../jas_repro_build/src/libjasper/include -I"$PWD/src/libjasper/include" poc_jas_matrix_bindsub.c -L../jas_repro_build/src/libjasper -ljasper -Wl,-rpath,"$PWD/../jas_repro_build/src/libjasper" -o poc_jas_matrix_bindsub
ASAN_OPTIONS=abort_on_error=0:halt_on_error=1 ./poc_jas_matrix_bindsub --near 2>&1 | tee jas_matrix_bindsub_asan.log
The expected result for --near is:
[poc] jas_matrix_bindrow(out, m{4x4}, r=8)
=================================================================
==PID==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000002c0
READ of size 8 at 0x6060000002c0 thread T0
#0 jas_matrix_bindsub .../jasper/src/libjasper/base/jas_seq.c:242
#1 jas_matrix_bindrow .../jasper/src/libjasper/include/jasper/jas_seq.h:318
#2 main .../jasper/poc_jas_matrix_bindsub.c:18
Address 0x6060000002c0 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow .../jasper/src/libjasper/base/jas_seq.c:242 in jas_matrix_bindsub
The deprecation warning for jas_init and the warning about the default JasPer memory limit may also appear before the ASan report; they are unrelated to this out-of-bounds read.
The full AddressSanitizer output is attached at the top of this report.
Affected version: latest upstream master as of June 1, 2026 @ 5ce57f67e0011e0d2483992a5d77a092b1b64eb7.
Expected behavior
Reject out-of-range r0 / r1 / c0 / c1 at entry to jas_matrix_bindsub — and therefore for the inline jas_matrix_bindrow / jas_matrix_bindcol wrappers — before allocating mat0->rows_ or executing the row-copy loop.
Suggested fix direction
Validate r0, r1, c0, and c1 against the source matrix dimensions at the entry to jas_matrix_bindsub, before allocating or copying row pointers.
This follows the validation approach already used by jas_seq2d_bindsub in the same file.
For example:
diff --git a/src/libjasper/base/jas_seq.c b/src/libjasper/base/jas_seq.c
--- a/src/libjasper/base/jas_seq.c
+++ b/src/libjasper/base/jas_seq.c
@@ -219,6 +219,11 @@ int jas_matrix_bindsub(jas_matrix_t *mat0, jas_matrix_t *mat1,
{
jas_matind_t i;
+ if (r0 < 0 || r1 < r0 || r1 >= mat1->numrows_ ||
+ c0 < 0 || c1 < c0 || c1 >= mat1->numcols_) {
+ return -1;
+ }
+
if (mat0->data_) {
if (!(mat0->flags_ & JAS_MATRIX_REF)) {
jas_free(mat0->data_);
jas_matrix_bindsub_asan.log
Describe the bug
jas_matrix_bindsubis a public API function declared withJAS_EXPORT, and it is also reachable through the inline wrappersjas_matrix_bindrowandjas_matrix_bindcoldeclared in the public header.The function accepts caller-supplied row/column indices and uses them to index into
mat1->rows_with no validation againstmat1->numrows_/mat1->numcols_.I found this with KLEE symbolic execution of
src/libjasper/base/jas_seq.cand reproduced it under AddressSanitizer.It is present in upstream
masteras of June 1, 2026.Out-of-bounds row-pointer read at jas_seq.c:242
r0,r1,c0,c1are passed straight through from the caller (ajas_matind_t, i.e. signed integer).With
r0 + i >= mat1->numrows_the load reads past the end of themat1->rows_pointer array; the read value, which is an invalid row pointer, is then stored intomat0->rows_[i], so any subsequent matrix-element accessor onmat0dereferences it.The sibling entry
jas_seq2d_bindsub(jas_seq.c:206) does validate its inputs before forwarding tojas_matrix_bindsub, but the public inline wrappers insrc/libjasper/include/jasper/jas_seq.hdo not:By contrast, the public inline wrapper used by the PoC forwards its caller-supplied row index directly:
The centralized fix belongs in
jas_matrix_bindsubbecause callers can also invoke that exported function directly.To Reproduce
Standalone reproducer using only the public headers.
After cloning JasPer, save this as
jasper/poc_jas_matrix_bindsub.cin the root of the JasPer source checkout:For
r = 8, AddressSanitizer reports the out-of-bounds read whilejas_matrix_bindrowis executing; the follow-onjas_matrix_getcall is not required to trigger this report.The following commands reproduce the issue from a clean checkout.
Run them from the root of the JasPer source checkout.
The build directory is created next to the checkout because JasPer rejects build directories located inside its source tree:
The expected result for
--nearis:The deprecation warning for
jas_initand the warning about the default JasPer memory limit may also appear before the ASan report; they are unrelated to this out-of-bounds read.The full AddressSanitizer output is attached at the top of this report.
Affected version: latest upstream
masteras of June 1, 2026 @5ce57f67e0011e0d2483992a5d77a092b1b64eb7.Expected behavior
Reject out-of-range
r0/r1/c0/c1at entry tojas_matrix_bindsub— and therefore for the inlinejas_matrix_bindrow/jas_matrix_bindcolwrappers — before allocatingmat0->rows_or executing the row-copy loop.Suggested fix direction
Validate
r0,r1,c0, andc1against the source matrix dimensions at the entry tojas_matrix_bindsub, before allocating or copying row pointers.This follows the validation approach already used by
jas_seq2d_bindsubin the same file.For example: