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