深入剖析Grassroot DICOM JPEG解码越界读取漏洞

本文详细分析了Cisco Talos发现的Grassroot DICOM库中JPEGBITSCodec::InternalCode函数存在的两个越界读取漏洞。这些漏洞源于对恶意DICOM文件处理时缺乏边界检查,可能导致信息泄露。文章包含漏洞触发路径、代码分析和崩溃调试信息。

TALOS-2025-2210 || Cisco Talos情报组 - 综合威胁情报

Talos漏洞报告

TALOS-2025-2210 Grassroot DICOM JPEGBITSCodec::InternalCode越界读取漏洞 2025年12月16日

CVE编号 CVE-2025-53619, CVE-2025-53618

摘要 Grassroot DICOM 3.024的JPEGBITSCodec::InternalCode功能中存在越界读取漏洞。特制的DICOM文件可导致信息泄露。攻击者可通过提供恶意文件来触发此漏洞。

确认受影响版本 以下版本经过Talos测试或验证,或已由供应商确认为易受攻击。 Grassroot DICOM 3.024

产品URL Grassroot DICOM - https://sourceforge.net/projects/gdcm/

CVSSv3评分 7.4 - CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE CWE-119 - 内存缓冲区操作范围限制不当

详细信息 Grassroots DiCoM是一个用于处理DICOM医疗文件的C++库。可从Python、C#、Java和PHP访问。它支持RAW、JPEG、JPEG 2000、JPEG-LS、RLE和deflated传输语法。

它附带一个超快速扫描器实现,可快速扫描数百个DICOM文件。 它支持SCU网络操作(C-ECHO、C-FIND、C-STORE、C-MOVE)。PS 3.3和3.6以XML文件形式分发。 它还提供PS 3.15证书和基于密码的机制,用于匿名化和去标识化DICOM数据集。

特制的DICOM文件可在多个压缩例程中触发越界读取,例如grayscale_convertnull_convert。此漏洞源于处理期间未对源内存缓冲区进行大小检查。

基于为压缩提供的输入文件,稍后将调用各种函数来处理颜色空间。相关信息将存储在一个名为cinfo的JPEG压缩对象中,该对象在名为jinit_color_converter的函数中设置。

例如,根据编码格式,颜色转换的函数指针可能按以下方式分配:

  • cconvert->pub.color_convert = grayscale_convert;(用于灰度转换)
  • cconvert->pub.color_convert = null_convert;(用于无转换)

jinit_color_converter函数负责根据需要配置color_convert对象。以下是处理此设置的实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
LINE 1. /*
LINE 2.  * Module initialization routine for input colorspace conversion.
LINE 3.  */
LINE 4. 
LINE 5. GLOBAL(void)
LINE 6. jinit_color_converter (j_compress_ptr cinfo)
LINE 7. {
[...]
LINE 47. 
LINE 48.   /* Check num_components, set conversion method based on requested space */
LINE 49.   switch (cinfo->jpeg_color_space) {
LINE 50.   case JCS_GRAYSCALE:
LINE 53.     if (cinfo->in_color_space == JCS_GRAYSCALE)
LINE 54.       cconvert->pub.color_convert = grayscale_convert;
[...]
LINE 62.     break;
LINE 63. 
LINE 64.   case JCS_RGB:
[...]
LINE 67.     if (cinfo->in_color_space == JCS_RGB && RGB_PIXELSIZE == 3)
LINE 68.       cconvert->pub.color_convert = null_convert;
[...]
LINE 71.     break;
[...]
LINE 112.   }
LINE 113. }

为了更深入地了解底层过程,检查构造非常重要。在这种情况下,使用rr记录工具非常有效,因为它有助于识别负责处理JPEG压缩的函数。

在压缩过程中,会调用一个名为JPEGBITSCodec::InternalCode的函数。该函数在管理JPEG压缩中起关键作用。其输入参数是一个向量,该向量以文件中记录的像素数据大小确定的固定长度分配。此长度称为len,相应设置并作为参数传递给函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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      
LINE 287.        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
LINE 288.      }
LINE 289.      }
[...]
LINE 328.  }

在代码的前面部分,由于缺乏边界检查,可以在第286行观察到漏洞。具体来说,对row_pointer的赋值可能导致潜在的越界(OOBO)值,因为没有验证image_buffer[cinfo.next_scanline * row_stride]是否保持在image_buffer或其长度(len)的范围内。

然后,计算出的row_pointer缓冲区作为参数传递给jpeg_write_scanlines,在那里它被用作scanlines参数。在jpeg_write_scanlines中,我们可以在第361行观察到对cinfo->main->process_data的调用,其中scanlines(对应前面提到的row_pointer)作为第二个参数传递。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
LINE 329. GLOBAL(JDIMENSION)
LINE 330. jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
LINE 331.           JDIMENSION num_lines)
LINE 332. {
[...]
LINE 355.   /* Ignore any extra scanlines at bottom of image. */
LINE 356.   rows_left = cinfo->image_height - cinfo->next_scanline;
LINE 357.   if (num_lines > rows_left)
LINE 358.     num_lines = rows_left;
LINE 359. 
LINE 360.   row_ctr = 0;
LINE 361.   (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
LINE 362.   cinfo->next_scanline += row_ctr;
LINE 363.   return row_ctr;
LINE 364. }

在这种情况下,第361行的函数指针cinfo->main->process_data指向process_data_simple_main函数。当调用此函数时,scanlines参数作为input_buf传递。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
LINE 365. METHODDEF(void)
LINE 366. process_data_simple_main (j_compress_ptr cinfo,
LINE 367.         JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
LINE 368.         JDIMENSION in_rows_avail)
LINE 369. {
LINE 370.   my_main_ptr mainPtr = (my_main_ptr) cinfo->main;
LINE 371.   JDIMENSION data_unit = (JDIMENSION)(cinfo->data_unit);
LINE 372. 
LINE 373.   while (mainPtr->cur_iMCU_row < cinfo->total_iMCU_rows) {
LINE 374.     /* Read input data if we haven't filled the main buffer yet */
LINE 375.     if (mainPtr->rowgroup_ctr < data_unit)
LINE 376.       (*cinfo->prep->pre_process_data) (cinfo,
LINE 377.           input_buf, in_row_ctr, in_rows_avail,
LINE 378.           mainPtr->buffer, &mainPtr->rowgroup_ctr,
LINE 379.           (JDIMENSION) data_unit);
LINE 380. 
[...]
LINE 412. }

在第376行,函数指针(*cinfo->prep->pre_process_data)指向pre_process_data函数。此函数以input_buf作为其参数之一被调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
LINE 413. METHODDEF(void)
LINE 414. pre_process_data (j_compress_ptr cinfo,
LINE 415.       JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
LINE 416.       JDIMENSION in_rows_avail,
LINE 417.       JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
LINE 418.       JDIMENSION out_row_groups_avail)
LINE 419. {
LINE 420.   my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
LINE 421.   int numrows, ci;
LINE 422.   JDIMENSION inrows;
LINE 423.   jpeg_component_info * compptr;
LINE 424. 
LINE 425.   while (*in_row_ctr < in_rows_avail &&
LINE 426.    *out_row_group_ctr < out_row_groups_avail) {
LINE 427.     /* Do color conversion to fill the conversion buffer. */
LINE 428.     inrows = in_rows_avail - *in_row_ctr;
LINE 429.     numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
LINE 430.     numrows = (int) MIN((JDIMENSION) numrows, inrows);
LINE 431.     (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr, 
LINE 432.                prep->color_buf,
LINE 433.                (JDIMENSION) prep->next_buf_row,
LINE 434.                numrows);
[...]
LINE 470.   }
LINE 471. }

最后,调用了前面提到的颜色转换函数,即第431行的(*cinfo->cconvert->color_convert)。此函数根据恶意DICOM文件的内容动态调用不同的例程,可能导致各种崩溃。

CVE-2025-53618 - grayscale_convert

以下是grayscale_convert函数的摘录,崩溃发生在第495行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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];                             // <----- 此处崩溃
LINE 496.       inptr += instride;                                  // <----- 此处OOBO
LINE 497.     }
LINE 498.   }
LINE 499. }

变量cinfo->image_widthcinfo->input_componentsnum_rows直接受从恶意DICOM文件中提取的值影响。

此外,第491行获取的指针inptr是从作为参数传递给函数的input_buf指针派生和计算的。分析后,我们观察到第496行发生了越界读取问题。

崩溃信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
NumberOfDimensions: 2
Dimensions: (256,58112,1)
SamplesPerPixel    :1
BitsAllocated      :16
BitsStored         :16
HighBit            :15
PixelRepresentation:0
ScalarType found   :UINT16
PhotometricInterpretation: MONOCHROME2 
PlanarConfiguration: 0
TransferSyntax: 1.2.840.10008.1.2.1
Origin: (0,0,0)
Spacing: (2.21,2.21,1)
DirectionCosines: (1,0,0,0,1,0)
Rescale Intercept/Slope: (0,1)

Program received signal SIGSEGV, Segmentation fault.
grayscale_convert (cinfo=<optimized out>, input_buf=0x7fffffffda30, output_buf=<optimized out>, output_row=1, num_rows=<optimized out>) at /src/gdcm-git/Utilities/gdcmjpeg/jccolor.c:295
295	      outptr[col] = inptr[0];  /* don't need GETJSAMPLE() here */
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────
 RAX  0x555555f644a8 ◂— 0
 RBX  0x200
 RCX  0
 RDX  0x7ffff7c6c000 ◂— 0
 RDI  0x555555f644b8 ◂— 0x221
 RSI  2
 R8   1
 R9   1
 R10  0x7fffffffda30 —▸ 0x555555716590 (my_error_exit) ◂— endbr64 
 R11  0x555555f60008 —▸ 0x555555f642b8 ◂— 0
 R12  0x7fffffffdba0 —▸ 0x7fffffffda30 —▸ 0x555555716590 (my_error_exit) ◂— endbr64 
 R13  0x7fffffffda28 —▸ 0x7ffff7c6be10 ◂— 0
 R14  0x555555f5ff98 —▸ 0x5555557ec640 (start_pass_prep) ◂— endbr64 
 R15  0x7fffffffdba0 —▸ 0x7fffffffda30 —▸ 0x555555716590 (my_error_exit) ◂— endbr64 
 RBP  1
 RSP  0x7fffffffd8d0 ◂— 1
 RIP  0x5555557ed8d0 (grayscale_convert+80) ◂— movzx ecx, word ptr [rdx]
─────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────────
  0x5555557ed8d0 <grayscale_convert+80>    movzx  ecx, word ptr [rdx]        ECX, [0x7ffff7c6c000] => 0
   0x5555557ed8d3 <grayscale_convert+83>    add    rax, 2                     RAX => 0x555555f644aa (0x555555f644a8 + 0x2)
   0x5555557ed8d7 <grayscale_convert+87>    add    rdx, rsi                   RDX => 0x7ffff7c6c002 (0x7ffff7c6c000 + 0x2)
   0x5555557ed8da <grayscale_convert+90>    mov    word ptr [rax - 2], cx     [0x555555f644a8] <= 0
   0x5555557ed8de <grayscale_convert+94>    cmp    rax, rdi                   0x555555f644aa - 0x555555f644b8     EFLAGS => 0x10283 [ CF pf af zf SF IF df of ac ]
   0x5555557ed8e1 <grayscale_convert+97>   jne    grayscale_convert+80        <grayscale_convert+80>
    
   0x5555557ed8d0 <grayscale_convert+80>    movzx  ecx, word ptr [rdx]        ECX, [0x7ffff7c6c002] => 0
   0x5555557ed8d3 <grayscale_convert+83>    add    rax, 2                     RAX => 0x555555f644ac (0x555555f644aa + 0x2)
   0x5555557ed8d7 <grayscale_convert+87>    add    rdx, rsi                   RDX => 0x7ffff7c6c004 (0x7ffff7c6c002 + 0x2)
   0x5555557ed8da <grayscale_convert+90>    mov    word ptr [rax - 2], cx     [0x555555f644aa] <= 0
   0x5555557ed8de <grayscale_convert+94>    cmp    rax, rdi                   0x555555f644ac - 0x555555f644b8     EFLAGS => 0x10283 [ CF pf af zf SF IF df of ac ]
───────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────────────────────
In file: /src/gdcm-git/Utilities/gdcmjpeg/jccolor.c:295
   290   while (--num_rows >= 0) {
   291     inptr = *input_buf++;
   292     outptr = output_buf[0][output_row];
   293     output_row++;
   294     for (col = 0; col < num_cols; col++) {
  295       outptr[col] = inptr[0];  /* don't need GETJSAMPLE() here */
   296       inptr += instride;
   297     }
   298   }
   299 }
   300 
───────────────────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────────────────────
00:0000 rsp 0x7fffffffd8d0 ◂— 1
01:0008     0x7fffffffd8d8 —▸ 0x5555557ec76c (pre_process_data+220) ◂— mov rax, qword ptr [rsp + 0x10]
02:0010     0x7fffffffd8e0 —▸ 0x555555f5ff98 —▸ 0x5555557ec640 (start_pass_prep) ◂— endbr64 
03:0018     0x7fffffffd8e8 ◂— 0x555500000000
04:0020     0x7fffffffd8f0 —▸ 0x7fffffffd9c4 ◂— 0xc2ebf50000000000
05:0028     0x7fffffffd8f8 ◂— 0x101c60000
06:0030     0x7fffffffd900 —▸ 0x555555f60024 ◂— 0
07:0038     0x7fffffffd908 —▸ 0x555555f5ffa8 —▸ 0x555555f60008 —▸ 0x555555f642b8 ◂— 0
─────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────────────────────
  0   0x5555557ed8d0 grayscale_convert+80
   1   0x5555557ec76c pre_process_data+220
   2   0x5555557ec488 process_data_simple_main+120
   3   0x5555557e7efb gdcmjpeg16_jpeg_write_scanlines+187
   4   0x5555557168a6 gdcm::JPEG16Codec::InternalCode(char const*, unsigned long, std::ostream&)+518
   5   0x5555556edeec gdcm::JPEGCodec::Code(gdcm::DataElement const&, gdcm::DataElement&)+1164
   6   0x5555556b3f56 gdcm::ImageChangeTransferSyntax::TryJPEGCodec(gdcm::DataElement const&, gdcm::Bitmap const&, gdcm::Bitmap&)+358
   7   0x5555556b5a33 gdcm::ImageChangeTransferSyntax::Change()+1747
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

CVE-2025-53619 - null_convert

以下是null_convert函数的摘录,崩溃发生在第526行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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];                             // <----- 此处崩溃                               
LINE 527.         inptr += nc;                                         // <----- 此处OOBO
LINE 528.       }
LINE 529.     }
LINE 530.     input_buf++;
LINE 531.     output_row++;
LINE 532.   }
LINE 533. }

变量cinfo->image_widthcinfo->input_componentsnum_rows直接受从恶意DICOM文件中提取的值影响。

此外,第523行获取的指针inptr是从作为参数传递给函数的input_buf指针派生和计算的。分析后,我们可以观察到第527行发生了越界读取问题。

崩溃信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
NumberOfDimensions: 2
Dimensions: (256,58112,1)
SamplesPerPixel    :1
BitsAllocated      :16
BitsStored         :16
HighBit            :0
PixelRepresentation:0
ScalarType found   :UINT16
PhotometricInterpretation: RGB 
PlanarConfiguration: 0
TransferSyntax: 1.2.840.10008.1.2.1
Origin: (0,0,0)
Spacing: (1,1,1)
DirectionCosines: (1,0,0,0,1,0)
Rescale Intercept/Slope: (0,1)

Program received signal SIGSEGV, Segmentation fault.
null_convert (cinfo=<optimized out>, input_buf=0x7fffffffda28, output_buf=0x555555f58ae8, output_row=0, num_rows=<optimized out>) at /src/gdcm-git/Utilities/gdcmjpeg/jccolor.c:326
326	  outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────
 RAX  0x555555f5dea8 ◂— 0
 RBX  0x7fffffffda28 —▸ 0x7ffff7c6bc10 ◂— 0
 RCX  0
 RDX  0x7ffff7c6c000 ◂— 0
 RDI  0x555555f5df58 ◂— 0x221
 RSI  6
 R8   0
 R9   0
 R10  0x7ffff7c6bc10 ◂— 0
 R11  0x200
 R12  0
 R13  1
 R14  0x555555f58ad8 —▸ 0x5555557ec640 (start_pass_prep) ◂— endbr64 
 R15  0x7fffffffdba0 —▸ 0x7fffffffda30 —▸ 0x555555716590 (my_error_exit) ◂— endbr64 
 RBP  0x555555f58ae8 —▸ 0x555555f58b48 —▸ 0x555555f5dd58 ◂— 0
 RSP  0x7fffffffd8b8 ◂— 1
 RIP  0x5555557ed998 (null_convert+104) ◂— movzx ecx, word ptr [rdx]
─────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────────
  0x5555557ed998 <null_convert+104>    movzx  ecx, word ptr [rdx]        ECX, [0x7ffff7c6c000] => 0
   0x5555557ed99b <null_convert+107>    add    rax, 2                     RAX => 0x555555f5deaa (0x555555f5dea8 + 0x2)
   0x5555557ed99f <null_convert+111>    add    rdx, rsi                   RDX => 0x7ffff7c6c006 (0x7ffff7c6c000 + 0x6)
   0x5555557ed9a2 <null_convert+114>    mov    word ptr [rax - 2], cx     [0x555555f5dea8] <= 0
   0x5555557ed9a6 <null_convert+118>    cmp    rdi, rax                   0x555555f5df58 - 0x555555f5deaa     EFLAGS => 0x10212 [ cf pf AF zf sf IF df of ac ]
   0x5555557ed9a9 <null_convert+121>   jne    null_convert+104            <null_convert+104>
    
   0x5555557ed998 <null_convert+104>    movzx  ecx, word ptr [rdx]        ECX, [0x7ffff7c6c006] => 0
   0x5555557ed99b <null_convert+107>    add    rax, 2                     RAX => 0x555555f5deac (0x555555f5deaa + 0x2)
   0x5555557ed99f <null_convert+111>    add    rdx, rsi                   RDX => 0x7ffff7c6c00c (0x7ffff7c6c006 + 0x6)
   0x5555557ed9a2 <null_convert+114>    mov    word ptr [rax - 2], cx     [0x555555f5deaa] <= 0
   0x5555557ed9a6 <null_convert+118>    cmp    rdi, rax                   0x555555f5df58 - 0x555555f5deac     EFLAGS => 0x10216 [ cf PF AF zf sf IF df of ac ]
───────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────────────────────
In file: /src/gdcm-git/Utilities/gdcmjpeg/jccolor.c:326
   321     /* It seems fastest to make a separate pass for each component. */
   322     for (ci = 0; ci < nc; ci++) {
   323       inptr = *input_buf;
   324       outptr = output_buf[ci][output_row];
   325       for (col = 0; col < num_cols; col++) {
  326   outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
   327   inptr += nc;
   328       }
   329     }
   330     input_buf++;
   331     output_row++;
───────────────────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────────────────────
00:0000 rsp 0x7fffffffd8b8 ◂— 1
01:0008     0x7fffffffd8c0 ◂— 1
02:0010     0x7fffffffd8c8 —▸ 0x7fffffffdba0 —▸ 0x7fffffffda30 —▸ 0x555555716590 (my_error_exit) ◂— endbr64 
03:0018     0x7fffffffd8d0 —▸ 0x7fffffffda28 —▸ 0x7ffff7c6bc10 ◂— 0
04:0020     0x7fffffffd8d8 —▸ 0x5555557ec76c (pre_process_data+220) ◂— mov rax, qword ptr [rsp + 0x10]
05:0028     0x7fffffffd8e0 —▸ 0x555555f58ad8 —▸ 0x5555557ec640 (start_pass_prep) ◂— endbr64 
06:0030     0x7fffffffd8e8 ◂— 0x555500000000
07:0038     0x7fffffffd8f0 —▸ 0x7fffffffd9c4 ◂— 0xb3a3ea0000000000
─────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────────────────────
  0   0x5555557ed998 null_convert+104
   1   0x5555557ec76c pre_process_data+220
   2   0x5555557ec488 process_data_simple_main+120
   3   0x5555557e7efb gdcmjpeg16_jpeg_write_scanlines+187
   4   0x5555557168a6 gdcm::JPEG16Codec::InternalCode(char const*, unsigned long, std::ostream&)+518
   5   0x5555556edeec gdcm::JPEGCodec::Code(gdcm::DataElement const&, gdcm::DataElement&)+1164
   6   0x5555556b3f56 gdcm::ImageChangeTransferSyntax::TryJPEGCodec(gdcm::DataElement const&, gdcm::Bitmap const&, gdcm::Bitmap&)+358
   7   0x5555556b5a33 gdcm::ImageChangeTransferSyntax::Change()+1747
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

时间线

  • 2025-07-15 - 向供应商披露
  • 2025-08-04 - Talos跟进
  • 2025-09-01 - Talos跟进
  • 2025-10-06 - Talos跟进
  • 2025-12-16 - 公开披露

致谢 由Cisco Talos的Emmanuel Tacheau发现。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计