Skip to content

Commit

Permalink
parse_uri: Fix some UB corner-cases (reported by OSS-Fuzz)
Browse files Browse the repository at this point in the history
* possible bitwise left shift with a negative value (UB)
* possible integer overflow, due to multiplication (UB)

Fixes OSS-Fuzz#48273

(cherry picked from commit cf95355)
  • Loading branch information
liviuchircu committed Sep 15, 2022
1 parent d798d7b commit 7cc6242
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 25 deletions.
55 changes: 30 additions & 25 deletions parser/parse_uri.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,10 +369,13 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
int i;
#endif

#define case_port( ch, var) \
#define case_port( ch, var, ovf_check1, ovf_check2) \
case ch: \
(var)=(var)*10+ch-'0'; \
break
if (ovf_check1) \
(var)=(var)*10+ch-'0'; \
if (ovf_check2 && (var) > USHRT_MAX) \
goto error_bad_port; \
break

#define still_at_user \
if (found_user==0){ \
Expand Down Expand Up @@ -656,7 +659,8 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure*/
/*look for sip:, sips: or tel:*/
if (len<5) goto error_too_short;
scheme=buf[0]+(buf[1]<<8)+(buf[2]<<16)+(buf[3]<<24);
scheme=(unsigned char)buf[0]+((unsigned char)buf[1]<<8)+
((unsigned char)buf[2]<<16)+((unsigned char)buf[3]<<24);
scheme|=0x20202020;
if (scheme==SIP_SCH){
uri->type=SIP_URI_T;
Expand Down Expand Up @@ -775,16 +779,16 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
found_user=1; /* there is no user part */
s=p+1;
break;
case_port('0', port_no);
case_port('1', port_no);
case_port('2', port_no);
case_port('3', port_no);
case_port('4', port_no);
case_port('5', port_no);
case_port('6', port_no);
case_port('7', port_no);
case_port('8', port_no);
case_port('9', port_no);
case_port('0', port_no, port_no < INT_MAX / 10, 0);
case_port('1', port_no, port_no < INT_MAX / 10, 0);
case_port('2', port_no, port_no < INT_MAX / 10, 0);
case_port('3', port_no, port_no < INT_MAX / 10, 0);
case_port('4', port_no, port_no < INT_MAX / 10, 0);
case_port('5', port_no, port_no < INT_MAX / 10, 0);
case_port('6', port_no, port_no < INT_MAX / 10, 0);
case_port('7', port_no, port_no < INT_MAX / 10, 0);
case_port('8', port_no, port_no < INT_MAX / 10, 0);
case_port('9', port_no, port_no < INT_MAX / 10, 0);
case '[':
case ']':
case ':':
Expand Down Expand Up @@ -870,16 +874,16 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
state=URI_HEADERS;
s=p+1;
break;
case_port('0', port_no);
case_port('1', port_no);
case_port('2', port_no);
case_port('3', port_no);
case_port('4', port_no);
case_port('5', port_no);
case_port('6', port_no);
case_port('7', port_no);
case_port('8', port_no);
case_port('9', port_no);
case_port('0', port_no, 1, 1);
case_port('1', port_no, 1, 1);
case_port('2', port_no, 1, 1);
case_port('3', port_no, 1, 1);
case_port('4', port_no, 1, 1);
case_port('5', port_no, 1, 1);
case_port('6', port_no, 1, 1);
case_port('7', port_no, 1, 1);
case_port('8', port_no, 1, 1);
case_port('9', port_no, 1, 1);
case '&':
case '@':
case ':':
Expand Down Expand Up @@ -1350,6 +1354,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
case URI_PASSWORD:
/* this is the port, it can't be the passwd */
if (found_user) goto error_bad_port;
if (port_no > USHRT_MAX) goto error_bad_port;
uri->port.s=s;
uri->port.len=p-s;
uri->port_no=port_no;
Expand Down Expand Up @@ -1609,7 +1614,7 @@ int parse_uri(char* buf, int len, struct sip_uri* uri)
len, ZSW(buf), len);
goto error_exit;
error_bad_port:
LM_ERR("bad port in uri (error at char %c in"
LM_ERR("bad port in uri (error at char '%c' in"
" state %d) parsed: <%.*s>(%d) /<%.*s> (%d)\n",
*p, state, (int)(p-buf), ZSW(buf), (int)(p-buf),
len, ZSW(buf), len);
Expand Down
14 changes: 14 additions & 0 deletions parser/test/test_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ void test_parse_uri(void)
ok(!u.user.s, "puri-0.5");
ok(u.user.len == 0, "puri-0.6");

/* URI port parsing tests, with or w/o a username */
ok(!parse_uri(STR_L("sip:localhost@atlanta.org:0"), &u), "puri-0.7");
ok(!parse_uri(STR_L("sip:localhost@atlanta.org:65535"), &u), "puri-0.8");
ok(parse_uri(STR_L("sip:localhost@atlanta.org:65536"), &u), "puri-0.9");
ok(parse_uri(STR_L("sip:localhost@atlanta.org:55555555555555555555"), &u), "puri-0.10");
ok(!parse_uri(STR_L("sip:localhost:0@atlanta.org"), &u), "puri-0.11");
ok(!parse_uri(STR_L("sip:localhost:65535@atlanta.org"), &u), "puri-0.12");
ok(!parse_uri(STR_L("sip:localhost:65536@atlanta.org"), &u), "puri-0.13");
ok(!parse_uri(STR_L("sip:localhost:5555555555555@atlanta.org"), &u), "puri-0.14");
ok(!parse_uri(STR_L("sip:localhost:0"), &u), "puri-0.15");
ok(!parse_uri(STR_L("sip:localhost:65535"), &u), "puri-0.16");
ok(parse_uri(STR_L("sip:localhost:65536"), &u), "puri-0.17");
ok(parse_uri(STR_L("sip:localhost:55555555555"), &u), "puri-0.18");

in = *_str("sip:alice@atlanta.org;user=phone");
ok(parse_uri(in.s, in.len, &u) == 0, "puri-1");
ok(str_match(&u.user_param, const_str("user=phone")), "puri-2");
Expand Down

0 comments on commit 7cc6242

Please sign in to comment.