Package: release.debian.org Severity: normal Tags: buster User: release.debian....@packages.debian.org Usertags: pu
Hi, I would like to make a stable-update for asterisk. It fixes three minor CVEs (marked no-dsa) #940060 CVE-2019-15297: AST-2019-004: Crash when negotiating for T.38 with a declined stream #947377 CVE-2019-18610: AST-2019-007: AMI user could execute system commands #947381 CVE-2019-18790: AST-2019-006: SIP request can change address of a SIP peer It fixes one segmentation fault due to a wrong datatype when IPv6 is in use #882145 asterisk: pjsip show history causes segmentation fault and one use-after-free that causes a misleading error message to appear #966334 ast_json_vpack: Error building JSON ... Invalid UTF-8 string. All of them have been fixed by backporting the corressponding upstream fixes that are already in sid/bullseye. Debdiff attached. Bernhard
diffstat for asterisk-16.2.1~dfsg asterisk-16.2.1~dfsg changelog | 13 ++ patches/AST-2019-004.patch | 171 ++++++++++++++++++++++++++++++++ patches/AST-2019-006.patch | 73 +++++++++++++ patches/AST-2019-007.patch | 46 ++++++++ patches/fix-error-building-json.patch | 30 +++++ patches/fix-sigsegv-pjsip-history.patch | 30 +++++ patches/series | 9 + 7 files changed, 372 insertions(+) diff -Nru asterisk-16.2.1~dfsg/debian/changelog asterisk-16.2.1~dfsg/debian/changelog --- asterisk-16.2.1~dfsg/debian/changelog 2019-08-20 22:31:33.000000000 +0200 +++ asterisk-16.2.1~dfsg/debian/changelog 2020-08-27 00:53:40.000000000 +0200 @@ -1,3 +1,16 @@ +asterisk (1:16.2.1~dfsg-1+deb10u2) buster; urgency=medium + + * CVE-2019-15297: AST-2019-004 + Crash when negotiating for T.38 with a declined stream (Closes: #940060) + * CVE-2019-18790: AST-2019-006 + SIP request can change address of a SIP peer (Closes: #947381) + * CVE-2019-18610: AST-2019-007 + AMI user could execute system commands (Closes: #947377) + * Fix use-after-free with TEST_FRAMEWORK enabled (Closes: #966334) + * Fix segfault in pjsip show history with IPv6 peers (Closes: #882145) + + -- Bernhard Schmidt <be...@debian.org> Thu, 27 Aug 2020 00:53:40 +0200 + asterisk (1:16.2.1~dfsg-1+deb10u1) buster; urgency=medium * AST-2019-002 / CVE-2019-12827 diff -Nru asterisk-16.2.1~dfsg/debian/patches/AST-2019-004.patch asterisk-16.2.1~dfsg/debian/patches/AST-2019-004.patch --- asterisk-16.2.1~dfsg/debian/patches/AST-2019-004.patch 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-16.2.1~dfsg/debian/patches/AST-2019-004.patch 2020-08-27 00:53:40.000000000 +0200 @@ -0,0 +1,171 @@ +From 965df3c228d49bcde3503e0482f3c831dcbf6c77 Mon Sep 17 00:00:00 2001 +From: Kevin Harwell <kharw...@digium.com> +Date: Tue, 20 Aug 2019 15:05:45 -0500 +Subject: [PATCH] AST-2019-004 - res_pjsip_t38.c: Add NULL checks before using session media + +After receiving a 200 OK with a declined stream in response to a T.38 +initiated re-invite Asterisk would crash when attempting to dereference +a NULL session media object. + +This patch checks to make sure the session media object is not NULL before +attempting to use it. + +ASTERISK-28495 +patches: + ast-2019-004.patch submitted by Alexei Gradinari (license 5691) + +Change-Id: I168f45f4da29cfe739acf87e597baa2aae7aa572 +--- + +diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c +index 11804e2..e5c6090 100644 +--- a/res/res_pjsip_t38.c ++++ b/res/res_pjsip_t38.c +@@ -203,7 +203,6 @@ + { + RAII_VAR(struct ast_sip_session *, session, obj, ao2_cleanup); + RAII_VAR(struct ast_datastore *, datastore, ast_sip_session_get_datastore(session, "t38"), ao2_cleanup); +- struct ast_sip_session_media *session_media; + + if (!datastore) { + return 0; +@@ -212,8 +211,7 @@ + ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : "<gone>"); + +- session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(session, session_media, datastore->data, T38_REJECTED); ++ t38_change_state(session, NULL, datastore->data, T38_REJECTED); + ast_sip_session_resume_reinvite(session); + + return 0; +@@ -322,28 +320,37 @@ + int index; + + session_media = session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(session, session_media, state, T38_ENABLED); ++ if (!session_media) { ++ ast_log(LOG_WARNING, "Received %d response to T.38 re-invite on '%s' but no active session media\n", ++ status.code, session->channel ? ast_channel_name(session->channel) : "unknown channel"); ++ } else { ++ t38_change_state(session, session_media, state, T38_ENABLED); + +- /* Stop all the streams in the stored away active state, they'll go back to being active once +- * we reinvite back. +- */ +- for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) { +- struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index); ++ /* Stop all the streams in the stored away active state, they'll go back to being active once ++ * we reinvite back. ++ */ ++ for (index = 0; index < AST_VECTOR_SIZE(&state->media_state->sessions); ++index) { ++ struct ast_sip_session_media *session_media = AST_VECTOR_GET(&state->media_state->sessions, index); + +- if (session_media && session_media->handler && session_media->handler->stream_stop) { +- session_media->handler->stream_stop(session_media); ++ if (session_media && session_media->handler && session_media->handler->stream_stop) { ++ session_media->handler->stream_stop(session_media); ++ } + } ++ ++ return 0; + } + } else { + session_media = session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(session, session_media, state, T38_REJECTED); +- +- /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */ +- ast_sip_session_media_state_free(state->media_state); +- state->media_state = NULL; +- ast_sip_session_media_state_reset(session->pending_media_state); + } + ++ /* If no session_media then response contained a declined stream, so disable */ ++ t38_change_state(session, NULL, state, session_media ? T38_REJECTED : T38_DISABLED); ++ ++ /* Abort this attempt at switching to T.38 by resetting the pending state and freeing our stored away active state */ ++ ast_sip_session_media_state_free(state->media_state); ++ state->media_state = NULL; ++ ast_sip_session_media_state_reset(session->pending_media_state); ++ + return 0; + } + +@@ -426,12 +433,10 @@ + /* Negotiation can not take place without a valid max_ifp value. */ + if (!parameters->max_ifp) { + if (data->session->t38state == T38_PEER_REINVITE) { +- session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(data->session, session_media, state, T38_REJECTED); ++ t38_change_state(data->session, NULL, state, T38_REJECTED); + ast_sip_session_resume_reinvite(data->session); + } else if (data->session->t38state == T38_ENABLED) { +- session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(data->session, session_media, state, T38_DISABLED); ++ t38_change_state(data->session, NULL, state, T38_DISABLED); + ast_sip_session_refresh(data->session, NULL, NULL, NULL, + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state); + state->media_state = NULL; +@@ -454,6 +459,11 @@ + state->our_parms.version = MIN(state->our_parms.version, state->their_parms.version); + state->our_parms.rate_management = state->their_parms.rate_management; + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; ++ if (!session_media) { ++ ast_log(LOG_ERROR, "Failed to negotiate parameters for reinvite on channel '%s' (No pending session media).\n", ++ data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel"); ++ break; ++ } + ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp); + t38_change_state(data->session, session_media, state, T38_ENABLED); + ast_sip_session_resume_reinvite(data->session); +@@ -468,8 +478,13 @@ + } + state->our_parms = *parameters; + session_media = media_state->default_session[AST_MEDIA_TYPE_IMAGE]; ++ if (!session_media) { ++ ast_log(LOG_ERROR, "Failed to negotiate parameters on channel '%s' (No default session media).\n", ++ data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel"); ++ break; ++ } + ast_udptl_set_local_max_ifp(session_media->udptl, state->our_parms.max_ifp); +- t38_change_state(data->session, session_media, state, T38_LOCAL_REINVITE); ++ t38_change_state(data->session, NULL, state, T38_LOCAL_REINVITE); + ast_sip_session_refresh(data->session, NULL, t38_reinvite_sdp_cb, t38_reinvite_response_cb, + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, media_state); + } +@@ -478,12 +493,10 @@ + case AST_T38_REFUSED: + case AST_T38_REQUEST_TERMINATE: /* Shutdown T38 */ + if (data->session->t38state == T38_PEER_REINVITE) { +- session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(data->session, session_media, state, T38_REJECTED); ++ t38_change_state(data->session, NULL, state, T38_REJECTED); + ast_sip_session_resume_reinvite(data->session); + } else if (data->session->t38state == T38_ENABLED) { +- session_media = data->session->active_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; +- t38_change_state(data->session, session_media, state, T38_DISABLED); ++ t38_change_state(data->session, NULL, state, T38_DISABLED); + ast_sip_session_refresh(data->session, NULL, NULL, NULL, AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, state->media_state); + state->media_state = NULL; + } +@@ -493,6 +506,11 @@ + + if (data->session->t38state == T38_PEER_REINVITE) { + session_media = data->session->pending_media_state->default_session[AST_MEDIA_TYPE_IMAGE]; ++ if (!session_media) { ++ ast_log(LOG_ERROR, "Failed to request parameters for reinvite on channel '%s' (No pending session media).\n", ++ data->session->channel ? ast_channel_name(data->session->channel) : "unknown channel"); ++ break; ++ } + parameters.max_ifp = ast_udptl_get_far_max_ifp(session_media->udptl); + parameters.request_response = AST_T38_REQUEST_NEGOTIATE; + ast_queue_control_data(data->session->channel, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters)); +@@ -788,7 +806,7 @@ + + if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) { + ast_debug(3, "Declining; T.38 state is rejected or declined\n"); +- t38_change_state(session, session_media, state, T38_DISABLED); ++ t38_change_state(session, NULL, state, T38_DISABLED); + return 0; + } + diff -Nru asterisk-16.2.1~dfsg/debian/patches/AST-2019-006.patch asterisk-16.2.1~dfsg/debian/patches/AST-2019-006.patch --- asterisk-16.2.1~dfsg/debian/patches/AST-2019-006.patch 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-16.2.1~dfsg/debian/patches/AST-2019-006.patch 2020-08-27 00:53:40.000000000 +0200 @@ -0,0 +1,73 @@ +From 8cdaa93e658a46e7baf6b606468b5e2c88a0133b Mon Sep 17 00:00:00 2001 +From: Ben Ford <bf...@digium.com> +Date: Mon, 21 Oct 2019 14:55:06 -0500 +Subject: [PATCH] chan_sip.c: Prevent address change on unauthenticated SIP request. + +If the name of a peer is known and a SIP request is sent using that +peer's name, the address of the peer will change even if the request +fails the authentication challenge. This means that an endpoint can +be altered and even rendered unusuable, even if it was in a working +state previously. This can only occur when the nat option is set to the +default, or auto_force_rport. + +This change checks the result of authentication first to ensure it is +successful before setting the address and the nat option. + +ASTERISK-28589 #close + +Change-Id: I581c5ed1da60ca89f590bd70872de2b660de02df +--- + +diff --git a/channels/chan_sip.c b/channels/chan_sip.c +index 6ac2e61..4d79a47 100644 +--- a/channels/chan_sip.c ++++ b/channels/chan_sip.c +@@ -19245,18 +19245,6 @@ + bogus_peer = NULL; + } + +- /* build_peer, called through sip_find_peer, is not able to check the +- * sip_pvt->natdetected flag in order to determine if the peer is behind +- * NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA +- * are set on the peer. So we check for that here and set the peer's +- * address accordingly. +- */ +- set_peer_nat(p, peer); +- +- if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { +- ast_sockaddr_copy(&peer->addr, &p->recv); +- } +- + if (!ast_apply_acl(peer->acl, addr, "SIP Peer ACL: ")) { + ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of); + sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED"); +@@ -19325,6 +19313,21 @@ + ast_string_field_set(p, peermd5secret, NULL); + } + if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable))) { ++ ++ /* build_peer, called through sip_find_peer, is not able to check the ++ * sip_pvt->natdetected flag in order to determine if the peer is behind ++ * NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA ++ * are set on the peer. So we check for that here and set the peer's ++ * address accordingly. The address should ONLY be set once we are sure ++ * authentication was a success. If, for example, an INVITE was sent that ++ * matched the peer name but failed the authentication check, the address ++ * would be updated, which is bad. ++ */ ++ set_peer_nat(p, peer); ++ if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) { ++ ast_sockaddr_copy(&peer->addr, &p->recv); ++ } ++ + /* If we have a call limit, set flag */ + if (peer->call_limit) + ast_set_flag(&p->flags[0], SIP_CALL_LIMIT); +@@ -19424,6 +19427,7 @@ + } + } + sip_unref_peer(peer, "check_peer_ok: sip_unref_peer: tossing temp ptr to peer from sip_find_peer"); ++ + return res; + } + diff -Nru asterisk-16.2.1~dfsg/debian/patches/AST-2019-007.patch asterisk-16.2.1~dfsg/debian/patches/AST-2019-007.patch --- asterisk-16.2.1~dfsg/debian/patches/AST-2019-007.patch 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-16.2.1~dfsg/debian/patches/AST-2019-007.patch 2020-08-27 00:53:40.000000000 +0200 @@ -0,0 +1,46 @@ +From 7574be5110e049a44b8c8ead52cd1c2a5d442afa Mon Sep 17 00:00:00 2001 +From: George Joseph <gjos...@digium.com> +Date: Thu, 24 Oct 2019 11:41:23 -0600 +Subject: [PATCH] manager.c: Prevent the Originate action from running the Originate app + +If an AMI user without the "system" authorization calls the +Originate AMI command with the Originate application, +the second Originate could run the "System" command. + +Action: Originate +Channel: Local/1111 +Application: Originate +Data: Local/2222,app,System,touch /tmp/owned + +If the "system" authorization isn't set, we now block the +Originate app as well as the System, Exec, etc. apps. + +ASTERISK-28580 +Reported by: Eliel SardaƱons + +Change-Id: Ic4c9dedc34c426f03c8c14fce334a71386d8a5fa +--- + +diff --git a/doc/UPGRADE-staging/AMI-Originate.txt b/doc/UPGRADE-staging/AMI-Originate.txt +new file mode 100644 +index 0000000..f2d3133 +--- /dev/null ++++ b/doc/UPGRADE-staging/AMI-Originate.txt +@@ -0,0 +1,5 @@ ++Subject: AMI ++ ++The AMI Originate action, which optionally takes a dialplan application as ++an argument, no longer accepts "Originate" as the application due to ++security concerns. +diff --git a/main/manager.c b/main/manager.c +index f138801..1963151 100644 +--- a/main/manager.c ++++ b/main/manager.c +@@ -5744,6 +5744,7 @@ + EAGI(/bin/rm,-rf /) */ + strcasestr(app, "mixmonitor") || /* MixMonitor(blah,,rm -rf) */ + strcasestr(app, "externalivr") || /* ExternalIVR(rm -rf) */ ++ strcasestr(app, "originate") || /* Originate(Local/1234,app,System,rm -rf) */ + (strstr(appdata, "SHELL") && (bad_appdata = 1)) || /* NoOp(${SHELL(rm -rf /)}) */ + (strstr(appdata, "EVAL") && (bad_appdata = 1)) /* NoOp(${EVAL(${some_var_containing_SHELL})}) */ + )) { diff -Nru asterisk-16.2.1~dfsg/debian/patches/fix-error-building-json.patch asterisk-16.2.1~dfsg/debian/patches/fix-error-building-json.patch --- asterisk-16.2.1~dfsg/debian/patches/fix-error-building-json.patch 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-16.2.1~dfsg/debian/patches/fix-error-building-json.patch 2020-08-27 00:53:40.000000000 +0200 @@ -0,0 +1,30 @@ +From 4d56adf8fbbbaa6c05c547eb482f1d154ec006d4 Mon Sep 17 00:00:00 2001 +From: Sean Bright <sean.bri...@gmail.com> +Date: Tue, 03 Dec 2019 16:42:00 -0500 +Subject: [PATCH] res_pjsip_session.c: Prevent use-after-free with TEST_FRAMEWORK enabled + +We need to copy the endpoint name before we call ao2_cleanup() on it, +otherwise we might try to access memory that has been reclaimed. + +ASTERISK-28445 #close +Reported by: Bernhard Schmidt + +Change-Id: I404b952608aa606e0babd3c4108346721fb726b3 +--- + +diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c +index 7373c19..bc01548 100644 +--- a/res/res_pjsip_session.c ++++ b/res/res_pjsip_session.c +@@ -2150,8 +2150,10 @@ + { + struct ast_sip_session *session = obj; + struct ast_sip_session_delayed_request *delay; ++ ++ /* We dup the endpoint ID in case the endpoint gets freed out from under us */ + const char *endpoint_name = session->endpoint ? +- ast_sorcery_object_get_id(session->endpoint) : "<none>"; ++ ast_strdupa(ast_sorcery_object_get_id(session->endpoint)) : "<none>"; + + ast_debug(3, "Destroying SIP session with endpoint %s\n", endpoint_name); + diff -Nru asterisk-16.2.1~dfsg/debian/patches/fix-sigsegv-pjsip-history.patch asterisk-16.2.1~dfsg/debian/patches/fix-sigsegv-pjsip-history.patch --- asterisk-16.2.1~dfsg/debian/patches/fix-sigsegv-pjsip-history.patch 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-16.2.1~dfsg/debian/patches/fix-sigsegv-pjsip-history.patch 2020-08-27 00:53:40.000000000 +0200 @@ -0,0 +1,30 @@ +From 29910aa451e8b815fdf21d997bffbb662653d261 Mon Sep 17 00:00:00 2001 +From: Roger James <ro...@beardandsandals.co.uk> +Date: Sat, 09 May 2020 08:46:51 +0100 +Subject: [PATCH] res_pjsip_history.c: Fix to stop SIGSEGV when IPv6 addresses are encountered. + +Changed source and destination address fields in struct +pjsip_history_entry so that they are long enough to hold an IPv6 +address. + +ASTERISK-28854 + +Change-Id: Id65bb9aa961e9ecbcb500815e18170f774e34d3e +--- + +diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c +index 10bcd96..e4b784d 100644 +--- a/res/res_pjsip_history.c ++++ b/res/res_pjsip_history.c +@@ -64,9 +64,9 @@ + /*! \brief Time the packet was transmitted/received */ + struct timeval timestamp; + /*! \brief Source address */ +- pj_sockaddr_in src; ++ pj_sockaddr src; + /*! \brief Destination address */ +- pj_sockaddr_in dst; ++ pj_sockaddr dst; + /*! \brief Memory pool used to allocate \c msg */ + pj_pool_t *pool; + /*! \brief The actual SIP message */ diff -Nru asterisk-16.2.1~dfsg/debian/patches/series asterisk-16.2.1~dfsg/debian/patches/series --- asterisk-16.2.1~dfsg/debian/patches/series 2019-08-20 22:31:33.000000000 +0200 +++ asterisk-16.2.1~dfsg/debian/patches/series 2020-08-27 00:53:40.000000000 +0200 @@ -37,3 +37,12 @@ AST-2019-002.patch # AST-2019-003 / CVE-2019-13161 AST-2019-003.patch +# AST-2019-004 / CVE-2019-15297 +AST-2019-004.patch +# AST-2019-006 / CVE-2019-18790 +AST-2019-006.patch +# AST-2019-007 / CVE-2019-18610 +AST-2019-007.patch + +fix-error-building-json.patch +fix-sigsegv-pjsip-history.patch