Merge "Build System: Disable parallel make in the root Makefile."
[asterisk/asterisk.git] / third-party / pjproject / patches / 0020-sip_parser-Add-validity-checking-for-numeric-header-.patch
1 From b21042956dc4d3526052d5030953e5c565bb0895 Mon Sep 17 00:00:00 2001
2 From: George Joseph <gjoseph@digium.com>
3 Date: Thu, 2 Nov 2017 08:23:00 -0600
4 Subject: [PATCH] sip_parser: Add validity checking for numeric header values
5
6 Parsing the numeric header fields like cseq, ttl, port, etc. all
7 had the potential to overflow, either causing unintended values to
8 be captured or, if the values were subsequently converted back to
9 strings, a buffer overrun.  To address this, new "strto" functions
10 have been created that do range checking and those functions are
11 used wherever possible in the parser.
12
13  * Created pjlib/include/limits.h and pjlib/include/compat/limits.h
14    to either include the system limits.h or define common numeric
15    limits if there is no system limits.h.
16
17  * Created strto*_validate functions in sip_parser that take bounds
18    and on failure call the on_str_parse_error function which prints
19    an error message and calls PJ_THROW.
20
21  * Updated sip_parser to validate the numeric fields.
22
23  * Fixed an issue in sip_transport that prevented error messages
24    from being properly displayed.
25
26  * Added "volatile" to some variables referenced in PJ_CATCH blocks
27    as the optimizer was sometimes optimizing them away.
28
29  * Fixed length calculation in sip_transaction/create_tsx_key_2543
30    to account for signed ints being 11 characters, not 9.
31
32 Reported by: Youngsung Kim at LINE Corporation
33 ---
34  pjlib/build/pjlib.vcproj           |  14 +++-
35  pjlib/build/pjlib.vcxproj          |   4 +-
36  pjlib/build/pjlib.vcxproj.filters  |   6 ++
37  pjlib/include/pj/compat/limits.h   |  65 +++++++++++++++
38  pjlib/include/pj/compat/os_win32.h |   1 +
39  pjlib/include/pj/limits.h          |  51 ++++++++++++
40  pjlib/include/pj/string.h          |  46 +++++++++-
41  pjlib/include/pj/types.h           |   3 -
42  pjlib/src/pj/string.c              | 119 +++++++++++++++++++++++++-
43  pjlib/src/pj/timer.c               |   1 +
44  pjsip/include/pjsip/sip_parser.h   |  25 ++++++
45  pjsip/src/pjsip/sip_parser.c       | 166 +++++++++++++++++++++++++++++--------
46  pjsip/src/pjsip/sip_transaction.c  |   4 +-
47  pjsip/src/pjsip/sip_transport.c    |   7 +-
48  14 files changed, 463 insertions(+), 49 deletions(-)
49  create mode 100644 pjlib/include/pj/compat/limits.h
50  create mode 100644 pjlib/include/pj/limits.h
51
52 diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj
53 index 6a217a0b7..12592ef94 100644
54 --- a/pjlib/build/pjlib.vcproj
55 +++ b/pjlib/build/pjlib.vcproj
56 @@ -14967,7 +14967,11 @@
57                         </File>\r
58                         <File\r
59                                 RelativePath="..\include\pj\ip_helper.h"\r
60 -                               >\r
61 +                               >
62 +                       </File>
63 +                       <File
64 +                               RelativePath="..\include\pj\limits.h"
65 +                               >
66                         </File>\r
67                         <File\r
68                                 RelativePath="..\include\pj\list.h"\r
69 @@ -15070,8 +15074,12 @@
70                                 </File>\r
71                                 <File\r
72                                         RelativePath="..\include\pj\compat\high_precision.h"\r
73 -                                       >\r
74 -                               </File>\r
75 +                                       >
76 +                               </File>
77 +                               <File
78 +                                       RelativePath="..\include\pj\compat\limits.h"
79 +                                       >
80 +                               </File>
81                                 <File\r
82                                         RelativePath="..\include\pj\compat\m_alpha.h"\r
83                                         >\r
84 diff --git a/pjlib/build/pjlib.vcxproj b/pjlib/build/pjlib.vcxproj
85 index abf09ec44..e41731e3c 100644
86 --- a/pjlib/build/pjlib.vcxproj
87 +++ b/pjlib/build/pjlib.vcxproj
88 @@ -494,7 +494,7 @@
89        <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
90        <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
91      </ClCompile>
92 -    <ClCompile Include="..\src\pj\file_io_win32.c" />    
93 +    <ClCompile Include="..\src\pj\file_io_win32.c" />
94      <ClCompile Include="..\src\pj\guid.c" />
95      <ClCompile Include="..\src\pj\guid_simple.c">
96        <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">true</ExcludedFromBuild>
97 @@ -890,6 +890,7 @@
98      <ClInclude Include="..\include\pj\compat\ctype.h" />
99      <ClInclude Include="..\include\pj\compat\errno.h" />
100      <ClInclude Include="..\include\pj\compat\high_precision.h" />
101 +    <ClInclude Include="..\include\pj\compat\limits.h" />
102      <ClInclude Include="..\include\pj\compat\malloc.h" />
103      <ClInclude Include="..\include\pj\compat\m_alpha.h" />
104      <ClInclude Include="..\include\pj\compat\m_i386.h" />
105 @@ -925,6 +926,7 @@
106      <ClInclude Include="..\include\pj\hash.h" />
107      <ClInclude Include="..\include\pj\ioqueue.h" />
108      <ClInclude Include="..\include\pj\ip_helper.h" />
109 +    <ClInclude Include="..\include\pj\limits.h" />
110      <ClInclude Include="..\include\pj\list.h" />
111      <ClInclude Include="..\include\pj\list_i.h" />
112      <ClInclude Include="..\include\pj\lock.h" />
113 diff --git a/pjlib/build/pjlib.vcxproj.filters b/pjlib/build/pjlib.vcxproj.filters
114 index 0b5cbf109..6f343b019 100644
115 --- a/pjlib/build/pjlib.vcxproj.filters
116 +++ b/pjlib/build/pjlib.vcxproj.filters
117 @@ -439,5 +439,11 @@
118      <ClInclude Include="..\include\pj\compat\os_winuwp.h">
119        <Filter>Header Files\compat</Filter>
120      </ClInclude>
121 +    <ClInclude Include="..\include\pj\limits.h">
122 +      <Filter>Header Files</Filter>
123 +    </ClInclude>
124 +    <ClInclude Include="..\include\pj\compat\limits.h">
125 +      <Filter>Header Files\compat</Filter>
126 +    </ClInclude>
127    </ItemGroup>
128  </Project>
129 \ No newline at end of file
130 diff --git a/pjlib/include/pj/compat/limits.h b/pjlib/include/pj/compat/limits.h
131 new file mode 100644
132 index 000000000..fba0625df
133 --- /dev/null
134 +++ b/pjlib/include/pj/compat/limits.h
135 @@ -0,0 +1,65 @@
136 +/* $Id$ */
137 +/*
138 + * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
139 + * Copyright (C) 2017 George Joseph <gjoseph@digium.com>
140 + *
141 + * This program is free software; you can redistribute it and/or modify
142 + * it under the terms of the GNU General Public License as published by
143 + * the Free Software Foundation; either version 2 of the License, or
144 + * (at your option) any later version.
145 + *
146 + * This program is distributed in the hope that it will be useful,
147 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
148 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149 + * GNU General Public License for more details.
150 + *
151 + * You should have received a copy of the GNU General Public License
152 + * along with this program; if not, write to the Free Software
153 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
154 + */
155 +#ifndef __PJ_COMPAT_LIMITS_H__
156 +#define __PJ_COMPAT_LIMITS_H__
157 +
158 +/**
159 + * @file limits.h
160 + * @brief Provides integer limits normally found in limits.h.
161 + */
162 +
163 +#if defined(PJ_HAS_LIMITS_H) && PJ_HAS_LIMITS_H != 0
164 +#  include <limits.h>
165 +#else
166 +
167 +#  ifdef _MSC_VER
168 +#  pragma message("limits.h is not found or not supported. LONG_MIN and "\
169 +                "LONG_MAX will be defined by the library in "\
170 +                "pj/compats/limits.h and overridable in config_site.h")
171 +#  else
172 +#  warning "limits.h is not found or not supported. LONG_MIN and LONG_MAX " \
173 +           "will be defined by the library in pj/compats/limits.h and "\
174 +           "overridable in config_site.h"
175 +#  endif
176 +
177 +/* Minimum and maximum values a `signed long int' can hold.  */
178 +#  ifndef LONG_MAX
179 +#    if __WORDSIZE == 64
180 +#      define LONG_MAX     9223372036854775807L
181 +#    else
182 +#      define LONG_MAX     2147483647L
183 +#    endif
184 +#  endif
185 +
186 +#  ifndef LONG_MIN
187 +#    define LONG_MIN      (-LONG_MAX - 1L)
188 +#  endif
189 +
190 +/* Maximum value an `unsigned long int' can hold.  (Minimum is 0.)  */
191 +#  ifndef ULONG_MAX
192 +#    if __WORDSIZE == 64
193 +#      define ULONG_MAX    18446744073709551615UL
194 +#    else    
195 +#      define ULONG_MAX    4294967295UL
196 +#    endif
197 +#  endif
198 +#endif
199 +
200 +#endif  /* __PJ_COMPAT_LIMITS_H__ */
201 diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h
202 index 4fa8b21ea..9b18e4eb1 100644
203 --- a/pjlib/include/pj/compat/os_win32.h
204 +++ b/pjlib/include/pj/compat/os_win32.h
205 @@ -57,6 +57,7 @@
206  #define PJ_HAS_SYS_TYPES_H         1
207  #define PJ_HAS_TIME_H              1
208  #define PJ_HAS_UNISTD_H                    0
209 +#define PJ_HAS_LIMITS_H                    1
210  
211  #define PJ_HAS_MSWSOCK_H           1
212  #define PJ_HAS_WINSOCK_H           0
213 diff --git a/pjlib/include/pj/limits.h b/pjlib/include/pj/limits.h
214 new file mode 100644
215 index 000000000..8b00ae52a
216 --- /dev/null
217 +++ b/pjlib/include/pj/limits.h
218 @@ -0,0 +1,51 @@
219 +/* $Id$ */
220 +/*
221 + * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
222 + * Copyright (C) 2017 George Joseph <gjoseph@digium.com>
223 + *
224 + * This program is free software; you can redistribute it and/or modify
225 + * it under the terms of the GNU General Public License as published by
226 + * the Free Software Foundation; either version 2 of the License, or
227 + * (at your option) any later version.
228 + *
229 + * This program is distributed in the hope that it will be useful,
230 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
231 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
232 + * GNU General Public License for more details.
233 + *
234 + * You should have received a copy of the GNU General Public License
235 + * along with this program; if not, write to the Free Software
236 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
237 + */
238 +#ifndef __PJ_LIMITS_H__
239 +#define __PJ_LIMITS_H__
240 +
241 +/**
242 + * @file limits.h
243 + * @brief Common min and max values
244 + */
245 +
246 +#include <pj/compat/limits.h>
247 +
248 +/** Maximum value for signed 32-bit integer. */
249 +#define PJ_MAXINT32    0x7fffffff
250 +
251 +/** Minimum value for signed 32-bit integer. */
252 +#define PJ_MININT32    0x80000000
253 +
254 +/** Maximum value for unsigned 16-bit integer. */
255 +#define PJ_MAXUINT16   0xffff
256 +
257 +/** Maximum value for unsigned char. */
258 +#define PJ_MAXUINT8    0xff
259 +
260 +/** Maximum value for long. */
261 +#define PJ_MAXLONG     LONG_MAX
262 +
263 +/** Minimum value for long. */
264 +#define PJ_MINLONG     LONG_MIN
265 +
266 +/** Minimum value for unsigned long. */
267 +#define PJ_MAXULONG    ULONG_MAX
268 +
269 +#endif  /* __PJ_LIMITS_H__ */
270 diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h
271 index 70a1d6c8c..5de236a65 100644
272 --- a/pjlib/include/pj/string.h
273 +++ b/pjlib/include/pj/string.h
274 @@ -28,7 +28,6 @@
275  #include <pj/types.h>
276  #include <pj/compat/string.h>
277  
278 -
279  PJ_BEGIN_DECL
280  
281  /**
282 @@ -636,6 +635,29 @@ PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);
283  PJ_DECL(long) pj_strtol(const pj_str_t *str);
284  
285  /**
286 + * Convert string to signed long integer. The conversion will stop as
287 + * soon as non-digit character is found or all the characters have
288 + * been processed.
289 + *
290 + * @param str   the string.
291 + * @param value Pointer to a long to receive the value.
292 + *
293 + * @return PJ_SUCCESS if successful.  Otherwise:
294 + *         PJ_ETOOSMALL if the value was an impossibly long negative number.
295 + *         In this case *value will be set to LONG_MIN.
296 + *         \n
297 + *         PJ_ETOOBIG if the value was an impossibly long positive number.
298 + *         In this case, *value will be set to LONG_MAX.
299 + *         \n
300 + *         PJ_EINVAL if the input string was NULL, the value pointer was NULL 
301 + *         or the input string could not be parsed at all such as starting with
302 + *         a character other than a '+', '-' or not in the '0' - '9' range.
303 + *         In this case, *value will be left untouched.
304 + */
305 +PJ_DECL(pj_status_t) pj_strtol2(const pj_str_t *str, long *value);
306 +
307 +
308 +/**
309   * Convert string to unsigned integer. The conversion will stop as
310   * soon as non-digit character is found or all the characters have
311   * been processed.
312 @@ -664,6 +686,27 @@ PJ_DECL(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr,
313                                    unsigned base);
314  
315  /**
316 + * Convert string to unsigned long integer. The conversion will stop as
317 + * soon as non-digit character is found or all the characters have
318 + * been processed.
319 + *
320 + * @param str       The input string.
321 + * @param value     Pointer to an unsigned long to receive the value.
322 + * @param base     Number base to use.
323 + *
324 + * @return PJ_SUCCESS if successful.  Otherwise:
325 + *         PJ_ETOOBIG if the value was an impossibly long positive number.
326 + *         In this case, *value will be set to ULONG_MAX.
327 + *         \n
328 + *         PJ_EINVAL if the input string was NULL, the value pointer was NULL 
329 + *         or the input string could not be parsed at all such as starting 
330 + *         with a character outside the base character range.  In this case,
331 + *         *value will be left untouched.
332 + */
333 +PJ_DECL(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value,
334 +                                unsigned base);
335 +
336 +/**
337   * Convert string to float.
338   *
339   * @param str  the string.
340 @@ -786,7 +829,6 @@ PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)
341      return (void*)memchr((void*)buf, c, size);
342  }
343  
344 -
345  /**
346   * @}
347   */
348 diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h
349 index 0e0e2d9a7..8c9f78238 100644
350 --- a/pjlib/include/pj/types.h
351 +++ b/pjlib/include/pj/types.h
352 @@ -280,9 +280,6 @@ typedef int pj_exception_id_t;
353  /** Utility macro to compute the number of elements in static array. */
354  #define PJ_ARRAY_SIZE(a)    (sizeof(a)/sizeof(a[0]))
355  
356 -/** Maximum value for signed 32-bit integer. */
357 -#define PJ_MAXINT32  0x7FFFFFFFL
358 -
359  /**
360   * Length of object names.
361   */
362 diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c
363 index 307cfb47e..b95f141be 100644
364 --- a/pjlib/src/pj/string.c
365 +++ b/pjlib/src/pj/string.c
366 @@ -23,11 +23,14 @@
367  #include <pj/ctype.h>
368  #include <pj/rand.h>
369  #include <pj/os.h>
370 +#include <pj/errno.h>
371 +#include <pj/limits.h>
372  
373  #if PJ_FUNCTIONS_ARE_INLINED==0
374  #  include <pj/string_i.h>
375  #endif
376  
377 +
378  PJ_DEF(pj_ssize_t) pj_strspn(const pj_str_t *str, const pj_str_t *set_char)
379  {
380      pj_ssize_t i, j, count = 0;
381 @@ -230,6 +233,55 @@ PJ_DEF(long) pj_strtol(const pj_str_t *str)
382          return pj_strtoul(str);
383  }
384  
385 +
386 +PJ_DEF(pj_status_t) pj_strtol2(const pj_str_t *str, long *value)
387 +{
388 +    pj_str_t s;
389 +    unsigned long retval = 0;
390 +    pj_bool_t is_negative = PJ_FALSE;
391 +    int rc = 0;
392 +
393 +    PJ_CHECK_STACK();
394 +
395 +    if (!str || !value) {
396 +        return PJ_EINVAL;
397 +    }
398 +
399 +    s = *str;
400 +    pj_strltrim(&s);
401 +
402 +    if (s.slen == 0)
403 +        return PJ_EINVAL;
404 +
405 +    if (s.ptr[0] == '+' || s.ptr[0] == '-') {
406 +        is_negative = (s.ptr[0] == '-');
407 +        s.ptr += 1;
408 +        s.slen -= 1;
409 +    }
410 +
411 +    rc = pj_strtoul3(&s, &retval, 10);
412 +    if (rc == PJ_EINVAL) {
413 +        return rc;
414 +    } else if (rc != PJ_SUCCESS) {
415 +        *value = is_negative ? PJ_MINLONG : PJ_MAXLONG;
416 +        return is_negative ? PJ_ETOOSMALL : PJ_ETOOBIG;
417 +    }
418 +
419 +    if (retval > PJ_MAXLONG && !is_negative) {
420 +        *value = PJ_MAXLONG;
421 +        return PJ_ETOOBIG;
422 +    }
423 +
424 +    if (retval > (PJ_MAXLONG + 1UL) && is_negative) {
425 +        *value = PJ_MINLONG;
426 +        return PJ_ETOOSMALL;
427 +    }
428 +
429 +    *value = is_negative ? -(long)retval : retval;
430 +
431 +    return PJ_SUCCESS;
432 +}
433 +
434  PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
435  {
436      unsigned long value;
437 @@ -282,6 +334,71 @@ PJ_DEF(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr,
438      return value;
439  }
440  
441 +PJ_DEF(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value,
442 +                               unsigned base)
443 +{
444 +    pj_str_t s;
445 +    unsigned i;
446 +
447 +    PJ_CHECK_STACK();
448 +
449 +    if (!str || !value) {
450 +        return PJ_EINVAL;
451 +    }
452 +
453 +    s = *str;
454 +    pj_strltrim(&s);
455 +
456 +    if (s.slen == 0 || s.ptr[0] < '0' ||
457 +       (base <= 10 && (unsigned)s.ptr[0] > ('0' - 1) + base) ||
458 +       (base == 16 && !pj_isxdigit(s.ptr[0])))
459 +    {
460 +        return PJ_EINVAL;
461 +    }
462 +
463 +    *value = 0;
464 +    if (base <= 10) {
465 +       for (i=0; i<(unsigned)s.slen; ++i) {
466 +           unsigned c = s.ptr[i] - '0';
467 +           if (s.ptr[i] < '0' || (unsigned)s.ptr[i] > ('0' - 1) + base) {
468 +               break;
469 +           }
470 +           if (*value > PJ_MAXULONG / base) {
471 +               *value = PJ_MAXULONG;
472 +               return PJ_ETOOBIG;
473 +           }
474 +
475 +           *value *= base;
476 +           if ((PJ_MAXULONG - *value) < c) {
477 +               *value = PJ_MAXULONG;
478 +               return PJ_ETOOBIG;
479 +           }
480 +           *value += c;
481 +       }
482 +    } else if (base == 16) {
483 +       for (i=0; i<(unsigned)s.slen; ++i) {
484 +           unsigned c = pj_hex_digit_to_val(s.ptr[i]);
485 +           if (!pj_isxdigit(s.ptr[i]))
486 +               break;
487 +
488 +           if (*value > PJ_MAXULONG / base) {
489 +               *value = PJ_MAXULONG;
490 +               return PJ_ETOOBIG;
491 +           }
492 +           *value *= base;
493 +           if ((PJ_MAXULONG - *value) < c) {
494 +               *value = PJ_MAXULONG;
495 +               return PJ_ETOOBIG;
496 +           }
497 +           *value += c;
498 +       }
499 +    } else {
500 +       pj_assert(!"Unsupported base");
501 +       return PJ_EINVAL;
502 +    }
503 +    return PJ_SUCCESS;
504 +}
505 +
506  PJ_DEF(float) pj_strtof(const pj_str_t *str)
507  {
508      pj_str_t part;
509 @@ -356,5 +473,3 @@ PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
510  
511      return len;
512  }
513 -
514 -
515 diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
516 index 225be4498..399e114a8 100644
517 --- a/pjlib/src/pj/timer.c
518 +++ b/pjlib/src/pj/timer.c
519 @@ -36,6 +36,7 @@
520  #include <pj/lock.h>
521  #include <pj/log.h>
522  #include <pj/rand.h>
523 +#include <pj/limits.h>
524  
525  #define THIS_FILE      "timer.c"
526  
527 diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h
528 index 0d767f0ad..5691fed3a 100644
529 --- a/pjsip/include/pjsip/sip_parser.h
530 +++ b/pjsip/include/pjsip/sip_parser.h
531 @@ -39,6 +39,26 @@ PJ_BEGIN_DECL
532   */
533  
534  /**
535 + * Contants for limit checks
536 + */
537 +#define PJSIP_MIN_CONTENT_LENGTH    0
538 +#define PJSIP_MAX_CONTENT_LENGTH    PJ_MAXINT32
539 +#define PJSIP_MIN_PORT             0
540 +#define PJSIP_MAX_PORT             PJ_MAXUINT16
541 +#define PJSIP_MIN_TTL              0
542 +#define PJSIP_MAX_TTL              PJ_MAXUINT8
543 +#define PJSIP_MIN_STATUS_CODE      100
544 +#define PJSIP_MAX_STATUS_CODE      999
545 +#define PJSIP_MIN_Q1000                    0
546 +#define PJSIP_MAX_Q1000                    PJ_MAXINT32 / 1000
547 +#define PJSIP_MIN_EXPIRES          0
548 +#define PJSIP_MAX_EXPIRES          PJ_MAXINT32
549 +#define PJSIP_MIN_CSEQ             0
550 +#define PJSIP_MAX_CSEQ             PJ_MAXINT32
551 +#define PJSIP_MIN_RETRY_AFTER      0
552 +#define PJSIP_MAX_RETRY_AFTER      PJ_MAXINT32
553 +
554 +/**
555   * URI Parsing options.
556   */
557  enum
558 @@ -64,6 +84,11 @@ enum
559  extern int PJSIP_SYN_ERR_EXCEPTION;
560  
561  /**
562 + * Invalid value error exception value.
563 + */
564 +extern int PJSIP_EINVAL_ERR_EXCEPTION;
565 +
566 +/**
567   * This structure is used to get error reporting from parser.
568   */
569  typedef struct pjsip_parser_err_report
570 diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
571 index cf3b879f6..f9a0e65b5 100644
572 --- a/pjsip/src/pjsip/sip_parser.c
573 +++ b/pjsip/src/pjsip/sip_parser.c
574 @@ -34,6 +34,7 @@
575  #include <pj/string.h>
576  #include <pj/ctype.h>
577  #include <pj/assert.h>
578 +#include <pj/limits.h>
579  
580  #define THIS_FILE          "sip_parser.c"
581  
582 @@ -93,6 +94,7 @@ static unsigned uri_handler_count;
583   * Global vars (also extern).
584   */
585  int PJSIP_SYN_ERR_EXCEPTION = -1;
586 +int PJSIP_EINVAL_ERR_EXCEPTION = -2;
587  
588  /* Parser constants */
589  static pjsip_parser_const_t pconst =
590 @@ -205,7 +207,6 @@ static unsigned long pj_strtoul_mindigit(const pj_str_t *str,
591  /* Case insensitive comparison */
592  #define parser_stricmp(s1, s2)  (s1.slen!=s2.slen || pj_stricmp_alnum(&s1, &s2))
593  
594 -
595  /* Get a token and unescape */
596  PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool,
597                                         const pj_cis_t *spec, 
598 @@ -223,8 +224,6 @@ PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool,
599  #endif
600  }
601  
602 -
603 -
604  /* Syntax error handler for parser. */
605  static void on_syntax_error(pj_scanner *scanner)
606  {
607 @@ -232,6 +231,60 @@ static void on_syntax_error(pj_scanner *scanner)
608      PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
609  }
610  
611 +/* Syntax error handler for parser. */
612 +static void on_str_parse_error(const pj_str_t *str, int rc)
613 +{
614 +    char *s;
615 +
616 +    switch(rc) {
617 +    case PJ_EINVAL:
618 +        s = "NULL input string, invalid input string, or NULL return "\
619 +           "value pointer";
620 +        break;
621 +    case PJ_ETOOSMALL:
622 +        s = "String value was less than the minimum allowed value.";
623 +        break;
624 +    case PJ_ETOOBIG:
625 +        s = "String value was greater than the maximum allowed value.";
626 +        break;
627 +    default:
628 +        s = "Unknown error";
629 +    }
630 +
631 +    if (str) {
632 +        PJ_LOG(1, (THIS_FILE, "Error parsing '%.*s': %s",
633 +                   (int)str->slen, str->ptr, s));
634 +    } else {
635 +        PJ_LOG(1, (THIS_FILE, "Can't parse input string: %s", s));
636 +    }
637 +    PJ_THROW(PJSIP_EINVAL_ERR_EXCEPTION);
638 +}
639 +
640 +static void strtoi_validate(const pj_str_t *str, int min_val,
641 +                           int max_val, int *value)
642 +{ 
643 +    long retval;
644 +    pj_status_t status;
645 +
646 +    if (!str || !value) {
647 +        on_str_parse_error(str, PJ_EINVAL);
648 +    }
649 +    status = pj_strtol2(str, &retval);
650 +    if (status != PJ_EINVAL) {
651 +       if (min_val > retval) {
652 +           *value = min_val;
653 +           status = PJ_ETOOSMALL;
654 +       } else if (retval > max_val) {
655 +           *value = max_val;
656 +           status = PJ_ETOOBIG;
657 +       } else
658 +           *value = (int)retval;
659 +    }
660 +
661 +    if (status != PJ_SUCCESS)
662 +       on_str_parse_error(str, status);
663 +}
664 +
665  /* Get parser constants. */
666  PJ_DEF(const pjsip_parser_const_t*) pjsip_parser_const(void)
667  {
668 @@ -285,6 +338,14 @@ static pj_status_t init_parser()
669      PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
670  
671      /*
672 +     * Invalid value exception.
673 +     */
674 +    pj_assert (PJSIP_EINVAL_ERR_EXCEPTION == -2);
675 +    status = pj_exception_id_alloc("PJSIP invalid value error", 
676 +                                  &PJSIP_EINVAL_ERR_EXCEPTION);
677 +    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
678 +
679 +    /*
680       * Init character input spec (cis)
681       */
682  
683 @@ -502,6 +563,9 @@ void deinit_sip_parser(void)
684         /* Deregister exception ID */
685         pj_exception_id_free(PJSIP_SYN_ERR_EXCEPTION);
686         PJSIP_SYN_ERR_EXCEPTION = -1;
687 +
688 +       pj_exception_id_free(PJSIP_EINVAL_ERR_EXCEPTION);
689 +       PJSIP_EINVAL_ERR_EXCEPTION = -2;
690      }
691      pj_leave_critical_section();
692  }
693 @@ -766,7 +830,7 @@ PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,
694  }
695  
696  /* Determine if a message has been received. */
697 -PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, 
698 +PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size, 
699                                   pj_bool_t is_datagram, pj_size_t *msg_size)
700  {
701  #if PJ_HAS_TCP
702 @@ -776,6 +840,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
703      const char *line;
704      int content_length = -1;
705      pj_str_t cur_msg;
706 +    pj_status_t status = PJ_SUCCESS;
707      const pj_str_t end_hdr = { "\n\r\n", 3};
708  
709      *msg_size = size;
710 @@ -836,9 +901,16 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
711                 pj_scan_get_newline(&scanner);
712  
713                 /* Found a valid Content-Length header. */
714 -               content_length = pj_strtoul(&str_clen);
715 +               strtoi_validate(&str_clen, PJSIP_MIN_CONTENT_LENGTH,
716 +                               PJSIP_MAX_CONTENT_LENGTH, &content_length);
717             }
718             PJ_CATCH_ANY {
719 +               int eid = PJ_GET_EXCEPTION();
720 +               if (eid == PJSIP_SYN_ERR_EXCEPTION) {
721 +                   status = PJSIP_EMISSINGHDR;
722 +               } else if (eid == PJSIP_EINVAL_ERR_EXCEPTION) {
723 +                   status = PJSIP_EINVALIDHDR;
724 +               }
725                 content_length = -1;
726             }
727             PJ_END
728 @@ -858,7 +930,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
729  
730      /* Found Content-Length? */
731      if (content_length == -1) {
732 -       return PJSIP_EMISSINGHDR;
733 +       return status;
734      }
735  
736      /* Enough packet received? */
737 @@ -938,10 +1010,14 @@ static pj_bool_t is_next_sip_version(pj_scanner *scanner)
738  static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,
739                                  pjsip_parser_err_report *err_list)
740  {
741 -    pj_bool_t parsing_headers;
742 -    pjsip_msg *msg = NULL;
743 +    /* These variables require "volatile" so their values get
744 +     * preserved when re-entering the PJ_TRY block after an error.
745 +     */
746 +    volatile pj_bool_t parsing_headers;
747 +    pjsip_msg *volatile msg = NULL;
748 +    pjsip_ctype_hdr *volatile ctype_hdr = NULL;
749 +
750      pj_str_t hname;
751 -    pjsip_ctype_hdr *ctype_hdr = NULL;
752      pj_scanner *scanner = ctx->scanner;
753      pj_pool_t *pool = ctx->pool;
754      PJ_USE_EXCEPTION;
755 @@ -1023,7 +1099,6 @@ parse_headers:
756                 hdr->name = hdr->sname = hname;
757             }
758             
759 -       
760             /* Single parse of header line can produce multiple headers.
761              * For example, if one Contact: header contains Contact list
762              * separated by comma, then these Contacts will be split into
763 @@ -1267,7 +1342,7 @@ static void int_parse_uri_host_port( pj_scanner *scanner,
764         pj_str_t port;
765         pj_scan_get_char(scanner);
766         pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &port);
767 -       *p_port = pj_strtoul(&port);
768 +       strtoi_validate(&port, PJSIP_MIN_PORT, PJSIP_MAX_PORT, p_port);
769      } else {
770         *p_port = 0;
771      }
772 @@ -1458,8 +1533,8 @@ static void* int_parse_sip_url( pj_scanner *scanner,
773             url->transport_param = pvalue;
774  
775         } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) {
776 -           url->ttl_param = pj_strtoul(&pvalue);
777 -
778 +           strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL,
779 +                           &url->ttl_param);
780         } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) {
781             url->maddr_param = pvalue;
782  
783 @@ -1595,7 +1670,8 @@ static void int_parse_status_line( pj_scanner *scanner,
784  
785      parse_sip_version(scanner);
786      pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token);
787 -    status_line->code = pj_strtoul(&token);
788 +    strtoi_validate(&token, PJSIP_MIN_STATUS_CODE, PJSIP_MAX_STATUS_CODE,
789 +                    &status_line->code);
790      if (*scanner->curptr != '\r' && *scanner->curptr != '\n')
791         pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &status_line->reason);
792      else
793 @@ -1780,20 +1856,34 @@ static void int_parse_contact_param( pjsip_contact_hdr *hdr,
794         if (!parser_stricmp(pname, pconst.pjsip_Q_STR) && pvalue.slen) {
795             char *dot_pos = (char*) pj_memchr(pvalue.ptr, '.', pvalue.slen);
796             if (!dot_pos) {
797 -               hdr->q1000 = pj_strtoul(&pvalue) * 1000;
798 +               strtoi_validate(&pvalue, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000,
799 +                                &hdr->q1000);
800 +               hdr->q1000 *= 1000;
801             } else {
802                 pj_str_t tmp = pvalue;
803 +               unsigned long qval_frac;
804  
805                 tmp.slen = dot_pos - pvalue.ptr;
806 -               hdr->q1000 = pj_strtoul(&tmp) * 1000;
807 +               strtoi_validate(&tmp, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000,
808 +                                &hdr->q1000);
809 +                hdr->q1000 *= 1000;
810  
811                 pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1);
812                 pvalue.ptr = dot_pos + 1;
813 -               hdr->q1000 += pj_strtoul_mindigit(&pvalue, 3);
814 +               if (pvalue.slen > 3) {
815 +                   pvalue.slen = 3;
816 +               }
817 +               qval_frac = pj_strtoul_mindigit(&pvalue, 3);
818 +               if ((unsigned)hdr->q1000 > (PJ_MAXINT32 - qval_frac)) {
819 +                   PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
820 +               }
821 +               hdr->q1000 += qval_frac;
822             }    
823 -       } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && pvalue.slen) {
824 -           hdr->expires = pj_strtoul(&pvalue);
825 -
826 +       } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && 
827 +                   pvalue.slen) 
828 +        {
829 +           strtoi_validate(&pvalue, PJSIP_MIN_EXPIRES, PJSIP_MAX_EXPIRES,
830 +                            &hdr->expires);
831         } else {
832             pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
833             p->name = pname;
834 @@ -1890,19 +1980,22 @@ static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx )
835  static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
836  {
837      pj_str_t cseq, method;
838 -    pjsip_cseq_hdr *hdr;
839 +    pjsip_cseq_hdr *hdr = NULL;
840 +    int cseq_val = 0;
841  
842 -    hdr = pjsip_cseq_hdr_create(ctx->pool);
843      pj_scan_get( ctx->scanner, &pconst.pjsip_DIGIT_SPEC, &cseq);
844 -    hdr->cseq = pj_strtoul(&cseq);
845 +    strtoi_validate(&cseq, PJSIP_MIN_CSEQ, PJSIP_MAX_CSEQ, &cseq_val);
846  
847 -    pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method);
848 -    pjsip_method_init_np(&hdr->method, &method);
849 +    hdr = pjsip_cseq_hdr_create(ctx->pool);
850 +    hdr->cseq = cseq_val;
851  
852 +    pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method);
853      parse_hdr_end( ctx->scanner );
854  
855 -    if (ctx->rdata)
856 +    pjsip_method_init_np(&hdr->method, &method);
857 +    if (ctx->rdata) {
858          ctx->rdata->msg_info.cseq = hdr;
859 +    }
860  
861      return (pjsip_hdr*)hdr;
862  }
863 @@ -1984,7 +2077,8 @@ static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)
864      hdr = pjsip_retry_after_hdr_create(ctx->pool, 0);
865      
866      pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &tmp);
867 -    hdr->ivalue = pj_strtoul(&tmp);
868 +    strtoi_validate(&tmp, PJSIP_MIN_RETRY_AFTER, PJSIP_MAX_RETRY_AFTER,
869 +                    &hdr->ivalue);
870  
871      while (!pj_scan_is_eof(scanner) && *scanner->curptr!='\r' &&
872            *scanner->curptr!='\n')
873 @@ -2073,7 +2167,8 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
874             hdr->branch_param = pvalue;
875  
876         } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) {
877 -           hdr->ttl_param = pj_strtoul(&pvalue);
878 +           strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL,
879 +                            &hdr->ttl_param);
880             
881         } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) {
882             hdr->maddr_param = pvalue;
883 @@ -2082,9 +2177,10 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
884             hdr->recvd_param = pvalue;
885  
886         } else if (!parser_stricmp(pname, pconst.pjsip_RPORT_STR)) {
887 -           if (pvalue.slen)
888 -               hdr->rport_param = pj_strtoul(&pvalue);
889 -           else
890 +           if (pvalue.slen) {
891 +               strtoi_validate(&pvalue, PJSIP_MIN_PORT, PJSIP_MAX_PORT,
892 +                               &hdr->rport_param);
893 +            } else
894                 hdr->rport_param = 0;
895         } else {
896             pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
897 @@ -2213,7 +2309,8 @@ static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx )
898             pj_str_t digit;
899             pj_scan_get_char(scanner);
900             pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &digit);
901 -           hdr->sent_by.port = pj_strtoul(&digit);
902 +           strtoi_validate(&digit, PJSIP_MIN_PORT, PJSIP_MAX_PORT,
903 +                            &hdr->sent_by.port);
904         }
905         
906         int_parse_via_param(hdr, scanner, ctx->pool);
907 @@ -2298,9 +2395,10 @@ PJ_DEF(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, char *input,
908                                          unsigned options)
909  {
910      enum { STOP_ON_ERROR = 1 };
911 +    pj_str_t hname;
912      pj_scanner scanner;
913      pjsip_parse_ctx ctx;
914 -    pj_str_t hname;
915 +
916      PJ_USE_EXCEPTION;
917  
918      pj_scan_init(&scanner, input, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
919 @@ -2323,7 +2421,7 @@ retry_parse:
920              */
921             hname.slen = 0;
922  
923 -           /* Get hname. */
924 +           /* Get hname. */            
925             pj_scan_get( &scanner, &pconst.pjsip_TOKEN_SPEC, &hname);
926             if (pj_scan_get_char( &scanner ) != ':') {
927                 PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
928 diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
929 index f3be93beb..7ac3d1b76 100644
930 --- a/pjsip/src/pjsip/sip_transaction.c
931 +++ b/pjsip/src/pjsip/sip_transaction.c
932 @@ -289,11 +289,11 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
933  
934      /* Calculate length required. */
935      len_required = method->name.slen +      /* Method */
936 -                   9 +                     /* CSeq number */
937 +                   11 +                            /* CSeq number */
938                    rdata->msg_info.from->tag.slen +   /* From tag. */
939                    rdata->msg_info.cid->id.slen +    /* Call-ID */
940                    host->slen +             /* Via host. */
941 -                  9 +                      /* Via port. */
942 +                  11 +                     /* Via port. */
943                    16;                      /* Separator+Allowance. */
944      key = p = (char*) pj_pool_alloc(pool, len_required);
945  
946 diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
947 index 0c338e8fd..b24cbb411 100644
948 --- a/pjsip/src/pjsip/sip_transport.c
949 +++ b/pjsip/src/pjsip/sip_transport.c
950 @@ -1848,7 +1848,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
951         /* Check for parsing syntax error */
952         if (msg==NULL || !pj_list_empty(&rdata->msg_info.parse_err)) {
953             pjsip_parser_err_report *err;
954 -           char buf[128];
955 +           char buf[256];
956             pj_str_t tmp;
957  
958             /* Gather syntax error information */
959 @@ -1862,7 +1862,10 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
960                                        pj_exception_id_name(err->except_code),
961                                        (int)err->hname.slen, err->hname.ptr,
962                                        err->line, err->col);
963 -               if (len > 0 && len < (int) (sizeof(buf)-tmp.slen)) {
964 +               if (len >= (int)sizeof(buf)-tmp.slen) {
965 +                   len = (int)sizeof(buf)-tmp.slen;
966 +               }
967 +               if (len > 0) {
968                     tmp.slen += len;
969                 }
970                 err = err->next;
971 -- 
972 2.13.6
973