Skip to content

Commit 947bc1e

Browse files
authored
Merge pull request from GHSA-rwgw-vwxg-q799
* Prevent potential infinite loop when parsing WAV format file * Check if subchunk is negative. * Fix and add checks * Change data type from pj_ssize_t to long. * Modify check * Fix leak file descriptor and modify check on wav_playlist * Move overflow/underflow check to pj_file_setpos() * Use macro to simplify check * modification based on comments * Remove unnecessary casting * Modification based on comments
1 parent d2006a4 commit 947bc1e

File tree

5 files changed

+51
-10
lines changed

5 files changed

+51
-10
lines changed

Diff for: pjlib/include/pj/types.h

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* @{
3232
*/
3333
#include <pj/config.h>
34+
#include <pj/limits.h>
3435

3536
PJ_BEGIN_DECL
3637

@@ -361,6 +362,13 @@ PJ_INLINE(pj_int32_t) pj_swap32(pj_int32_t val32)
361362
return val32;
362363
}
363364

365+
/* This is to check if uint32 var will overflow if converted to signed long */
366+
#define PJ_CHECK_OVERFLOW_UINT32_TO_LONG(uint32_var, exec_on_overflow) \
367+
do { \
368+
if (uint32_var > PJ_MAXLONG) { \
369+
exec_on_overflow; \
370+
} \
371+
} while (0)
364372

365373
/**
366374
* @}

Diff for: pjlib/src/pj/file_io_ansi.c

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <pj/file_io.h>
2121
#include <pj/assert.h>
2222
#include <pj/errno.h>
23+
#include <pj/limits.h>
2324
#include <stdio.h>
2425
#include <errno.h>
2526

@@ -124,6 +125,12 @@ PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
124125
{
125126
int mode;
126127

128+
if ((sizeof(pj_off_t) > sizeof(long)) &&
129+
(offset > PJ_MAXLONG || offset < PJ_MINLONG))
130+
{
131+
return PJ_ENOTSUP;
132+
}
133+
127134
switch (whence) {
128135
case PJ_SEEK_SET:
129136
mode = SEEK_SET; break;

Diff for: pjmedia/src/pjmedia/avi_player.c

+18-4
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool,
282282
/* Read the headers of each stream. */
283283
for (i = 0; i < avi_hdr.avih_hdr.num_streams; i++) {
284284
pj_size_t elem = 0;
285-
pj_ssize_t size_to_read;
285+
pj_off_t size_to_read;
286286

287287
/* Read strl header */
288288
status = file_read(fport[0]->fd, &avi_hdr.strl_hdr[i],
@@ -335,6 +335,7 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool,
335335
do {
336336
pjmedia_avi_subchunk ch;
337337
int read = 0;
338+
pj_off_t size_to_read;
338339

339340
status = file_read(fport[0]->fd, &ch, sizeof(pjmedia_avi_subchunk));
340341
if (status != PJ_SUCCESS) {
@@ -349,7 +350,15 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool,
349350
break;
350351
}
351352

352-
status = pj_file_setpos(fport[0]->fd, ch.len-read, PJ_SEEK_CUR);
353+
if (ch.len < read) {
354+
status = PJ_EINVAL;
355+
goto on_error;
356+
}
357+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(ch.len - read,
358+
status = PJ_EINVAL; goto on_error;);
359+
size_to_read = (pj_off_t)ch.len - read;
360+
361+
status = pj_file_setpos(fport[0]->fd, size_to_read, PJ_SEEK_CUR);
353362
if (status != PJ_SUCCESS) {
354363
goto on_error;
355364
}
@@ -775,6 +784,8 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
775784
/* Read new chunk data */
776785
if (fport->size_left == 0) {
777786
pj_off_t pos;
787+
pj_off_t ch_len;
788+
778789
pj_file_getpos(fport->fd, &pos);
779790

780791
/* Data is padded to the nearest WORD boundary */
@@ -788,6 +799,10 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
788799
size_read = 0;
789800
goto on_error2;
790801
}
802+
803+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(ch.len,
804+
status = PJ_EINVAL; goto on_error2;);
805+
ch_len = ch.len;
791806

792807
cid = (char *)&ch.id;
793808
if (cid[0] >= '0' && cid[0] <= '9' &&
@@ -814,8 +829,7 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
814829
goto on_error2;
815830
}
816831

817-
status = pj_file_setpos(fport->fd, ch.len,
818-
PJ_SEEK_CUR);
832+
status = pj_file_setpos(fport->fd, ch_len, PJ_SEEK_CUR);
819833
continue;
820834
}
821835
fport->size_left = ch.len;

Diff for: pjmedia/src/pjmedia/wav_player.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
188188
pjmedia_port **p_port )
189189
{
190190
pjmedia_wave_hdr wave_hdr;
191-
pj_ssize_t size_to_read, size_read;
191+
pj_ssize_t size_read;
192+
pj_off_t size_to_read;
192193
struct file_reader_port *fport;
193194
pjmedia_audio_format_detail *ad;
194195
pj_off_t pos;
@@ -234,7 +235,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
234235
return status;
235236

236237
/* Read the file header plus fmt header only. */
237-
size_read = size_to_read = sizeof(wave_hdr) - 8;
238+
size_to_read = size_read = sizeof(wave_hdr) - 8;
238239
status = pj_file_read( fport->fd, &wave_hdr, &size_read);
239240
if (status != PJ_SUCCESS) {
240241
pj_file_close(fport->fd);
@@ -297,7 +298,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
297298
* fmt header data.
298299
*/
299300
if (wave_hdr.fmt_hdr.len > 16) {
300-
size_to_read = wave_hdr.fmt_hdr.len - 16;
301+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(wave_hdr.fmt_hdr.len - 16,
302+
pj_file_close(fport->fd); return PJMEDIA_ENOTVALIDWAVE;);
303+
size_to_read = (pj_off_t)wave_hdr.fmt_hdr.len - 16;
301304
status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
302305
if (status != PJ_SUCCESS) {
303306
pj_file_close(fport->fd);
@@ -326,7 +329,10 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
326329
}
327330

328331
/* Otherwise skip the chunk contents */
332+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(subchunk.len,
333+
pj_file_close(fport->fd); return PJMEDIA_ENOTVALIDWAVE;);
329334
size_to_read = subchunk.len;
335+
330336
status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
331337
if (status != PJ_SUCCESS) {
332338
pj_file_close(fport->fd);

Diff for: pjmedia/src/pjmedia/wav_playlist.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_create(pj_pool_t *pool,
419419
for (index=file_count-1; index>=0; index--) {
420420

421421
pjmedia_wave_hdr wavehdr;
422-
pj_ssize_t size_to_read, size_read;
422+
pj_ssize_t size_read;
423+
pj_off_t size_to_read;
423424

424425
/* we end with the last one so we are good to go if still in function*/
425426
pj_memcpy(filename, file_list[index].ptr, file_list[index].slen);
@@ -442,7 +443,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_create(pj_pool_t *pool,
442443
goto on_error;
443444

444445
/* Read the file header plus fmt header only. */
445-
size_read = size_to_read = sizeof(wavehdr) - 8;
446+
size_to_read = size_read = sizeof(wavehdr) - 8;
446447
status = pj_file_read( fport->fd_list[index], &wavehdr, &size_read);
447448
if (status != PJ_SUCCESS) {
448449
goto on_error;
@@ -492,7 +493,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_create(pj_pool_t *pool,
492493
* fmt header data.
493494
*/
494495
if (wavehdr.fmt_hdr.len > 16) {
495-
size_to_read = wavehdr.fmt_hdr.len - 16;
496+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(wavehdr.fmt_hdr.len-16,
497+
status = PJMEDIA_ENOTVALIDWAVE; goto on_error;);
498+
size_to_read = (pj_off_t)wavehdr.fmt_hdr.len - 16;
496499
status = pj_file_setpos(fport->fd_list[index], size_to_read,
497500
PJ_SEEK_CUR);
498501
if (status != PJ_SUCCESS) {
@@ -522,7 +525,10 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_create(pj_pool_t *pool,
522525
}
523526

524527
/* Otherwise skip the chunk contents */
528+
PJ_CHECK_OVERFLOW_UINT32_TO_LONG(subchunk.len,
529+
status = PJMEDIA_ENOTVALIDWAVE; goto on_error;);
525530
size_to_read = subchunk.len;
531+
526532
status = pj_file_setpos(fport->fd_list[index], size_to_read,
527533
PJ_SEEK_CUR);
528534
if (status != PJ_SUCCESS) {

0 commit comments

Comments
 (0)