2626#define OPCODE_ID_WARP_RECTILINEAR (1)
2727#define OPCODE_ID_VIGNETTE_RADIAL (3)
2828
29+ /* Sizes of the fixed-width values serialized in DNG opcode data. */
30+ #define DNG_UINT32_SIZE (4)
31+ #define DNG_FLOAT_SIZE (4)
32+ #define DNG_DOUBLE_SIZE (8)
33+
34+ /* DNG opcode lists start with an opcode count. Each opcode then has a header
35+ * containing four uint32 values: ID, version, flags, and parameter byte count. */
36+ #define OPCODE_LIST_HEADER_SIZE (DNG_UINT32_SIZE)
37+ #define OPCODE_HEADER_SIZE (4 * DNG_UINT32_SIZE)
38+
39+ /* A GainMap payload has eleven 32-bit fields and four 64-bit floating-point
40+ * fields before its variable-length array of gain values. */
41+ #define GAIN_MAP_HEADER_SIZE (11 * DNG_UINT32_SIZE + 4 * DNG_DOUBLE_SIZE)
42+
43+ /* WarpRectilinear has six coefficients per plane and a two-value center.
44+ * VignetteRadial has five coefficients and the same two-value center. */
45+ #define WARP_COEFFICIENTS_PER_PLANE (6)
46+ #define VIGNETTE_COEFFICIENTS (5)
47+ #define OPCODE_CENTER_VALUES (2)
48+ #define WARP_RECTILINEAR_SIZE (planes ) \
49+ (DNG_UINT32_SIZE + DNG_DOUBLE_SIZE * ((planes) * WARP_COEFFICIENTS_PER_PLANE \
50+ + OPCODE_CENTER_VALUES))
51+ #define VIGNETTE_RADIAL_SIZE \
52+ (DNG_DOUBLE_SIZE * (VIGNETTE_COEFFICIENTS + OPCODE_CENTER_VALUES))
53+
2954static double _get_double (uint8_t * ptr )
3055{
3156 guint64 in ;
@@ -62,25 +87,58 @@ void dt_dng_opcode_process_opcode_list_2(uint8_t *buf, uint32_t buf_size, dt_ima
6287 g_list_free_full (img -> dng_gain_maps , g_free );
6388 img -> dng_gain_maps = NULL ;
6489
90+ if (buf_size < OPCODE_LIST_HEADER_SIZE )
91+ {
92+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid OpcodeList2 header" );
93+ return ;
94+ }
95+
6596 uint32_t count = _get_long (& buf [0 ]);
66- uint32_t offset = 4 ;
97+ uint32_t offset = OPCODE_LIST_HEADER_SIZE ;
6798 while (count > 0 )
6899 {
100+ if (offset > buf_size || buf_size - offset < OPCODE_HEADER_SIZE )
101+ {
102+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid opcode header in OpcodeList2" );
103+ return ;
104+ }
105+
69106 uint32_t opcode_id = _get_long (& buf [offset ]);
70107 uint32_t flags = _get_long (& buf [offset + 8 ]);
71108 uint32_t param_size = _get_long (& buf [offset + 12 ]);
72- uint8_t * param = & buf [offset + 16 ];
109+ uint8_t * param = & buf [offset + OPCODE_HEADER_SIZE ];
73110
74- if (offset + 16 + param_size > buf_size )
111+ if (param_size > buf_size - offset - OPCODE_HEADER_SIZE )
75112 {
76113 dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid opcode size in OpcodeList2" );
77114 return ;
78115 }
79116
80117 if (opcode_id == OPCODE_ID_GAINMAP )
81118 {
82- uint32_t gain_count = (param_size - 76 ) / 4 ;
83- dt_dng_gain_map_t * gm = g_malloc (sizeof (dt_dng_gain_map_t ) + gain_count * sizeof (float ));
119+ if (param_size < GAIN_MAP_HEADER_SIZE
120+ || (param_size - GAIN_MAP_HEADER_SIZE ) % DNG_FLOAT_SIZE )
121+ {
122+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid GainMap size in OpcodeList2" );
123+ return ;
124+ }
125+
126+ uint32_t gain_count = (param_size - GAIN_MAP_HEADER_SIZE ) / DNG_FLOAT_SIZE ;
127+ #if SIZE_MAX < UINT64_MAX
128+ if (gain_count > (SIZE_MAX - sizeof (dt_dng_gain_map_t )) / sizeof (float ))
129+ {
130+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] GainMap is too large in OpcodeList2" );
131+ return ;
132+ }
133+ #endif
134+
135+ dt_dng_gain_map_t * gm =
136+ g_try_malloc (sizeof (dt_dng_gain_map_t ) + gain_count * sizeof (float ));
137+ if (!gm )
138+ {
139+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Failed to allocate GainMap in OpcodeList2" );
140+ return ;
141+ }
84142 gm -> top = _get_long (& param [0 ]);
85143 gm -> left = _get_long (& param [4 ]);
86144 gm -> bottom = _get_long (& param [8 ]);
@@ -96,8 +154,26 @@ void dt_dng_opcode_process_opcode_list_2(uint8_t *buf, uint32_t buf_size, dt_ima
96154 gm -> map_origin_v = _get_double (& param [56 ]);
97155 gm -> map_origin_h = _get_double (& param [64 ]);
98156 gm -> map_planes = _get_long (& param [72 ]);
99- for (int i = 0 ; i < gain_count ; i ++ )
100- gm -> map_gain [i ] = _get_float (& param [76 + 4 * i ]);
157+
158+ const uint64_t map_points =
159+ (uint64_t )gm -> map_points_v * gm -> map_points_h ;
160+ if (gm -> map_planes && map_points > UINT64_MAX / gm -> map_planes )
161+ {
162+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid GainMap dimensions in OpcodeList2" );
163+ g_free (gm );
164+ return ;
165+ }
166+
167+ const uint64_t expected_gain_count = map_points * gm -> map_planes ;
168+ if (expected_gain_count != gain_count )
169+ {
170+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid GainMap data length in OpcodeList2" );
171+ g_free (gm );
172+ return ;
173+ }
174+
175+ for (uint32_t i = 0 ; i < gain_count ; i ++ )
176+ gm -> map_gain [i ] = _get_float (& param [GAIN_MAP_HEADER_SIZE + DNG_FLOAT_SIZE * i ]);
101177
102178 img -> dng_gain_maps = g_list_append (img -> dng_gain_maps , gm );
103179 }
@@ -107,7 +183,7 @@ void dt_dng_opcode_process_opcode_list_2(uint8_t *buf, uint32_t buf_size, dt_ima
107183 flags & 1 ? "optional" : "mandatory" , opcode_id );
108184 }
109185
110- offset += 16 + param_size ;
186+ offset += OPCODE_HEADER_SIZE + param_size ;
111187 count -- ;
112188 }
113189}
@@ -118,50 +194,86 @@ void dt_dng_opcode_process_opcode_list_3(uint8_t *buf, uint32_t buf_size, dt_ima
118194 cd -> dng .has_warp = FALSE;
119195 cd -> dng .has_vignette = FALSE;
120196
197+ if (buf_size < OPCODE_LIST_HEADER_SIZE )
198+ {
199+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid OpcodeList3 header" );
200+ return ;
201+ }
202+
121203 uint32_t count = _get_long (& buf [0 ]);
122- uint32_t offset = 4 ;
204+ uint32_t offset = OPCODE_LIST_HEADER_SIZE ;
123205 while (count > 0 )
124206 {
207+ if (offset > buf_size || buf_size - offset < OPCODE_HEADER_SIZE )
208+ {
209+ dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid opcode header in OpcodeList3" );
210+ return ;
211+ }
212+
125213 uint32_t opcode_id = _get_long (& buf [offset ]);
126214 uint32_t flags = _get_long (& buf [offset + 8 ]);
127215 uint32_t param_size = _get_long (& buf [offset + 12 ]);
128- uint8_t * param = & buf [offset + 16 ];
216+ uint8_t * param = & buf [offset + OPCODE_HEADER_SIZE ];
129217
130- if (offset + 16 + param_size > buf_size )
218+ if (param_size > buf_size - offset - OPCODE_HEADER_SIZE )
131219 {
132220 dt_print (DT_DEBUG_IMAGEIO , "[dng_opcode] Invalid opcode size in OpcodeList3" );
133221 return ;
134222 }
135223
136224 if (opcode_id == OPCODE_ID_WARP_RECTILINEAR )
137225 {
226+ if (param_size < DNG_UINT32_SIZE )
227+ {
228+ dt_print (DT_DEBUG_IMAGEIO , "[OPCODE_ID_WARP_RECTILINEAR] Invalid opcode size" );
229+ return ;
230+ }
231+
138232 const int planes = _get_long (& param [0 ]);
139233 if ((planes != 1 ) && (planes != 3 ))
140234 {
141235 dt_print (DT_DEBUG_IMAGEIO , "[OPCODE_ID_WARP_RECTILINEAR] Invalid number of planes %i" , planes );
142236 return ;
143237 }
144238
239+ const uint32_t required_size = WARP_RECTILINEAR_SIZE (planes );
240+ if (param_size < required_size )
241+ {
242+ dt_print (DT_DEBUG_IMAGEIO , "[OPCODE_ID_WARP_RECTILINEAR] Invalid opcode size" );
243+ return ;
244+ }
245+
145246 cd -> dng .planes = planes ;
146247 for (int p = 0 ; p < planes ; p ++ )
147248 {
148- for (int i = 0 ; i < 6 ; i ++ )
149- cd -> dng .cwarp [p ][i ] = _get_double (& param [4 + 8 * (i + p * 6 )]);
249+ for (int i = 0 ; i < WARP_COEFFICIENTS_PER_PLANE ; i ++ )
250+ cd -> dng .cwarp [p ][i ] =
251+ _get_double (& param [DNG_UINT32_SIZE
252+ + DNG_DOUBLE_SIZE * (i + p * WARP_COEFFICIENTS_PER_PLANE )]);
150253 }
151254
152- for (int i = 0 ; i < 2 ; i ++ )
153- cd -> dng .centre_warp [i ] = _get_double (& param [4 + 8 * (i + planes * 6 )]);
255+ for (int i = 0 ; i < OPCODE_CENTER_VALUES ; i ++ )
256+ cd -> dng .centre_warp [i ] =
257+ _get_double (& param [DNG_UINT32_SIZE
258+ + DNG_DOUBLE_SIZE * (i + planes * WARP_COEFFICIENTS_PER_PLANE )]);
154259
155260 img -> exif_correction_type = CORRECTION_TYPE_DNG ;
156261 cd -> dng .has_warp = TRUE;
157262 }
158263
159264 else if (opcode_id == OPCODE_ID_VIGNETTE_RADIAL )
160265 {
161- for (int i = 0 ; i < 5 ; i ++ )
162- cd -> dng .cvig [i ] = _get_double (& param [8 * i ]);
163- for (int i = 0 ; i < 2 ; i ++ )
164- cd -> dng .centre_vig [i ] = _get_double (& param [8 * (5 + i )]);
266+ if (param_size < VIGNETTE_RADIAL_SIZE )
267+ {
268+ dt_print (DT_DEBUG_IMAGEIO , "[OPCODE_ID_VIGNETTE_RADIAL] Invalid opcode size" );
269+ return ;
270+ }
271+
272+ for (int i = 0 ; i < VIGNETTE_COEFFICIENTS ; i ++ )
273+ cd -> dng .cvig [i ] = _get_double (& param [DNG_DOUBLE_SIZE * i ]);
274+ for (int i = 0 ; i < OPCODE_CENTER_VALUES ; i ++ )
275+ cd -> dng .centre_vig [i ] =
276+ _get_double (& param [DNG_DOUBLE_SIZE * (VIGNETTE_COEFFICIENTS + i )]);
165277
166278 cd -> dng .has_vignette = TRUE;
167279 img -> exif_correction_type = CORRECTION_TYPE_DNG ;
@@ -173,7 +285,7 @@ void dt_dng_opcode_process_opcode_list_3(uint8_t *buf, uint32_t buf_size, dt_ima
173285 flags & 1 ? "optional" : "mandatory" , opcode_id );
174286 }
175287
176- offset += 16 + param_size ;
288+ offset += OPCODE_HEADER_SIZE + param_size ;
177289 count -- ;
178290 }
179291}
0 commit comments