diff options
-rw-r--r-- | bridges/bridge_softmix.c | 2 | ||||
-rw-r--r-- | main/cdr.c | 6 | ||||
-rw-r--r-- | main/stream.c | 3 | ||||
-rw-r--r-- | res/res_pjproject.c | 2 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 5 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 2 | ||||
-rw-r--r-- | res/res_pjsip_exten_state.c | 7 | ||||
-rw-r--r-- | res/res_pjsip_history.c | 30 | ||||
-rw-r--r-- | res/res_pjsip_outbound_registration.c | 6 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 119 | ||||
-rw-r--r-- | res/res_pjsip_t38.c | 13 | ||||
-rw-r--r-- | res/stasis/app.c | 9 | ||||
-rw-r--r-- | res/stasis/messaging.c | 12 | ||||
-rw-r--r-- | third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch | 973 |
14 files changed, 1120 insertions, 69 deletions
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c index f490967e2..8de88f257 100644 --- a/bridges/bridge_softmix.c +++ b/bridges/bridge_softmix.c @@ -541,6 +541,8 @@ static int append_all_streams(struct ast_stream_topology *dest, dest_index++; if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) { + /* This cannot fail because dest_index - 1 is less than the + * current count in dest. */ ast_stream_topology_set_stream(dest, dest_index - 1, clone); added = 1; break; diff --git a/main/cdr.c b/main/cdr.c index fdf764540..3681cdc6b 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -3407,7 +3407,8 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *da ast_assert(cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, info->channel_name)); - strcpy(cdr->party_b.userfield, info->userfield); + ast_copy_string(cdr->party_b.userfield, info->userfield, + sizeof(cdr->party_b.userfield)); } return 0; @@ -3430,7 +3431,8 @@ void ast_cdr_setuserfield(const char *channel_name, const char *userfield) if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) { continue; } - ast_copy_string(it_cdr->party_a.userfield, userfield, AST_MAX_USER_FIELD); + ast_copy_string(it_cdr->party_a.userfield, userfield, + sizeof(it_cdr->party_a.userfield)); } ao2_unlock(cdr); } diff --git a/main/stream.c b/main/stream.c index 72d859954..8597485f7 100644 --- a/main/stream.c +++ b/main/stream.c @@ -398,8 +398,7 @@ int ast_stream_topology_set_stream(struct ast_stream_topology *topology, stream->position = position; if (position == AST_VECTOR_SIZE(&topology->streams)) { - AST_VECTOR_APPEND(&topology->streams, stream); - return 0; + return AST_VECTOR_APPEND(&topology->streams, stream); } return AST_VECTOR_REPLACE(&topology->streams, position, stream); diff --git a/res/res_pjproject.c b/res/res_pjproject.c index 86b2502e5..6137898a3 100644 --- a/res/res_pjproject.c +++ b/res/res_pjproject.c @@ -234,7 +234,7 @@ static void capture_buildopts_cb(int level, const char *data, int len) } dup = ast_strdup(ast_skip_blanks(data)); - if (AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) { + if (dup && AST_VECTOR_ADD_SORTED(&buildopts, dup, strcmp)) { ast_free(dup); } } diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 9945c7c10..0d7b3da31 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1219,6 +1219,11 @@ static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object struct ast_sip_contact_status *status; struct ast_sip_contact *contact = object; + if (ast_strlen_zero(contact->uri)) { + ast_log(LOG_ERROR, "A URI on dynamic contact '%s' is empty\n", + ast_sorcery_object_get_id(contact)); + return -1; + } status = ast_res_pjsip_find_or_create_contact_status(contact); ao2_cleanup(status); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index a6afe5e53..168d86989 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -508,6 +508,8 @@ int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *valu goto failure; } if (AST_VECTOR_APPEND(auths, val)) { + ast_free(val); + goto failure; } } diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c index 95a40829e..3e756134c 100644 --- a/res/res_pjsip_exten_state.c +++ b/res/res_pjsip_exten_state.c @@ -729,8 +729,11 @@ static int exten_state_publisher_state_cb(const char *context, const char *exten } ao2_ref(publisher, +1); - AST_VECTOR_APPEND(&pub_data->pubs, publisher); - ast_debug(5, "'%s' will publish exten state\n", publisher->name); + if (AST_VECTOR_APPEND(&pub_data->pubs, publisher)) { + ao2_ref(publisher, -1); + } else { + ast_debug(5, "'%s' will publish exten state\n", publisher->name); + } } ao2_iterator_destroy(&publisher_iter); diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c index 4e7dbd007..ed374d605 100644 --- a/res/res_pjsip_history.c +++ b/res/res_pjsip_history.c @@ -705,10 +705,13 @@ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata) pj_sockaddr_cp(&entry->dst, &tdata->tp_info.dst_addr); ast_mutex_lock(&history_lock); - AST_VECTOR_APPEND(&vector_history, entry); + if (AST_VECTOR_APPEND(&vector_history, entry)) { + ao2_ref(entry, -1); + entry = NULL; + } ast_mutex_unlock(&history_lock); - if (log_level != -1) { + if (log_level != -1 && entry) { char line[256]; sprint_list_entry(entry, line, sizeof(line)); @@ -745,10 +748,13 @@ static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata) } ast_mutex_lock(&history_lock); - AST_VECTOR_APPEND(&vector_history, entry); + if (AST_VECTOR_APPEND(&vector_history, entry)) { + ao2_ref(entry, -1); + entry = NULL; + } ast_mutex_unlock(&history_lock); - if (log_level != -1) { + if (log_level != -1 && entry) { char line[256]; sprint_list_entry(entry, line, sizeof(line)); @@ -959,7 +965,9 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr /* If this is not an operator, push it to the stack */ if (!it_queue->op) { - AST_VECTOR_APPEND(&stack, it_queue); + if (AST_VECTOR_APPEND(&stack, it_queue)) { + goto error; + } continue; } @@ -1035,7 +1043,11 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr if (!result) { goto error; } - AST_VECTOR_APPEND(&stack, result); + if (AST_VECTOR_APPEND(&stack, result)) { + expression_token_free(result); + + goto error; + } } /* @@ -1056,6 +1068,7 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr } result = final->result; ast_free(final); + AST_VECTOR_FREE(&stack); return result; @@ -1098,6 +1111,7 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a) queue = build_expression_queue(a); if (!queue) { + AST_VECTOR_PTR_FREE(output); return NULL; } @@ -1118,7 +1132,9 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a) } else if (!res) { continue; } else { - AST_VECTOR_APPEND(output, ao2_bump(entry)); + if (AST_VECTOR_APPEND(output, ao2_bump(entry))) { + ao2_cleanup(entry); + } } } ast_mutex_unlock(&history_lock); diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index 7fa6e2c10..d9afcd284 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1385,10 +1385,10 @@ static int sip_outbound_registration_perform(void *data) AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(®istration->outbound_auths)); for (i = 0; i < AST_VECTOR_SIZE(®istration->outbound_auths); ++i) { - const char *name = ast_strdup(AST_VECTOR_GET(®istration->outbound_auths, i)); + char *name = ast_strdup(AST_VECTOR_GET(®istration->outbound_auths, i)); - if (name) { - AST_VECTOR_APPEND(&state->client_state->outbound_auths, name); + if (name && AST_VECTOR_APPEND(&state->client_state->outbound_auths, name)) { + ast_free(name); } } state->client_state->retry_interval = registration->retry_interval; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 4724d46ce..781d3e4eb 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -174,7 +174,8 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler * ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler); } -struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) +static struct ast_sip_session_media_state *internal_sip_session_media_state_alloc( + size_t sessions, size_t read_callbacks) { struct ast_sip_session_media_state *media_state; @@ -183,12 +184,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) return NULL; } - if (AST_VECTOR_INIT(&media_state->sessions, DEFAULT_NUM_SESSION_MEDIA) < 0) { + if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) { ast_free(media_state); return NULL; } - if (AST_VECTOR_INIT(&media_state->read_callbacks, DEFAULT_NUM_SESSION_MEDIA) < 0) { + if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) { AST_VECTOR_FREE(&media_state->sessions); ast_free(media_state); return NULL; @@ -197,6 +198,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) return media_state; } +struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void) +{ + return internal_sip_session_media_state_alloc( + DEFAULT_NUM_SESSION_MEDIA, DEFAULT_NUM_SESSION_MEDIA); +} + void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state) { int index; @@ -225,7 +232,9 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_clone(const stru return NULL; } - cloned = ast_sip_session_media_state_alloc(); + cloned = internal_sip_session_media_state_alloc( + AST_VECTOR_SIZE(&media_state->sessions), + AST_VECTOR_SIZE(&media_state->read_callbacks)); if (!cloned) { return NULL; } @@ -452,7 +461,11 @@ struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_ses } } - AST_VECTOR_REPLACE(&media_state->sessions, position, session_media); + if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) { + ao2_ref(session_media, -1); + + return NULL; + } /* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */ if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) { @@ -678,7 +691,10 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd if (!stream) { return -1; } - ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) { + ast_stream_free(stream); + return -1; + } } session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); @@ -1588,7 +1604,11 @@ int ast_sip_session_refresh(struct ast_sip_session *session, } ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED); - ast_stream_topology_append_stream(media_state->topology, cloned); + if (ast_stream_topology_append_stream(media_state->topology, cloned) < 0) { + ast_stream_free(cloned); + ast_sip_session_media_state_free(media_state); + return -1; + } } /* If the resulting media state matches the existing active state don't bother doing a session refresh */ @@ -1745,7 +1765,10 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_ /* As this is only called on an incoming SDP offer before processing it is not possible * for streams and their media sessions to exist. */ - ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream); + if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) { + ast_stream_free(stream); + return -1; + } session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i); if (!session_media) { @@ -3459,6 +3482,36 @@ static void session_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e) /* XXX STUB */ } +static int session_end_if_disconnected(int id, pjsip_inv_session *inv) +{ + struct ast_sip_session *session; + + if (inv->state != PJSIP_INV_STATE_DISCONNECTED) { + return 0; + } + + /* + * We are locking because ast_sip_dialog_get_session() needs + * the dialog locked to get the session by other threads. + */ + pjsip_dlg_inc_lock(inv->dlg); + session = inv->mod_data[id]; + inv->mod_data[id] = NULL; + pjsip_dlg_dec_lock(inv->dlg); + + /* + * Pass the session ref held by session->inv_session to + * session_end_completion(). + */ + if (session + && ast_sip_push_task(session->serializer, session_end_completion, session)) { + /* Do it anyway even though this is not the right thread. */ + session_end_completion(session); + } + + return 1; +} + static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) { ast_sip_session_response_cb cb; @@ -3483,6 +3536,17 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans /* The session has ended. Ignore the transaction change. */ return; } + + /* + * If the session is disconnected really nothing else to do unless currently transacting + * a BYE. If a BYE then hold off destruction until the transaction timeout occurs. This + * has to be done for BYEs because sometimes the dialog can be in a disconnected + * state but the BYE request transaction has not yet completed. + */ + if (tsx->method.id != PJSIP_BYE_METHOD && session_end_if_disconnected(id, inv)) { + return; + } + switch (e->body.tsx_state.type) { case PJSIP_EVENT_TX_MSG: /* When we create an outgoing request, we do not have access to the transaction that @@ -3605,49 +3669,12 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans } break; case PJSIP_EVENT_TRANSPORT_ERROR: - if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - /* - * Clear the module data now to block session_inv_on_state_changed() - * from calling session_end() if it hasn't already done so. - */ - inv->mod_data[id] = NULL; - - /* - * Pass the session ref held by session->inv_session to - * session_end_completion(). - */ - if (session - && ast_sip_push_task(session->serializer, session_end_completion, session)) { - /* Do it anyway even though this is not the right thread. */ - session_end_completion(session); - } - return; - } - break; case PJSIP_EVENT_TIMER: /* * The timer event is run by the pjsip monitor thread and not * by the session serializer. */ - if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - /* - * We are locking because ast_sip_dialog_get_session() needs - * the dialog locked to get the session by other threads. - */ - pjsip_dlg_inc_lock(inv->dlg); - session = inv->mod_data[id]; - inv->mod_data[id] = NULL; - pjsip_dlg_dec_lock(inv->dlg); - - /* - * Pass the session ref held by session->inv_session to - * session_end_completion(). - */ - if (session - && ast_sip_push_task(session->serializer, session_end_completion, session)) { - /* Do it anyway even though this is not the right thread. */ - session_end_completion(session); - } + if (session_end_if_disconnected(id, inv)) { return; } break; diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 48cbab37b..8f1905f6e 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -363,7 +363,11 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip } ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV); - ast_stream_topology_set_stream(media_state->topology, 0, stream); + if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) { + ast_stream_free(stream); + ast_sip_session_media_state_free(media_state); + return NULL; + } caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); if (!caps) { @@ -371,9 +375,14 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip return NULL; } - ast_format_cap_append(caps, ast_format_t38, 0); ast_stream_set_formats(stream, caps); + /* stream holds a reference to cap, release the local reference + * now so we don't have to deal with it in the error condition. */ ao2_ref(caps, -1); + if (ast_format_cap_append(caps, ast_format_t38, 0)) { + ast_sip_session_media_state_free(media_state); + return NULL; + } session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0); if (!session_media) { diff --git a/res/stasis/app.c b/res/stasis/app.c index 0b44bf3c6..a1ef5c0b6 100644 --- a/res/stasis/app.c +++ b/res/stasis/app.c @@ -588,6 +588,7 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js { RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup); struct ast_json *json_endpoint; + struct ast_json *message; struct stasis_app *app = pvt; char *tech; char *resource; @@ -613,11 +614,15 @@ static int message_received_handler(const char *endpoint_id, struct ast_json *js return -1; } - app_send(app, ast_json_pack("{s: s, s: o, s: o, s: o}", + message = ast_json_pack("{s: s, s: o, s: o, s: o}", "type", "TextMessageReceived", "timestamp", ast_json_timeval(ast_tvnow(), NULL), "endpoint", json_endpoint, - "message", ast_json_ref(json_msg))); + "message", ast_json_ref(json_msg)); + if (message) { + app_send(app, message); + ast_json_unref(message); + } return 0; } diff --git a/res/stasis/messaging.c b/res/stasis/messaging.c index d398bb6d4..77a58745a 100644 --- a/res/stasis/messaging.c +++ b/res/stasis/messaging.c @@ -457,7 +457,11 @@ static struct message_subscription *get_or_create_subscription(struct ast_endpoi ao2_link(endpoint_subscriptions, sub); } else { ast_rwlock_wrlock(&tech_subscriptions_lock); - AST_VECTOR_APPEND(&tech_subscriptions, ao2_bump(sub)); + if (AST_VECTOR_APPEND(&tech_subscriptions, ao2_bump(sub))) { + /* Release the ao2_bump that was for the vector and allocation references. */ + ao2_ref(sub, -2); + sub = NULL; + } ast_rwlock_unlock(&tech_subscriptions_lock); } @@ -485,7 +489,11 @@ int messaging_app_subscribe_endpoint(const char *app_name, struct ast_endpoint * ao2_unlock(sub); return -1; } - AST_VECTOR_APPEND(&sub->applications, tuple); + if (AST_VECTOR_APPEND(&sub->applications, tuple)) { + ao2_ref(tuple, -1); + ao2_unlock(sub); + return -1; + } ao2_unlock(sub); ast_debug(3, "App '%s' subscribed to messages from endpoint '%s'\n", app_name, endpoint ? ast_endpoint_get_id(endpoint) : "-- ALL --"); diff --git a/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch b/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch new file mode 100644 index 000000000..dfee4b2c2 --- /dev/null +++ b/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch @@ -0,0 +1,973 @@ +From b21042956dc4d3526052d5030953e5c565bb0895 Mon Sep 17 00:00:00 2001 +From: George Joseph <gjoseph@digium.com> +Date: Thu, 2 Nov 2017 08:23:00 -0600 +Subject: [PATCH] sip_parser: Add validity checking for numeric header values + +Parsing the numeric header fields like cseq, ttl, port, etc. all +had the potential to overflow, either causing unintended values to +be captured or, if the values were subsequently converted back to +strings, a buffer overrun. To address this, new "strto" functions +have been created that do range checking and those functions are +used wherever possible in the parser. + + * Created pjlib/include/limits.h and pjlib/include/compat/limits.h + to either include the system limits.h or define common numeric + limits if there is no system limits.h. + + * Created strto*_validate functions in sip_parser that take bounds + and on failure call the on_str_parse_error function which prints + an error message and calls PJ_THROW. + + * Updated sip_parser to validate the numeric fields. + + * Fixed an issue in sip_transport that prevented error messages + from being properly displayed. + + * Added "volatile" to some variables referenced in PJ_CATCH blocks + as the optimizer was sometimes optimizing them away. + + * Fixed length calculation in sip_transaction/create_tsx_key_2543 + to account for signed ints being 11 characters, not 9. + +Reported by: Youngsung Kim at LINE Corporation +--- + pjlib/build/pjlib.vcproj | 14 +++- + pjlib/build/pjlib.vcxproj | 4 +- + pjlib/build/pjlib.vcxproj.filters | 6 ++ + pjlib/include/pj/compat/limits.h | 65 +++++++++++++++ + pjlib/include/pj/compat/os_win32.h | 1 + + pjlib/include/pj/limits.h | 51 ++++++++++++ + pjlib/include/pj/string.h | 46 +++++++++- + pjlib/include/pj/types.h | 3 - + pjlib/src/pj/string.c | 119 +++++++++++++++++++++++++- + pjlib/src/pj/timer.c | 1 + + pjsip/include/pjsip/sip_parser.h | 25 ++++++ + pjsip/src/pjsip/sip_parser.c | 166 +++++++++++++++++++++++++++++-------- + pjsip/src/pjsip/sip_transaction.c | 4 +- + pjsip/src/pjsip/sip_transport.c | 7 +- + 14 files changed, 463 insertions(+), 49 deletions(-) + create mode 100644 pjlib/include/pj/compat/limits.h + create mode 100644 pjlib/include/pj/limits.h + +diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj +index 6a217a0b7..12592ef94 100644 +--- a/pjlib/build/pjlib.vcproj ++++ b/pjlib/build/pjlib.vcproj +@@ -14967,7 +14967,11 @@ + </File>
+ <File
+ RelativePath="..\include\pj\ip_helper.h"
+- >
++ > ++ </File> ++ <File ++ RelativePath="..\include\pj\limits.h" ++ > + </File>
+ <File
+ RelativePath="..\include\pj\list.h"
+@@ -15070,8 +15074,12 @@ + </File>
+ <File
+ RelativePath="..\include\pj\compat\high_precision.h"
+- >
+- </File>
++ > ++ </File> ++ <File ++ RelativePath="..\include\pj\compat\limits.h" ++ > ++ </File> + <File
+ RelativePath="..\include\pj\compat\m_alpha.h"
+ >
+diff --git a/pjlib/build/pjlib.vcxproj b/pjlib/build/pjlib.vcxproj +index abf09ec44..e41731e3c 100644 +--- a/pjlib/build/pjlib.vcxproj ++++ b/pjlib/build/pjlib.vcxproj +@@ -494,7 +494,7 @@ + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> + </ClCompile> +- <ClCompile Include="..\src\pj\file_io_win32.c" /> ++ <ClCompile Include="..\src\pj\file_io_win32.c" /> + <ClCompile Include="..\src\pj\guid.c" /> + <ClCompile Include="..\src\pj\guid_simple.c"> + <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">true</ExcludedFromBuild> +@@ -890,6 +890,7 @@ + <ClInclude Include="..\include\pj\compat\ctype.h" /> + <ClInclude Include="..\include\pj\compat\errno.h" /> + <ClInclude Include="..\include\pj\compat\high_precision.h" /> ++ <ClInclude Include="..\include\pj\compat\limits.h" /> + <ClInclude Include="..\include\pj\compat\malloc.h" /> + <ClInclude Include="..\include\pj\compat\m_alpha.h" /> + <ClInclude Include="..\include\pj\compat\m_i386.h" /> +@@ -925,6 +926,7 @@ + <ClInclude Include="..\include\pj\hash.h" /> + <ClInclude Include="..\include\pj\ioqueue.h" /> + <ClInclude Include="..\include\pj\ip_helper.h" /> ++ <ClInclude Include="..\include\pj\limits.h" /> + <ClInclude Include="..\include\pj\list.h" /> + <ClInclude Include="..\include\pj\list_i.h" /> + <ClInclude Include="..\include\pj\lock.h" /> +diff --git a/pjlib/build/pjlib.vcxproj.filters b/pjlib/build/pjlib.vcxproj.filters +index 0b5cbf109..6f343b019 100644 +--- a/pjlib/build/pjlib.vcxproj.filters ++++ b/pjlib/build/pjlib.vcxproj.filters +@@ -439,5 +439,11 @@ + <ClInclude Include="..\include\pj\compat\os_winuwp.h"> + <Filter>Header Files\compat</Filter> + </ClInclude> ++ <ClInclude Include="..\include\pj\limits.h"> ++ <Filter>Header Files</Filter> ++ </ClInclude> ++ <ClInclude Include="..\include\pj\compat\limits.h"> ++ <Filter>Header Files\compat</Filter> ++ </ClInclude> + </ItemGroup> + </Project> +\ No newline at end of file +diff --git a/pjlib/include/pj/compat/limits.h b/pjlib/include/pj/compat/limits.h +new file mode 100644 +index 000000000..fba0625df +--- /dev/null ++++ b/pjlib/include/pj/compat/limits.h +@@ -0,0 +1,65 @@ ++/* $Id$ */ ++/* ++ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com) ++ * Copyright (C) 2017 George Joseph <gjoseph@digium.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __PJ_COMPAT_LIMITS_H__ ++#define __PJ_COMPAT_LIMITS_H__ ++ ++/** ++ * @file limits.h ++ * @brief Provides integer limits normally found in limits.h. ++ */ ++ ++#if defined(PJ_HAS_LIMITS_H) && PJ_HAS_LIMITS_H != 0 ++# include <limits.h> ++#else ++ ++# ifdef _MSC_VER ++# pragma message("limits.h is not found or not supported. LONG_MIN and "\ ++ "LONG_MAX will be defined by the library in "\ ++ "pj/compats/limits.h and overridable in config_site.h") ++# else ++# warning "limits.h is not found or not supported. LONG_MIN and LONG_MAX " \ ++ "will be defined by the library in pj/compats/limits.h and "\ ++ "overridable in config_site.h" ++# endif ++ ++/* Minimum and maximum values a `signed long int' can hold. */ ++# ifndef LONG_MAX ++# if __WORDSIZE == 64 ++# define LONG_MAX 9223372036854775807L ++# else ++# define LONG_MAX 2147483647L ++# endif ++# endif ++ ++# ifndef LONG_MIN ++# define LONG_MIN (-LONG_MAX - 1L) ++# endif ++ ++/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */ ++# ifndef ULONG_MAX ++# if __WORDSIZE == 64 ++# define ULONG_MAX 18446744073709551615UL ++# else ++# define ULONG_MAX 4294967295UL ++# endif ++# endif ++#endif ++ ++#endif /* __PJ_COMPAT_LIMITS_H__ */ +diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h +index 4fa8b21ea..9b18e4eb1 100644 +--- a/pjlib/include/pj/compat/os_win32.h ++++ b/pjlib/include/pj/compat/os_win32.h +@@ -57,6 +57,7 @@ + #define PJ_HAS_SYS_TYPES_H 1 + #define PJ_HAS_TIME_H 1 + #define PJ_HAS_UNISTD_H 0 ++#define PJ_HAS_LIMITS_H 1 + + #define PJ_HAS_MSWSOCK_H 1 + #define PJ_HAS_WINSOCK_H 0 +diff --git a/pjlib/include/pj/limits.h b/pjlib/include/pj/limits.h +new file mode 100644 +index 000000000..8b00ae52a +--- /dev/null ++++ b/pjlib/include/pj/limits.h +@@ -0,0 +1,51 @@ ++/* $Id$ */ ++/* ++ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com) ++ * Copyright (C) 2017 George Joseph <gjoseph@digium.com> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef __PJ_LIMITS_H__ ++#define __PJ_LIMITS_H__ ++ ++/** ++ * @file limits.h ++ * @brief Common min and max values ++ */ ++ ++#include <pj/compat/limits.h> ++ ++/** Maximum value for signed 32-bit integer. */ ++#define PJ_MAXINT32 0x7fffffff ++ ++/** Minimum value for signed 32-bit integer. */ ++#define PJ_MININT32 0x80000000 ++ ++/** Maximum value for unsigned 16-bit integer. */ ++#define PJ_MAXUINT16 0xffff ++ ++/** Maximum value for unsigned char. */ ++#define PJ_MAXUINT8 0xff ++ ++/** Maximum value for long. */ ++#define PJ_MAXLONG LONG_MAX ++ ++/** Minimum value for long. */ ++#define PJ_MINLONG LONG_MIN ++ ++/** Minimum value for unsigned long. */ ++#define PJ_MAXULONG ULONG_MAX ++ ++#endif /* __PJ_LIMITS_H__ */ +diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h +index 70a1d6c8c..5de236a65 100644 +--- a/pjlib/include/pj/string.h ++++ b/pjlib/include/pj/string.h +@@ -28,7 +28,6 @@ + #include <pj/types.h> + #include <pj/compat/string.h> + +- + PJ_BEGIN_DECL + + /** +@@ -636,6 +635,29 @@ PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length); + PJ_DECL(long) pj_strtol(const pj_str_t *str); + + /** ++ * Convert string to signed long integer. The conversion will stop as ++ * soon as non-digit character is found or all the characters have ++ * been processed. ++ * ++ * @param str the string. ++ * @param value Pointer to a long to receive the value. ++ * ++ * @return PJ_SUCCESS if successful. Otherwise: ++ * PJ_ETOOSMALL if the value was an impossibly long negative number. ++ * In this case *value will be set to LONG_MIN. ++ * \n ++ * PJ_ETOOBIG if the value was an impossibly long positive number. ++ * In this case, *value will be set to LONG_MAX. ++ * \n ++ * PJ_EINVAL if the input string was NULL, the value pointer was NULL ++ * or the input string could not be parsed at all such as starting with ++ * a character other than a '+', '-' or not in the '0' - '9' range. ++ * In this case, *value will be left untouched. ++ */ ++PJ_DECL(pj_status_t) pj_strtol2(const pj_str_t *str, long *value); ++ ++ ++/** + * Convert string to unsigned integer. The conversion will stop as + * soon as non-digit character is found or all the characters have + * been processed. +@@ -664,6 +686,27 @@ PJ_DECL(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr, + unsigned base); + + /** ++ * Convert string to unsigned long integer. The conversion will stop as ++ * soon as non-digit character is found or all the characters have ++ * been processed. ++ * ++ * @param str The input string. ++ * @param value Pointer to an unsigned long to receive the value. ++ * @param base Number base to use. ++ * ++ * @return PJ_SUCCESS if successful. Otherwise: ++ * PJ_ETOOBIG if the value was an impossibly long positive number. ++ * In this case, *value will be set to ULONG_MAX. ++ * \n ++ * PJ_EINVAL if the input string was NULL, the value pointer was NULL ++ * or the input string could not be parsed at all such as starting ++ * with a character outside the base character range. In this case, ++ * *value will be left untouched. ++ */ ++PJ_DECL(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value, ++ unsigned base); ++ ++/** + * Convert string to float. + * + * @param str the string. +@@ -786,7 +829,6 @@ PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size) + return (void*)memchr((void*)buf, c, size); + } + +- + /** + * @} + */ +diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h +index 0e0e2d9a7..8c9f78238 100644 +--- a/pjlib/include/pj/types.h ++++ b/pjlib/include/pj/types.h +@@ -280,9 +280,6 @@ typedef int pj_exception_id_t; + /** Utility macro to compute the number of elements in static array. */ + #define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +-/** Maximum value for signed 32-bit integer. */ +-#define PJ_MAXINT32 0x7FFFFFFFL +- + /** + * Length of object names. + */ +diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c +index 307cfb47e..b95f141be 100644 +--- a/pjlib/src/pj/string.c ++++ b/pjlib/src/pj/string.c +@@ -23,11 +23,14 @@ + #include <pj/ctype.h> + #include <pj/rand.h> + #include <pj/os.h> ++#include <pj/errno.h> ++#include <pj/limits.h> + + #if PJ_FUNCTIONS_ARE_INLINED==0 + # include <pj/string_i.h> + #endif + ++ + PJ_DEF(pj_ssize_t) pj_strspn(const pj_str_t *str, const pj_str_t *set_char) + { + pj_ssize_t i, j, count = 0; +@@ -230,6 +233,55 @@ PJ_DEF(long) pj_strtol(const pj_str_t *str) + return pj_strtoul(str); + } + ++ ++PJ_DEF(pj_status_t) pj_strtol2(const pj_str_t *str, long *value) ++{ ++ pj_str_t s; ++ unsigned long retval = 0; ++ pj_bool_t is_negative = PJ_FALSE; ++ int rc = 0; ++ ++ PJ_CHECK_STACK(); ++ ++ if (!str || !value) { ++ return PJ_EINVAL; ++ } ++ ++ s = *str; ++ pj_strltrim(&s); ++ ++ if (s.slen == 0) ++ return PJ_EINVAL; ++ ++ if (s.ptr[0] == '+' || s.ptr[0] == '-') { ++ is_negative = (s.ptr[0] == '-'); ++ s.ptr += 1; ++ s.slen -= 1; ++ } ++ ++ rc = pj_strtoul3(&s, &retval, 10); ++ if (rc == PJ_EINVAL) { ++ return rc; ++ } else if (rc != PJ_SUCCESS) { ++ *value = is_negative ? PJ_MINLONG : PJ_MAXLONG; ++ return is_negative ? PJ_ETOOSMALL : PJ_ETOOBIG; ++ } ++ ++ if (retval > PJ_MAXLONG && !is_negative) { ++ *value = PJ_MAXLONG; ++ return PJ_ETOOBIG; ++ } ++ ++ if (retval > (PJ_MAXLONG + 1UL) && is_negative) { ++ *value = PJ_MINLONG; ++ return PJ_ETOOSMALL; ++ } ++ ++ *value = is_negative ? -(long)retval : retval; ++ ++ return PJ_SUCCESS; ++} ++ + PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str) + { + unsigned long value; +@@ -282,6 +334,71 @@ PJ_DEF(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr, + return value; + } + ++PJ_DEF(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value, ++ unsigned base) ++{ ++ pj_str_t s; ++ unsigned i; ++ ++ PJ_CHECK_STACK(); ++ ++ if (!str || !value) { ++ return PJ_EINVAL; ++ } ++ ++ s = *str; ++ pj_strltrim(&s); ++ ++ if (s.slen == 0 || s.ptr[0] < '0' || ++ (base <= 10 && (unsigned)s.ptr[0] > ('0' - 1) + base) || ++ (base == 16 && !pj_isxdigit(s.ptr[0]))) ++ { ++ return PJ_EINVAL; ++ } ++ ++ *value = 0; ++ if (base <= 10) { ++ for (i=0; i<(unsigned)s.slen; ++i) { ++ unsigned c = s.ptr[i] - '0'; ++ if (s.ptr[i] < '0' || (unsigned)s.ptr[i] > ('0' - 1) + base) { ++ break; ++ } ++ if (*value > PJ_MAXULONG / base) { ++ *value = PJ_MAXULONG; ++ return PJ_ETOOBIG; ++ } ++ ++ *value *= base; ++ if ((PJ_MAXULONG - *value) < c) { ++ *value = PJ_MAXULONG; ++ return PJ_ETOOBIG; ++ } ++ *value += c; ++ } ++ } else if (base == 16) { ++ for (i=0; i<(unsigned)s.slen; ++i) { ++ unsigned c = pj_hex_digit_to_val(s.ptr[i]); ++ if (!pj_isxdigit(s.ptr[i])) ++ break; ++ ++ if (*value > PJ_MAXULONG / base) { ++ *value = PJ_MAXULONG; ++ return PJ_ETOOBIG; ++ } ++ *value *= base; ++ if ((PJ_MAXULONG - *value) < c) { ++ *value = PJ_MAXULONG; ++ return PJ_ETOOBIG; ++ } ++ *value += c; ++ } ++ } else { ++ pj_assert(!"Unsupported base"); ++ return PJ_EINVAL; ++ } ++ return PJ_SUCCESS; ++} ++ + PJ_DEF(float) pj_strtof(const pj_str_t *str) + { + pj_str_t part; +@@ -356,5 +473,3 @@ PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad) + + return len; + } +- +- +diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c +index 225be4498..399e114a8 100644 +--- a/pjlib/src/pj/timer.c ++++ b/pjlib/src/pj/timer.c +@@ -36,6 +36,7 @@ + #include <pj/lock.h> + #include <pj/log.h> + #include <pj/rand.h> ++#include <pj/limits.h> + + #define THIS_FILE "timer.c" + +diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h +index 0d767f0ad..5691fed3a 100644 +--- a/pjsip/include/pjsip/sip_parser.h ++++ b/pjsip/include/pjsip/sip_parser.h +@@ -39,6 +39,26 @@ PJ_BEGIN_DECL + */ + + /** ++ * Contants for limit checks ++ */ ++#define PJSIP_MIN_CONTENT_LENGTH 0 ++#define PJSIP_MAX_CONTENT_LENGTH PJ_MAXINT32 ++#define PJSIP_MIN_PORT 0 ++#define PJSIP_MAX_PORT PJ_MAXUINT16 ++#define PJSIP_MIN_TTL 0 ++#define PJSIP_MAX_TTL PJ_MAXUINT8 ++#define PJSIP_MIN_STATUS_CODE 100 ++#define PJSIP_MAX_STATUS_CODE 999 ++#define PJSIP_MIN_Q1000 0 ++#define PJSIP_MAX_Q1000 PJ_MAXINT32 / 1000 ++#define PJSIP_MIN_EXPIRES 0 ++#define PJSIP_MAX_EXPIRES PJ_MAXINT32 ++#define PJSIP_MIN_CSEQ 0 ++#define PJSIP_MAX_CSEQ PJ_MAXINT32 ++#define PJSIP_MIN_RETRY_AFTER 0 ++#define PJSIP_MAX_RETRY_AFTER PJ_MAXINT32 ++ ++/** + * URI Parsing options. + */ + enum +@@ -64,6 +84,11 @@ enum + extern int PJSIP_SYN_ERR_EXCEPTION; + + /** ++ * Invalid value error exception value. ++ */ ++extern int PJSIP_EINVAL_ERR_EXCEPTION; ++ ++/** + * This structure is used to get error reporting from parser. + */ + typedef struct pjsip_parser_err_report +diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c +index cf3b879f6..f9a0e65b5 100644 +--- a/pjsip/src/pjsip/sip_parser.c ++++ b/pjsip/src/pjsip/sip_parser.c +@@ -34,6 +34,7 @@ + #include <pj/string.h> + #include <pj/ctype.h> + #include <pj/assert.h> ++#include <pj/limits.h> + + #define THIS_FILE "sip_parser.c" + +@@ -93,6 +94,7 @@ static unsigned uri_handler_count; + * Global vars (also extern). + */ + int PJSIP_SYN_ERR_EXCEPTION = -1; ++int PJSIP_EINVAL_ERR_EXCEPTION = -2; + + /* Parser constants */ + static pjsip_parser_const_t pconst = +@@ -205,7 +207,6 @@ static unsigned long pj_strtoul_mindigit(const pj_str_t *str, + /* Case insensitive comparison */ + #define parser_stricmp(s1, s2) (s1.slen!=s2.slen || pj_stricmp_alnum(&s1, &s2)) + +- + /* Get a token and unescape */ + PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool, + const pj_cis_t *spec, +@@ -223,8 +224,6 @@ PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool, + #endif + } + +- +- + /* Syntax error handler for parser. */ + static void on_syntax_error(pj_scanner *scanner) + { +@@ -232,6 +231,60 @@ static void on_syntax_error(pj_scanner *scanner) + PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); + } + ++/* Syntax error handler for parser. */ ++static void on_str_parse_error(const pj_str_t *str, int rc) ++{ ++ char *s; ++ ++ switch(rc) { ++ case PJ_EINVAL: ++ s = "NULL input string, invalid input string, or NULL return "\ ++ "value pointer"; ++ break; ++ case PJ_ETOOSMALL: ++ s = "String value was less than the minimum allowed value."; ++ break; ++ case PJ_ETOOBIG: ++ s = "String value was greater than the maximum allowed value."; ++ break; ++ default: ++ s = "Unknown error"; ++ } ++ ++ if (str) { ++ PJ_LOG(1, (THIS_FILE, "Error parsing '%.*s': %s", ++ (int)str->slen, str->ptr, s)); ++ } else { ++ PJ_LOG(1, (THIS_FILE, "Can't parse input string: %s", s)); ++ } ++ PJ_THROW(PJSIP_EINVAL_ERR_EXCEPTION); ++} ++ ++static void strtoi_validate(const pj_str_t *str, int min_val, ++ int max_val, int *value) ++{ ++ long retval; ++ pj_status_t status; ++ ++ if (!str || !value) { ++ on_str_parse_error(str, PJ_EINVAL); ++ } ++ status = pj_strtol2(str, &retval); ++ if (status != PJ_EINVAL) { ++ if (min_val > retval) { ++ *value = min_val; ++ status = PJ_ETOOSMALL; ++ } else if (retval > max_val) { ++ *value = max_val; ++ status = PJ_ETOOBIG; ++ } else ++ *value = (int)retval; ++ } ++ ++ if (status != PJ_SUCCESS) ++ on_str_parse_error(str, status); ++} ++ + /* Get parser constants. */ + PJ_DEF(const pjsip_parser_const_t*) pjsip_parser_const(void) + { +@@ -285,6 +338,14 @@ static pj_status_t init_parser() + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + + /* ++ * Invalid value exception. ++ */ ++ pj_assert (PJSIP_EINVAL_ERR_EXCEPTION == -2); ++ status = pj_exception_id_alloc("PJSIP invalid value error", ++ &PJSIP_EINVAL_ERR_EXCEPTION); ++ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); ++ ++ /* + * Init character input spec (cis) + */ + +@@ -502,6 +563,9 @@ void deinit_sip_parser(void) + /* Deregister exception ID */ + pj_exception_id_free(PJSIP_SYN_ERR_EXCEPTION); + PJSIP_SYN_ERR_EXCEPTION = -1; ++ ++ pj_exception_id_free(PJSIP_EINVAL_ERR_EXCEPTION); ++ PJSIP_EINVAL_ERR_EXCEPTION = -2; + } + pj_leave_critical_section(); + } +@@ -766,7 +830,7 @@ PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size, + } + + /* Determine if a message has been received. */ +-PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, ++PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size, + pj_bool_t is_datagram, pj_size_t *msg_size) + { + #if PJ_HAS_TCP +@@ -776,6 +840,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, + const char *line; + int content_length = -1; + pj_str_t cur_msg; ++ pj_status_t status = PJ_SUCCESS; + const pj_str_t end_hdr = { "\n\r\n", 3}; + + *msg_size = size; +@@ -836,9 +901,16 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, + pj_scan_get_newline(&scanner); + + /* Found a valid Content-Length header. */ +- content_length = pj_strtoul(&str_clen); ++ strtoi_validate(&str_clen, PJSIP_MIN_CONTENT_LENGTH, ++ PJSIP_MAX_CONTENT_LENGTH, &content_length); + } + PJ_CATCH_ANY { ++ int eid = PJ_GET_EXCEPTION(); ++ if (eid == PJSIP_SYN_ERR_EXCEPTION) { ++ status = PJSIP_EMISSINGHDR; ++ } else if (eid == PJSIP_EINVAL_ERR_EXCEPTION) { ++ status = PJSIP_EINVALIDHDR; ++ } + content_length = -1; + } + PJ_END +@@ -858,7 +930,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, + + /* Found Content-Length? */ + if (content_length == -1) { +- return PJSIP_EMISSINGHDR; ++ return status; + } + + /* Enough packet received? */ +@@ -938,10 +1010,14 @@ static pj_bool_t is_next_sip_version(pj_scanner *scanner) + static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx, + pjsip_parser_err_report *err_list) + { +- pj_bool_t parsing_headers; +- pjsip_msg *msg = NULL; ++ /* These variables require "volatile" so their values get ++ * preserved when re-entering the PJ_TRY block after an error. ++ */ ++ volatile pj_bool_t parsing_headers; ++ pjsip_msg *volatile msg = NULL; ++ pjsip_ctype_hdr *volatile ctype_hdr = NULL; ++ + pj_str_t hname; +- pjsip_ctype_hdr *ctype_hdr = NULL; + pj_scanner *scanner = ctx->scanner; + pj_pool_t *pool = ctx->pool; + PJ_USE_EXCEPTION; +@@ -1023,7 +1099,6 @@ parse_headers: + hdr->name = hdr->sname = hname; + } + +- + /* Single parse of header line can produce multiple headers. + * For example, if one Contact: header contains Contact list + * separated by comma, then these Contacts will be split into +@@ -1267,7 +1342,7 @@ static void int_parse_uri_host_port( pj_scanner *scanner, + pj_str_t port; + pj_scan_get_char(scanner); + pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &port); +- *p_port = pj_strtoul(&port); ++ strtoi_validate(&port, PJSIP_MIN_PORT, PJSIP_MAX_PORT, p_port); + } else { + *p_port = 0; + } +@@ -1458,8 +1533,8 @@ static void* int_parse_sip_url( pj_scanner *scanner, + url->transport_param = pvalue; + + } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) { +- url->ttl_param = pj_strtoul(&pvalue); +- ++ strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL, ++ &url->ttl_param); + } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) { + url->maddr_param = pvalue; + +@@ -1595,7 +1670,8 @@ static void int_parse_status_line( pj_scanner *scanner, + + parse_sip_version(scanner); + pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token); +- status_line->code = pj_strtoul(&token); ++ strtoi_validate(&token, PJSIP_MIN_STATUS_CODE, PJSIP_MAX_STATUS_CODE, ++ &status_line->code); + if (*scanner->curptr != '\r' && *scanner->curptr != '\n') + pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &status_line->reason); + else +@@ -1780,20 +1856,34 @@ static void int_parse_contact_param( pjsip_contact_hdr *hdr, + if (!parser_stricmp(pname, pconst.pjsip_Q_STR) && pvalue.slen) { + char *dot_pos = (char*) pj_memchr(pvalue.ptr, '.', pvalue.slen); + if (!dot_pos) { +- hdr->q1000 = pj_strtoul(&pvalue) * 1000; ++ strtoi_validate(&pvalue, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000, ++ &hdr->q1000); ++ hdr->q1000 *= 1000; + } else { + pj_str_t tmp = pvalue; ++ unsigned long qval_frac; + + tmp.slen = dot_pos - pvalue.ptr; +- hdr->q1000 = pj_strtoul(&tmp) * 1000; ++ strtoi_validate(&tmp, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000, ++ &hdr->q1000); ++ hdr->q1000 *= 1000; + + pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1); + pvalue.ptr = dot_pos + 1; +- hdr->q1000 += pj_strtoul_mindigit(&pvalue, 3); ++ if (pvalue.slen > 3) { ++ pvalue.slen = 3; ++ } ++ qval_frac = pj_strtoul_mindigit(&pvalue, 3); ++ if ((unsigned)hdr->q1000 > (PJ_MAXINT32 - qval_frac)) { ++ PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); ++ } ++ hdr->q1000 += qval_frac; + } +- } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && pvalue.slen) { +- hdr->expires = pj_strtoul(&pvalue); +- ++ } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && ++ pvalue.slen) ++ { ++ strtoi_validate(&pvalue, PJSIP_MIN_EXPIRES, PJSIP_MAX_EXPIRES, ++ &hdr->expires); + } else { + pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); + p->name = pname; +@@ -1890,19 +1980,22 @@ static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx ) + static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx ) + { + pj_str_t cseq, method; +- pjsip_cseq_hdr *hdr; ++ pjsip_cseq_hdr *hdr = NULL; ++ int cseq_val = 0; + +- hdr = pjsip_cseq_hdr_create(ctx->pool); + pj_scan_get( ctx->scanner, &pconst.pjsip_DIGIT_SPEC, &cseq); +- hdr->cseq = pj_strtoul(&cseq); ++ strtoi_validate(&cseq, PJSIP_MIN_CSEQ, PJSIP_MAX_CSEQ, &cseq_val); + +- pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method); +- pjsip_method_init_np(&hdr->method, &method); ++ hdr = pjsip_cseq_hdr_create(ctx->pool); ++ hdr->cseq = cseq_val; + ++ pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method); + parse_hdr_end( ctx->scanner ); + +- if (ctx->rdata) ++ pjsip_method_init_np(&hdr->method, &method); ++ if (ctx->rdata) { + ctx->rdata->msg_info.cseq = hdr; ++ } + + return (pjsip_hdr*)hdr; + } +@@ -1984,7 +2077,8 @@ static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx) + hdr = pjsip_retry_after_hdr_create(ctx->pool, 0); + + pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &tmp); +- hdr->ivalue = pj_strtoul(&tmp); ++ strtoi_validate(&tmp, PJSIP_MIN_RETRY_AFTER, PJSIP_MAX_RETRY_AFTER, ++ &hdr->ivalue); + + while (!pj_scan_is_eof(scanner) && *scanner->curptr!='\r' && + *scanner->curptr!='\n') +@@ -2073,7 +2167,8 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner, + hdr->branch_param = pvalue; + + } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) { +- hdr->ttl_param = pj_strtoul(&pvalue); ++ strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL, ++ &hdr->ttl_param); + + } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) { + hdr->maddr_param = pvalue; +@@ -2082,9 +2177,10 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner, + hdr->recvd_param = pvalue; + + } else if (!parser_stricmp(pname, pconst.pjsip_RPORT_STR)) { +- if (pvalue.slen) +- hdr->rport_param = pj_strtoul(&pvalue); +- else ++ if (pvalue.slen) { ++ strtoi_validate(&pvalue, PJSIP_MIN_PORT, PJSIP_MAX_PORT, ++ &hdr->rport_param); ++ } else + hdr->rport_param = 0; + } else { + pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); +@@ -2213,7 +2309,8 @@ static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx ) + pj_str_t digit; + pj_scan_get_char(scanner); + pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &digit); +- hdr->sent_by.port = pj_strtoul(&digit); ++ strtoi_validate(&digit, PJSIP_MIN_PORT, PJSIP_MAX_PORT, ++ &hdr->sent_by.port); + } + + int_parse_via_param(hdr, scanner, ctx->pool); +@@ -2298,9 +2395,10 @@ PJ_DEF(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, char *input, + unsigned options) + { + enum { STOP_ON_ERROR = 1 }; ++ pj_str_t hname; + pj_scanner scanner; + pjsip_parse_ctx ctx; +- pj_str_t hname; ++ + PJ_USE_EXCEPTION; + + pj_scan_init(&scanner, input, size, PJ_SCAN_AUTOSKIP_WS_HEADER, +@@ -2323,7 +2421,7 @@ retry_parse: + */ + hname.slen = 0; + +- /* Get hname. */ ++ /* Get hname. */ + pj_scan_get( &scanner, &pconst.pjsip_TOKEN_SPEC, &hname); + if (pj_scan_get_char( &scanner ) != ':') { + PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); +diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c +index f3be93beb..7ac3d1b76 100644 +--- a/pjsip/src/pjsip/sip_transaction.c ++++ b/pjsip/src/pjsip/sip_transaction.c +@@ -289,11 +289,11 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool, + + /* Calculate length required. */ + len_required = method->name.slen + /* Method */ +- 9 + /* CSeq number */ ++ 11 + /* CSeq number */ + rdata->msg_info.from->tag.slen + /* From tag. */ + rdata->msg_info.cid->id.slen + /* Call-ID */ + host->slen + /* Via host. */ +- 9 + /* Via port. */ ++ 11 + /* Via port. */ + 16; /* Separator+Allowance. */ + key = p = (char*) pj_pool_alloc(pool, len_required); + +diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c +index 0c338e8fd..b24cbb411 100644 +--- a/pjsip/src/pjsip/sip_transport.c ++++ b/pjsip/src/pjsip/sip_transport.c +@@ -1848,7 +1848,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, + /* Check for parsing syntax error */ + if (msg==NULL || !pj_list_empty(&rdata->msg_info.parse_err)) { + pjsip_parser_err_report *err; +- char buf[128]; ++ char buf[256]; + pj_str_t tmp; + + /* Gather syntax error information */ +@@ -1862,7 +1862,10 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr, + pj_exception_id_name(err->except_code), + (int)err->hname.slen, err->hname.ptr, + err->line, err->col); +- if (len > 0 && len < (int) (sizeof(buf)-tmp.slen)) { ++ if (len >= (int)sizeof(buf)-tmp.slen) { ++ len = (int)sizeof(buf)-tmp.slen; ++ } ++ if (len > 0) { + tmp.slen += len; + } + err = err->next; +-- +2.13.6 + |