Skip to content

Commit c38a669

Browse files
committed
fix(jpeg): Add check for jpeg marker parser in order to enhance safety
1 parent d816c3f commit c38a669

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

components/esp_driver_jpeg/jpeg_parse_marker.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ static const char *TAG = "jpeg.decoder";
2020

2121
static uint8_t jpeg_get_char(jpeg_dec_header_info_t *header_info)
2222
{
23+
// Check if there are bytes left to read before decrementing buffer_left
24+
if (header_info->buffer_left == 0) {
25+
ESP_LOGE(TAG, "Buffer underflow detected in jpeg_get_char: no more bytes left to read");
26+
return 0;
27+
}
2328
uint8_t c = header_info->buffer_offset[0];
2429
header_info->buffer_offset++;
2530
header_info->header_size++;
@@ -39,20 +44,26 @@ uint32_t jpeg_get_bytes(jpeg_dec_header_info_t *header_info, uint8_t num_bytes)
3944

4045
esp_err_t jpeg_parse_appn_marker(jpeg_dec_header_info_t *header_info)
4146
{
42-
uint32_t skip_num = jpeg_get_bytes(header_info, 2);
43-
header_info->buffer_offset += (skip_num - 2);
44-
header_info->header_size += (skip_num - 2);
45-
header_info->buffer_left -= (skip_num - 2);
47+
uint16_t skip_num = jpeg_get_bytes(header_info, 2);
48+
ESP_RETURN_ON_FALSE(skip_num >= 2, ESP_ERR_INVALID_ARG, TAG, "Invalid APPn marker length: %"PRIu32, skip_num);
49+
uint16_t bytes_to_skip = skip_num - 2;
50+
ESP_RETURN_ON_FALSE(header_info->buffer_left >= bytes_to_skip, ESP_ERR_INVALID_ARG, TAG, "APPn marker data underflow for buffer_left: %"PRIu32, header_info->buffer_left);
51+
header_info->buffer_offset += bytes_to_skip;
52+
header_info->header_size += bytes_to_skip;
53+
header_info->buffer_left -= bytes_to_skip;
4654

4755
return ESP_OK;
4856
}
4957

5058
esp_err_t jpeg_parse_com_marker(jpeg_dec_header_info_t *header_info)
5159
{
52-
uint32_t skip_num = jpeg_get_bytes(header_info, 2);
53-
header_info->buffer_offset += (skip_num - 2);
54-
header_info->header_size += (skip_num - 2);
55-
header_info->buffer_left -= (skip_num - 2);
60+
uint16_t skip_num = jpeg_get_bytes(header_info, 2);
61+
ESP_RETURN_ON_FALSE(skip_num >= 2, ESP_ERR_INVALID_ARG, TAG, "Invalid COM marker length: %"PRIu32, skip_num);
62+
uint32_t bytes_to_skip = skip_num - 2;
63+
ESP_RETURN_ON_FALSE(header_info->header_size >= bytes_to_skip, ESP_ERR_INVALID_ARG, TAG, "COM marker data underflow for header_size: %"PRIu32, header_info->header_size);
64+
header_info->buffer_offset += bytes_to_skip;
65+
header_info->header_size += bytes_to_skip;
66+
header_info->buffer_left -= bytes_to_skip;
5667
return ESP_OK;
5768
}
5869

@@ -61,21 +72,25 @@ esp_err_t jpeg_parse_dqt_marker(jpeg_dec_header_info_t *header_info)
6172
uint32_t n = 0, i = 0, prec = 0;
6273
uint32_t temp = 0;
6374

64-
uint32_t length_num = jpeg_get_bytes(header_info, 2);
75+
uint16_t length_num = jpeg_get_bytes(header_info, 2);
76+
ESP_RETURN_ON_FALSE(length_num >= 2, ESP_ERR_INVALID_ARG, TAG, "Invalid DQT marker length: %"PRIu32, length_num);
6577
length_num -= 2;
6678

6779
while (length_num) {
6880
n = jpeg_get_bytes(header_info, 1);
6981
prec = n >> 4;
7082
n &= 0x0F;
83+
ESP_RETURN_ON_FALSE(length_num >= 1, ESP_ERR_INVALID_ARG, TAG, "DQT marker length error: %"PRIu32, length_num);
7184
length_num -= 1;
7285

7386
// read quantization entries, in zig-zag order
7487
for (i = 0; i < 64; i++) {
7588
temp = jpeg_get_bytes(header_info, 1);
89+
ESP_RETURN_ON_FALSE(length_num >= 1, ESP_ERR_INVALID_ARG, TAG, "DQT marker length error: %"PRIu32, length_num);
7690
length_num -= 1;
7791
if (prec) {
7892
temp = (temp << 8) + jpeg_get_bytes(header_info, 1);
93+
ESP_RETURN_ON_FALSE(length_num >= 1, ESP_ERR_INVALID_ARG, TAG, "DQT marker length error: %"PRIu32, length_num);
7994
length_num -= 1;
8095
}
8196
header_info->qt_tbl[n][zigzag_arr[i]] = temp;
@@ -142,7 +157,10 @@ esp_err_t jpeg_parse_sof_marker(jpeg_dec_header_info_t *header_info)
142157
esp_err_t jpeg_parse_dht_marker(jpeg_dec_header_info_t *header_info)
143158
{
144159
// Recording num_left in DHT sector, not including length bytes (2 bytes).
145-
uint32_t num_left = jpeg_get_bytes(header_info, 2) - 2;
160+
uint16_t raw_length = jpeg_get_bytes(header_info, 2);
161+
// Check for integer underflow before subtraction
162+
ESP_RETURN_ON_FALSE(raw_length >= 2, ESP_ERR_INVALID_ARG, TAG, "Invalid DHT marker length: %"PRIu32, raw_length);
163+
uint16_t num_left = raw_length - 2;
146164
while (num_left) {
147165
uint32_t np = 0;
148166

@@ -159,6 +177,8 @@ esp_err_t jpeg_parse_dht_marker(jpeg_dec_header_info_t *header_info)
159177
header_info->huffcode[header_info->huffinfo.type][header_info->huffinfo.id][i] = jpeg_get_bytes(header_info, 1);
160178
}
161179

180+
// Check for integer underflow before subtraction
181+
ESP_RETURN_ON_FALSE(num_left >= (JPEG_HUFFMAN_BITS_LEN_TABLE_LEN + np + 1), ESP_ERR_INVALID_ARG, TAG, "DHT marker data underflow after parsing huffcode: %"PRIu32, num_left);
162182
num_left -= (1 + JPEG_HUFFMAN_BITS_LEN_TABLE_LEN + np);
163183
}
164184

@@ -181,6 +201,7 @@ esp_err_t jpeg_parse_dri_marker(jpeg_dec_header_info_t *header_info)
181201
esp_err_t jpeg_parse_sos_marker(jpeg_dec_header_info_t *header_info)
182202
{
183203
// Got the SOS marker, but need to recover this and feed to 2DDMA.
204+
ESP_RETURN_ON_FALSE(header_info->header_size >= 2, ESP_ERR_INVALID_ARG, TAG, "SOS marker header_size underflow: %"PRIu32, header_info->header_size);
184205
header_info->buffer_offset -= 2;
185206
header_info->header_size -= 2;
186207
header_info->buffer_left += 2;
@@ -191,6 +212,7 @@ esp_err_t jpeg_parse_inv_marker(jpeg_dec_header_info_t *header_info)
191212
{
192213
// Got invalid 0xFFFF, (followed by a valid marker type)
193214
// Go one byte back, to skip the first 0xFF
215+
ESP_RETURN_ON_FALSE(header_info->header_size >= 1, ESP_ERR_INVALID_ARG, TAG, "INV marker header_size underflow: %"PRIu32, header_info->header_size);
194216
header_info->buffer_offset--;
195217
header_info->header_size--;
196218
header_info->buffer_left++;

0 commit comments

Comments
 (0)