CVE-2022-24792 (C, published 2022-04-25T16:16Z)
Description: value: PJSIP is a free and open source multimedia communication library written in C. A denial-of-service vulnerability affects applications on a 32-bit systems that use PJSIP versions 2.12 and prior to play/read invalid WAV files. The vulnerability occurs when reading WAV file data chunks with length greater than 31-bit integers. The vulnerability does not affect 64-bit apps and should not affect apps that only plays trusted WAV files. A patch is available on the `master` branch of the `pjsip/project` GitHub repository. As a workaround, apps can reject a WAV file received from an unknown source or validate the file first.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-835 \u2014 Loop with Unreachable Exit Condition ('Infinite Loop')
The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
Repository: https://github.com/pjsip/pjproject
Files changed:
pjlib/include/pj/types.h
pjlib/src/pj/file_io_ansi.c
pjmedia/src/pjmedia/avi_player.c
pjmedia/src/pjmedia/wav_player.c
pjmedia/src/pjmedia/wav_playlist.c
Commit message: 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

Vulnerable code:
        pj_ssize_t size_to_read;
        status = pj_file_setpos(fport[0]->fd, ch.len-read, PJ_SEEK_CUR);
                status = pj_file_setpos(fport->fd, ch.len,
                                        PJ_SEEK_CUR);
    pj_ssize_t size_to_read, size_read;
    size_read = size_to_read = sizeof(wave_hdr) - 8;
	size_to_read = wave_hdr.fmt_hdr.len - 16;
	pj_ssize_t size_to_read, size_read;
	size_read = size_to_read = sizeof(wavehdr) - 8;
	    size_to_read = wavehdr.fmt_hdr.len - 16;

Fixed code:
#include <pj/limits.h>
/* This is to check if uint32 var will overflow if converted to signed long */
#define PJ_CHECK_OVERFLOW_UINT32_TO_LONG(uint32_var, exec_on_overflow) \
	do { \
	    if (uint32_var > PJ_MAXLONG) { \
		exec_on_overflow; \
	    } \
	} while (0)
#include <pj/limits.h>
    if ((sizeof(pj_off_t) > sizeof(long)) &&
        (offset > PJ_MAXLONG || offset < PJ_MINLONG)) 
    {
        return PJ_ENOTSUP;
    }

        pj_off_t size_to_read;
        pj_off_t size_to_read;
        if (ch.len < read) {
            status = PJ_EINVAL;
            goto on_error;
        }
        PJ_CHECK_OVERFLOW_UINT32_TO_LONG(ch.len - read, 
                                         status = PJ_EINVAL; goto on_error;);
        size_to_read = (pj_off_t)ch.len - read;

        status = pj_file_setpos(fport[0]->fd, size_to_read, PJ_SEEK_CUR);
            pj_off_t ch_len;

            
            PJ_CHECK_OVERFLOW_UINT32_TO_LONG(ch.len, 
                                         status = PJ_EINVAL;  goto on_error2;);
            ch_len = ch.len;
                status = pj_file_setpos(fport->fd, ch_len, PJ_SEEK_CUR);
    pj_ssize_t size_read;
    pj_off_t size_to_read;
    size_to_read = size_read = sizeof(wave_hdr) - 8;
	PJ_CHECK_OVERFLOW_UINT32_TO_LONG(wave_hdr.fmt_hdr.len - 16,
		      pj_file_close(fport->fd); return PJMEDIA_ENOTVALIDWAVE;);
	size_to_read = (pj_off_t)wave_hdr.fmt_hdr.len - 16;
	PJ_CHECK_OVERFLOW_UINT32_TO_LONG(subchunk.len, 
		      pj_file_close(fport->fd); return PJMEDIA_ENOTVALIDWAVE;);

	pj_ssize_t size_read;
	pj_off_t size_to_read;
	size_to_read = size_read = sizeof(wavehdr) - 8;	
	    PJ_CHECK_OVERFLOW_UINT32_TO_LONG(wavehdr.fmt_hdr.len-16,
			       status = PJMEDIA_ENOTVALIDWAVE; goto on_error;);
	    size_to_read = (pj_off_t)wavehdr.fmt_hdr.len - 16;
	    PJ_CHECK_OVERFLOW_UINT32_TO_LONG(subchunk.len, 
			       status = PJMEDIA_ENOTVALIDWAVE; goto on_error;);