Ignore:
Timestamp:
Mar 12, 2009 11:25:11 AM (15 years ago)
Author:
bennylp
Message:

Initial fixes for ticket #747: bugs in parsing SIP torture messages (RFC 4475):

  • SIP version components may be separated by whitespaces (e.g. "SIP / 2.0")
  • parsing of mangled header when for unknown/generic header
  • Via parameters were parsed with paramchar rather than token
  • handling NULL character inside quoted string

Some torture messages have been added in the Python test.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_parser.c

    r2394 r2505  
    5454 */ 
    5555#define GENERIC_URI_CHARS   "#?;:@&=+-_.!~*'()%$,/" "%" 
    56  
    57 #define PJSIP_VERSION           "SIP/2.0" 
    5856 
    5957#define UNREACHED(expr) 
     
    894892} 
    895893 
     894/* SIP version */ 
     895static void parse_sip_version(pj_scanner *scanner) 
     896{ 
     897    pj_str_t SIP = { "SIP", 3 }; 
     898    pj_str_t V2 = { "2.0", 3 }; 
     899    pj_str_t sip, version; 
     900 
     901    pj_scan_get( scanner, &pconst.pjsip_ALPHA_SPEC, &sip); 
     902    if (pj_scan_get_char(scanner) != '/') 
     903        on_syntax_error(scanner); 
     904    pj_scan_get_n( scanner, 3, &version); 
     905    if (pj_stricmp(&sip, &SIP) || pj_stricmp(&version, &V2)) 
     906        on_syntax_error(scanner); 
     907} 
     908 
     909static pj_bool_t is_next_sip_version(pj_scanner *scanner) 
     910{ 
     911    pj_str_t SIP = { "SIP", 3 }; 
     912    pj_str_t sip; 
     913    int c; 
     914 
     915    c = pj_scan_peek(scanner, &pconst.pjsip_ALPHA_SPEC, &sip); 
     916    /* return TRUE if it is "SIP" followed by "/" or space. 
     917     * we include space since the "/" may be separated by space, 
     918     * although this would mean it would return TRUE if it is a 
     919     * request and the method is "SIP"! 
     920     */ 
     921    return c && (c=='/' || c==' ' || c=='\t') && pj_stricmp(&sip, &SIP)==0; 
     922} 
     923 
    896924/* Internal function to parse SIP message */ 
    897925static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx, 
     
    927955 
    928956        /* Parse request or status line */ 
    929         if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) == 0) { 
     957        if (is_next_sip_version(scanner)) { 
    930958            msg = pjsip_msg_create(pool, PJSIP_RESPONSE_MSG); 
    931959            int_parse_status_line( scanner, &msg->line.status ); 
     
    11261154 
    11271155 
    1128 /* Parse parameter (";" pname ["=" pvalue]) in header. */ 
     1156/* Parse parameter (";" pname ["=" pvalue]) in SIP header. */ 
    11291157static void int_parse_param( pj_scanner *scanner, pj_pool_t *pool, 
    11301158                             pj_str_t *pname, pj_str_t *pvalue, 
     
    15141542 
    15151543    req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE); 
    1516     if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION, 7) != 0) 
    1517         PJ_THROW( PJSIP_SYN_ERR_EXCEPTION); 
    1518     pj_scan_advance_n (scanner, 7, 1); 
     1544    parse_sip_version(scanner); 
    15191545    pj_scan_get_newline( scanner ); 
    15201546} 
     
    15261552    pj_str_t token; 
    15271553 
    1528     if (pj_scan_stricmp_alnum(scanner, PJSIP_VERSION, 7) != 0) 
    1529         PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); 
    1530     pj_scan_advance_n( scanner, 7, 1); 
    1531  
     1554    parse_sip_version(scanner); 
    15321555    pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token); 
    15331556    status_line->code = pj_strtoul(&token); 
     
    16191642/* Parse generic string header. */ 
    16201643static void parse_generic_string_hdr( pjsip_generic_string_hdr *hdr, 
    1621                                       pj_scanner *scanner ) 
    1622 { 
    1623     if (pj_cis_match(&pconst.pjsip_NOT_NEWLINE, *scanner->curptr)) 
     1644                                      pjsip_parse_ctx *ctx) 
     1645{ 
     1646    pj_scanner *scanner = ctx->scanner; 
     1647 
     1648    hdr->hvalue.slen = 0; 
     1649 
     1650    /* header may be mangled hence the loop */ 
     1651    while (pj_cis_match(&pconst.pjsip_NOT_NEWLINE, *scanner->curptr)) { 
     1652        pj_str_t next, tmp; 
     1653 
    16241654        pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &hdr->hvalue); 
    1625     else 
    1626         hdr->hvalue.slen = 0; 
     1655        if (IS_NEWLINE(*scanner->curptr)) 
     1656            break; 
     1657        /* mangled, get next fraction */ 
     1658        pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &next); 
     1659        /* concatenate */ 
     1660        tmp.ptr = (char*)pj_pool_alloc(ctx->pool,  
     1661                                       hdr->hvalue.slen + next.slen + 2); 
     1662        tmp.slen = 0; 
     1663        pj_strcpy(&tmp, &hdr->hvalue); 
     1664        pj_strcat2(&tmp, " "); 
     1665        pj_strcat(&tmp, &next); 
     1666        tmp.ptr[tmp.slen] = '\0'; 
     1667 
     1668        hdr->hvalue = tmp; 
     1669    } 
    16271670 
    16281671    parse_hdr_end(scanner); 
     
    19351978 
    19361979        //Parse with PARAM_CHAR instead, to allow IPv6 
     1980        //No, back to using int_parse_param() for the "`" character! 
    19371981        //int_parse_param( scanner, pool, &pname, &pvalue, 0); 
    1938         /* Get ';' character */ 
    1939         pj_scan_get_char(scanner); 
    1940  
    1941         parse_param_imp(scanner, pool, &pname, &pvalue,  
    1942                         &pconst.pjsip_PARAM_CHAR_SPEC, 
    1943                         &pconst.pjsip_PARAM_CHAR_SPEC_ESC, 0); 
     1982        //parse_param_imp(scanner, pool, &pname, &pvalue,  
     1983        //              &pconst.pjsip_TOKEN_SPEC, 
     1984        //              &pconst.pjsip_TOKEN_SPEC_ESC, 0); 
     1985        int_parse_param(scanner, pool, &pname, &pvalue, 0); 
    19441986 
    19451987        if (!parser_stricmp(pname, pconst.pjsip_BRANCH_STR) && pvalue.slen) { 
     
    20762118            pj_list_insert_before(first, hdr); 
    20772119 
    2078         if (pj_scan_stricmp_alnum( scanner, PJSIP_VERSION "/", 8) != 0) 
    2079             PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); 
    2080  
    2081         pj_scan_advance_n( scanner, 8, 1); 
     2120        parse_sip_version(scanner); 
     2121        if (pj_scan_get_char(scanner) != '/') 
     2122            on_syntax_error(scanner); 
    20822123 
    20832124        pj_scan_get( scanner, &pconst.pjsip_TOKEN_SPEC, &hdr->transport); 
     
    21202161 
    21212162    hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL, NULL); 
    2122     parse_generic_string_hdr(hdr, ctx->scanner); 
     2163    parse_generic_string_hdr(hdr, ctx); 
    21232164    return (pjsip_hdr*)hdr; 
    21242165 
Note: See TracChangeset for help on using the changeset viewer.