Ignore:
Timestamp:
Nov 8, 2017 2:58:18 AM (5 years ago)
Author:
riza
Message:

Closed #2056: Add validity checking for numeric header values.

File:
1 edited

Legend:

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

    r5280 r5682  
    3535#include <pj/ctype.h> 
    3636#include <pj/assert.h> 
     37#include <pj/limits.h> 
    3738 
    3839#define THIS_FILE           "sip_parser.c" 
     
    9495 */ 
    9596int PJSIP_SYN_ERR_EXCEPTION = -1; 
     97int PJSIP_EINVAL_ERR_EXCEPTION = -2; 
    9698 
    9799/* Parser constants */ 
     
    206208#define parser_stricmp(s1, s2)  (s1.slen!=s2.slen || pj_stricmp_alnum(&s1, &s2)) 
    207209 
    208  
    209210/* Get a token and unescape */ 
    210211PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool, 
     
    224225} 
    225226 
    226  
    227  
    228227/* Syntax error handler for parser. */ 
    229228static void on_syntax_error(pj_scanner *scanner) 
     
    231230    PJ_UNUSED_ARG(scanner); 
    232231    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); 
     232} 
     233 
     234/* Syntax error handler for parser. */ 
     235static void on_str_parse_error(const pj_str_t *str, int rc) 
     236{ 
     237    char *s; 
     238 
     239    switch(rc) { 
     240    case PJ_EINVAL: 
     241        s = "NULL input string, invalid input string, or NULL return "\ 
     242            "value pointer"; 
     243        break; 
     244    case PJ_ETOOSMALL: 
     245        s = "String value was less than the minimum allowed value."; 
     246        break; 
     247    case PJ_ETOOBIG: 
     248        s = "String value was greater than the maximum allowed value."; 
     249        break; 
     250    default: 
     251        s = "Unknown error"; 
     252    } 
     253 
     254    if (str) { 
     255        PJ_LOG(1, (THIS_FILE, "Error parsing '%.*s': %s", 
     256                   (int)str->slen, str->ptr, s)); 
     257    } else { 
     258        PJ_LOG(1, (THIS_FILE, "Can't parse input string: %s", s)); 
     259    } 
     260    PJ_THROW(PJSIP_EINVAL_ERR_EXCEPTION); 
     261} 
     262 
     263static void strtoi_validate(const pj_str_t *str, int min_val, 
     264                            int max_val, int *value) 
     265{  
     266    long retval; 
     267    pj_status_t status; 
     268 
     269    if (!str || !value) { 
     270        on_str_parse_error(str, PJ_EINVAL); 
     271    } 
     272    status = pj_strtol2(str, &retval); 
     273    if (status != PJ_EINVAL) { 
     274        if (min_val > retval) { 
     275            *value = min_val; 
     276            status = PJ_ETOOSMALL; 
     277        } else if (retval > max_val) { 
     278            *value = max_val; 
     279            status = PJ_ETOOBIG; 
     280        } else 
     281            *value = (int)retval; 
     282    } 
     283 
     284    if (status != PJ_SUCCESS) 
     285        on_str_parse_error(str, status); 
    233286} 
    234287 
     
    286339 
    287340    /* 
     341     * Invalid value exception. 
     342     */ 
     343    pj_assert (PJSIP_EINVAL_ERR_EXCEPTION == -2); 
     344    status = pj_exception_id_alloc("PJSIP invalid value error",  
     345                                   &PJSIP_EINVAL_ERR_EXCEPTION); 
     346    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
     347 
     348    /* 
    288349     * Init character input spec (cis) 
    289350     */ 
     
    503564        pj_exception_id_free(PJSIP_SYN_ERR_EXCEPTION); 
    504565        PJSIP_SYN_ERR_EXCEPTION = -1; 
     566 
     567        pj_exception_id_free(PJSIP_EINVAL_ERR_EXCEPTION); 
     568        PJSIP_EINVAL_ERR_EXCEPTION = -2; 
    505569    } 
    506570    pj_leave_critical_section(); 
     
    767831 
    768832/* Determine if a message has been received. */ 
    769 PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,  
     833PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size,  
    770834                                  pj_bool_t is_datagram, pj_size_t *msg_size) 
    771835{ 
     
    777841    int content_length = -1; 
    778842    pj_str_t cur_msg; 
     843    pj_status_t status = PJ_SUCCESS; 
    779844    const pj_str_t end_hdr = { "\n\r\n", 3}; 
    780845 
     
    837902 
    838903                /* Found a valid Content-Length header. */ 
    839                 content_length = pj_strtoul(&str_clen); 
     904                strtoi_validate(&str_clen, PJSIP_MIN_CONTENT_LENGTH, 
     905                                PJSIP_MAX_CONTENT_LENGTH, &content_length); 
    840906            } 
    841907            PJ_CATCH_ANY { 
     908                int eid = PJ_GET_EXCEPTION(); 
     909                if (eid == PJSIP_SYN_ERR_EXCEPTION) { 
     910                    status = PJSIP_EMISSINGHDR; 
     911                } else if (eid == PJSIP_EINVAL_ERR_EXCEPTION) { 
     912                    status = PJSIP_EINVALIDHDR; 
     913                } 
    842914                content_length = -1; 
    843915            } 
     
    859931    /* Found Content-Length? */ 
    860932    if (content_length == -1) { 
    861         return PJSIP_EMISSINGHDR; 
     933        return status; 
    862934    } 
    863935 
     
    9391011                                 pjsip_parser_err_report *err_list) 
    9401012{ 
    941     pj_bool_t parsing_headers; 
    942     pjsip_msg *msg = NULL; 
     1013    /* These variables require "volatile" so their values get 
     1014     * preserved when re-entering the PJ_TRY block after an error. 
     1015     */ 
     1016    volatile pj_bool_t parsing_headers; 
     1017    pjsip_msg *volatile msg = NULL; 
     1018    pjsip_ctype_hdr *volatile ctype_hdr = NULL; 
     1019 
    9431020    pj_str_t hname; 
    944     pjsip_ctype_hdr *ctype_hdr = NULL; 
    9451021    pj_scanner *scanner = ctx->scanner; 
    9461022    pj_pool_t *pool = ctx->pool; 
     
    10241100            } 
    10251101             
    1026          
    10271102            /* Single parse of header line can produce multiple headers. 
    10281103             * For example, if one Contact: header contains Contact list 
     
    12681343        pj_scan_get_char(scanner); 
    12691344        pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &port); 
    1270         *p_port = pj_strtoul(&port); 
     1345        strtoi_validate(&port, PJSIP_MIN_PORT, PJSIP_MAX_PORT, p_port); 
    12711346    } else { 
    12721347        *p_port = 0; 
     
    14591534 
    14601535        } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) { 
    1461             url->ttl_param = pj_strtoul(&pvalue); 
    1462  
     1536            strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL, 
     1537                            &url->ttl_param); 
    14631538        } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) { 
    14641539            url->maddr_param = pvalue; 
     
    15961671    parse_sip_version(scanner); 
    15971672    pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token); 
    1598     status_line->code = pj_strtoul(&token); 
     1673    strtoi_validate(&token, PJSIP_MIN_STATUS_CODE, PJSIP_MAX_STATUS_CODE, 
     1674                    &status_line->code); 
    15991675    if (*scanner->curptr != '\r' && *scanner->curptr != '\n') 
    16001676        pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &status_line->reason); 
     
    17811857            char *dot_pos = (char*) pj_memchr(pvalue.ptr, '.', pvalue.slen); 
    17821858            if (!dot_pos) { 
    1783                 hdr->q1000 = pj_strtoul(&pvalue) * 1000; 
     1859                strtoi_validate(&pvalue, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000, 
     1860                                &hdr->q1000); 
     1861                hdr->q1000 *= 1000; 
    17841862            } else { 
    17851863                pj_str_t tmp = pvalue; 
     1864                unsigned long qval_frac; 
    17861865 
    17871866                tmp.slen = dot_pos - pvalue.ptr; 
    1788                 hdr->q1000 = pj_strtoul(&tmp) * 1000; 
     1867                strtoi_validate(&tmp, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000, 
     1868                                &hdr->q1000); 
     1869                hdr->q1000 *= 1000; 
    17891870 
    17901871                pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1); 
    17911872                pvalue.ptr = dot_pos + 1; 
    1792                 hdr->q1000 += pj_strtoul_mindigit(&pvalue, 3); 
     1873                if (pvalue.slen > 3) { 
     1874                    pvalue.slen = 3; 
     1875                } 
     1876                qval_frac = pj_strtoul_mindigit(&pvalue, 3); 
     1877                if ((unsigned)hdr->q1000 > (PJ_MAXINT32 - qval_frac)) { 
     1878                    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); 
     1879                } 
     1880                hdr->q1000 += qval_frac; 
    17931881            }     
    1794         } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && pvalue.slen) { 
    1795             hdr->expires = pj_strtoul(&pvalue); 
    1796  
     1882        } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) &&  
     1883                   pvalue.slen)  
     1884        { 
     1885            strtoi_validate(&pvalue, PJSIP_MIN_EXPIRES, PJSIP_MAX_EXPIRES, 
     1886                            &hdr->expires); 
    17971887        } else { 
    17981888            pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); 
     
    18911981{ 
    18921982    pj_str_t cseq, method; 
    1893     pjsip_cseq_hdr *hdr; 
     1983    pjsip_cseq_hdr *hdr = NULL; 
     1984    int cseq_val = 0; 
     1985 
     1986    pj_scan_get( ctx->scanner, &pconst.pjsip_DIGIT_SPEC, &cseq); 
     1987    strtoi_validate(&cseq, PJSIP_MIN_CSEQ, PJSIP_MAX_CSEQ, &cseq_val); 
    18941988 
    18951989    hdr = pjsip_cseq_hdr_create(ctx->pool); 
    1896     pj_scan_get( ctx->scanner, &pconst.pjsip_DIGIT_SPEC, &cseq); 
    1897     hdr->cseq = pj_strtoul(&cseq); 
     1990    hdr->cseq = cseq_val; 
    18981991 
    18991992    pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method); 
     1993    parse_hdr_end( ctx->scanner ); 
     1994 
    19001995    pjsip_method_init_np(&hdr->method, &method); 
    1901  
    1902     parse_hdr_end( ctx->scanner ); 
    1903  
    1904     if (ctx->rdata) 
     1996    if (ctx->rdata) { 
    19051997        ctx->rdata->msg_info.cseq = hdr; 
     1998    } 
    19061999 
    19072000    return (pjsip_hdr*)hdr; 
     
    19852078     
    19862079    pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &tmp); 
    1987     hdr->ivalue = pj_strtoul(&tmp); 
     2080    strtoi_validate(&tmp, PJSIP_MIN_RETRY_AFTER, PJSIP_MAX_RETRY_AFTER, 
     2081                    &hdr->ivalue); 
    19882082 
    19892083    while (!pj_scan_is_eof(scanner) && *scanner->curptr!='\r' && 
     
    20742168 
    20752169        } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) { 
    2076             hdr->ttl_param = pj_strtoul(&pvalue); 
     2170            strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL, 
     2171                            &hdr->ttl_param); 
    20772172             
    20782173        } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) { 
     
    20832178 
    20842179        } else if (!parser_stricmp(pname, pconst.pjsip_RPORT_STR)) { 
    2085             if (pvalue.slen) 
    2086                 hdr->rport_param = pj_strtoul(&pvalue); 
    2087             else 
     2180            if (pvalue.slen) { 
     2181                strtoi_validate(&pvalue, PJSIP_MIN_PORT, PJSIP_MAX_PORT, 
     2182                                &hdr->rport_param); 
     2183            } else 
    20882184                hdr->rport_param = 0; 
    20892185        } else { 
     
    22142310            pj_scan_get_char(scanner); 
    22152311            pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &digit); 
    2216             hdr->sent_by.port = pj_strtoul(&digit); 
     2312            strtoi_validate(&digit, PJSIP_MIN_PORT, PJSIP_MAX_PORT, 
     2313                            &hdr->sent_by.port); 
    22172314        } 
    22182315         
     
    22992396{ 
    23002397    enum { STOP_ON_ERROR = 1 }; 
     2398    pj_str_t hname; 
    23012399    pj_scanner scanner; 
    23022400    pjsip_parse_ctx ctx; 
    2303     pj_str_t hname; 
     2401 
    23042402    PJ_USE_EXCEPTION; 
    23052403 
     
    23242422            hname.slen = 0; 
    23252423 
    2326             /* Get hname. */ 
     2424            /* Get hname. */             
    23272425            pj_scan_get( &scanner, &pconst.pjsip_TOKEN_SPEC, &hname); 
    23282426            if (pj_scan_get_char( &scanner ) != ':') { 
Note: See TracChangeset for help on using the changeset viewer.