This description is extracted from https://talosintelligence.com/vulnerability_reports/TALOS-2025-2210
LINE 114. /*
LINE 115. * Sample routine for JPEG compression. We assume that the target file name
LINE 116. * and a compression quality factor are passed in.
LINE 117. */
LINE 118.
LINE 119. bool JPEGBITSCodec::InternalCode(const char* input, unsigned long len, std::ostream &os)
LINE 120. {
LINE 121. int quality = 100; (void)len;
LINE 122. (void)quality;
LINE 123. JSAMPLE * image_buffer = (JSAMPLE*)(void*)const_cast<char*>(input); /* Points to large array of R,G,B-order data */
LINE 124. const unsigned int *dims = this->GetDimensions();
LINE 125. int image_height = dims[1]; /* Number of rows in image */
LINE 126. int image_width = dims[0]; /* Number of columns in image */
LINE 127.
[...]
LINE 277. row_stride = image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */
LINE 278.
LINE 279. if( this->GetPlanarConfiguration() == 0 )
LINE 280. {
LINE 281. while (cinfo.next_scanline < cinfo.image_height) {
LINE 282. /* jpeg_write_scanlines expects an array of pointers to scanlines.
LINE 283. * Here the array is only one element long, but you could pass
LINE 284. * more than one scanline at a time if that's more convenient.
LINE 285. */
LINE 286. row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; <---- OOBO here
LINE 287. (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
LINE 288. }
LINE 289. }
[...]
LINE 328. }
Earlier in the code, a vulnerability can be observed at LINE 286 due to the absence of bounds checking. Specifically, the assignment to row_pointer may result in a potential out-of-bounds (OOBO) value, as there is no validation to ensure that image_buffer[cinfo.next_scanline * row_stride] stays within the bounds of image_buffer or its length (len).
This leads to two crash
LINE 473. /*
LINE 474. * Convert some rows of samples to the JPEG colorspace.
LINE 475. * This version handles grayscale output with no conversion.
LINE 476. * The source can be either plain grayscale or YCbCr (since Y == gray).
LINE 477. */
LINE 478.
LINE 479. METHODDEF(void)
LINE 480. grayscale_convert (j_compress_ptr cinfo,
LINE 481. JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
LINE 482. JDIMENSION output_row, int num_rows)
LINE 483. {
LINE 484. register JSAMPROW inptr;
LINE 485. register JSAMPROW outptr;
LINE 486. register JDIMENSION col;
LINE 487. JDIMENSION num_cols = cinfo->image_width;
LINE 488. int instride = cinfo->input_components;
LINE 489.
LINE 490. while (--num_rows >= 0) {
LINE 491. inptr = *input_buf++;
LINE 492. outptr = output_buf[0][output_row];
LINE 493. output_row++;
LINE 494. for (col = 0; col < num_cols; col++) {
LINE 495. outptr[col] = inptr[0]; // <----- crashing here
LINE 496. inptr += instride; // <----- OOBO here
LINE 497. }
LINE 498. }
LINE 499. }
The variables cinfo->image_width, cinfo->input_components, and num_rows are directly influenced by values extracted from the malicious DICOM file. Additionally, the pointer inptr, which is obtained at LINE 491, is derived and computed from the input_buf pointer that is passed as an argument to the function. Upon analysis, we can an out-of-bounds read issue occurring at LINE 496
LINE 502. /*
LINE 503. * Convert some rows of samples to the JPEG colorspace.
LINE 504. * This version handles multi-component colorspaces without conversion.
LINE 505. * We assume input_components == num_components.
LINE 506. */
LINE 507.
LINE 508. METHODDEF(void)
LINE 509. null_convert (j_compress_ptr cinfo,
LINE 510. JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
LINE 511. JDIMENSION output_row, int num_rows)
LINE 512. {
LINE 513. register JSAMPROW inptr;
LINE 514. register JSAMPROW outptr;
LINE 515. register JDIMENSION col;
LINE 516. register int ci;
LINE 517. int nc = cinfo->num_components;
LINE 518. JDIMENSION num_cols = cinfo->image_width;
LINE 519.
LINE 520. while (--num_rows >= 0) {
LINE 521. /* It seems fastest to make a separate pass for each component. */
LINE 522. for (ci = 0; ci < nc; ci++) {
LINE 523. inptr = *input_buf;
LINE 524. outptr = output_buf[ci][output_row];
LINE 525. for (col = 0; col < num_cols; col++) {
LINE 526. outptr[col] = inptr[ci]; // <----- crashing here
LINE 527. inptr += nc; // <----- OOBO here
LINE 528. }
LINE 529. }
LINE 530. input_buf++;
LINE 531. output_row++;
LINE 532. }
LINE 533. }
The variables cinfo->image_width, cinfo->input_components, and num_rows are directly influenced by values extracted from the malicious DICOM file. Additionally, the pointer inptr, which is obtained at LINE 523, is derived and computed from the input_buf pointer that is passed as an argument to the function. Upon analysis, we can observe an out-of-bounds read issue occurring at LINE 527
This issue appears to have been addressed in commit f0e359c87947326c7fb2f7b91ecbe351e9d8c683
Hello!
I'm from Debian LTS team. I'd like to know if you have news about this fix?
Thanks
Hello!
Sorry for bother you, do you have any updates here?
Thanks
Hi,
This was fixed in 3.2.3 - https://github.com/malaterre/GDCM/releases/tag/v3.2.3
https://github.com/malaterre/GDCM/pull/203