Version in base suite: 16.28.0~dfsg-0+deb11u1 Base version: asterisk_16.28.0~dfsg-0+deb11u1 Target version: asterisk_16.28.0~dfsg-0+deb11u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/a/asterisk/asterisk_16.28.0~dfsg-0+deb11u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/a/asterisk/asterisk_16.28.0~dfsg-0+deb11u2.dsc /srv/release.debian.org/tmp/Zf1XepuSfN/asterisk-16.28.0~dfsg/debian/pjproject_2.12.1~dfsg.orig.tar.bz2 |binary asterisk-16.28.0~dfsg/debian/changelog | 12 asterisk-16.28.0~dfsg/debian/patches/CVE-2022-37325.patch | 58 asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42705.patch | 657 ++++++++++ asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42706.patch | 166 ++ asterisk-16.28.0~dfsg/debian/patches/series | 3 6 files changed, 896 insertions(+) diff -Nru asterisk-16.28.0~dfsg/debian/changelog asterisk-16.28.0~dfsg/debian/changelog --- asterisk-16.28.0~dfsg/debian/changelog 2022-11-17 11:46:39.000000000 +0000 +++ asterisk-16.28.0~dfsg/debian/changelog 2023-02-22 22:11:00.000000000 +0000 @@ -1,3 +1,15 @@ +asterisk (1:16.28.0~dfsg-0+deb11u2) bullseye-security; urgency=high + + * Non-maintainer upload by the LTS team. + * Fix CVE-2022-23537, CVE-2022-23547, CVE-2022-31031, CVE-2022-37325, + CVE-2022-39244, CVE-2022-39269, CVE-2022-42705, CVE-2022-42706. + Multiple security vulnerabilities have been discovered in Asterisk, an Open + Source Private Branch Exchange. Buffer overflows and other programming + errors could be exploited for launching a denial of service attack or the + execution of arbitrary code. + + -- Markus Koschany Wed, 22 Feb 2023 23:11:00 +0100 + asterisk (1:16.28.0~dfsg-0+deb11u1) bullseye-security; urgency=high * Non-maintainer upload. diff -Nru asterisk-16.28.0~dfsg/debian/patches/CVE-2022-37325.patch asterisk-16.28.0~dfsg/debian/patches/CVE-2022-37325.patch --- asterisk-16.28.0~dfsg/debian/patches/CVE-2022-37325.patch 1970-01-01 00:00:00.000000000 +0000 +++ asterisk-16.28.0~dfsg/debian/patches/CVE-2022-37325.patch 2023-02-22 22:11:00.000000000 +0000 @@ -0,0 +1,58 @@ +From: Markus Koschany +Date: Wed, 22 Feb 2023 16:37:52 +0100 +Subject: CVE-2022-37325 + +Origin: https://downloads.asterisk.org/pub/security/AST-2022-007.html +--- + addons/ooh323c/src/ooq931.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/addons/ooh323c/src/ooq931.c b/addons/ooh323c/src/ooq931.c +index fe8b06e..b7bcba8 100644 +--- a/addons/ooh323c/src/ooq931.c ++++ b/addons/ooh323c/src/ooq931.c +@@ -192,11 +192,13 @@ EXTERN int ooQ931Decode + screening indicators ;-) */ + if(ie->discriminator == Q931CallingPartyNumberIE) + { ++ int numoffset=1; + OOTRACEDBGB1(" CallingPartyNumber IE = {\n"); +- if(ie->length < OO_MAX_NUMBER_LENGTH) ++ if(!(0x80 & ie->data[0])) numoffset = 2; ++ ++ if( (ie->length >= numoffset) && ++ (ie->length < OO_MAX_NUMBER_LENGTH) ) + { +- int numoffset=1; +- if(!(0x80 & ie->data[0])) numoffset = 2; + memcpy(number, ie->data+numoffset,ie->length-numoffset); + number[ie->length-numoffset]='\0'; + OOTRACEDBGB2(" %s\n", number); +@@ -204,7 +206,7 @@ EXTERN int ooQ931Decode + ooCallSetCallingPartyNumber(call, number); + } + else{ +- OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n", ++ OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n", + call->callType, call->callToken); + } + OOTRACEDBGB1(" }\n"); +@@ -214,7 +216,8 @@ EXTERN int ooQ931Decode + if(ie->discriminator == Q931CalledPartyNumberIE) + { + OOTRACEDBGB1(" CalledPartyNumber IE = {\n"); +- if(ie->length < OO_MAX_NUMBER_LENGTH) ++ if( (ie->length >= 1) && ++ (ie->length < OO_MAX_NUMBER_LENGTH) ) + { + memcpy(number, ie->data+1,ie->length-1); + number[ie->length-1]='\0'; +@@ -223,7 +226,7 @@ EXTERN int ooQ931Decode + ooCallSetCalledPartyNumber(call, number); + } + else{ +- OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n", ++ OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n", + call->callType, call->callToken); + } + OOTRACEDBGB1(" }\n"); diff -Nru asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42705.patch asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42705.patch --- asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42705.patch 1970-01-01 00:00:00.000000000 +0000 +++ asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42705.patch 2023-02-22 22:11:00.000000000 +0000 @@ -0,0 +1,657 @@ +From: Markus Koschany +Date: Wed, 22 Feb 2023 16:40:12 +0100 +Subject: CVE-2022-42705 + +Origin: https://downloads.asterisk.org/pub/security/AST-2022-008.html +--- + include/asterisk/res_pjsip.h | 83 +++++++++++++ + res/res_pjsip/pjsip_transport_events.c | 214 ++++++++++++++++++++++++++++++--- + res/res_pjsip_outbound_registration.c | 28 +++-- + res/res_pjsip_pubsub.c | 25 ++-- + 4 files changed, 307 insertions(+), 43 deletions(-) + +diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h +index 1714cff..abad25d 100644 +--- a/include/asterisk/res_pjsip.h ++++ b/include/asterisk/res_pjsip.h +@@ -81,6 +81,26 @@ + #define AST_STIR_SHAKEN_RESPONSE_STR_UNSUPPORTED_CREDENTIAL "Unsupported Credential" + #define AST_STIR_SHAKEN_RESPONSE_STR_INVALID_IDENTITY_HEADER "Invalid Identity Header" + ++/* ":12345" */ ++#define COLON_PORT_STRLEN 6 ++/* ++ * ":" ++ * PJ_INET6_ADDRSTRLEN includes the NULL terminator ++ */ ++#define IP6ADDR_COLON_PORT_BUFLEN (PJ_INET6_ADDRSTRLEN + COLON_PORT_STRLEN) ++ ++/*! ++ * \brief Fill a buffer with a pjsip transport's remote ip address and port ++ * ++ * \param transport The pjsip_transport to use ++ * \param dest The destination buffer of at least IP6ADDR_COLON_PORT_BUFLEN bytes ++ */ ++#define AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(_transport, _dest) \ ++ snprintf(_dest, IP6ADDR_COLON_PORT_BUFLEN, \ ++ PJSTR_PRINTF_SPEC ":%d", \ ++ PJSTR_PRINTF_VAR(_transport->remote_name.host), \ ++ _transport->remote_name.port); ++ + /* Forward declarations of PJSIP stuff */ + struct pjsip_rx_data; + struct pjsip_module; +@@ -3404,6 +3424,7 @@ enum ast_transport_monitor_reg { + + /*! + * \brief Register a reliable transport shutdown monitor callback. ++ * \deprecated Replaced with ast_sip_transport_monitor_register_key(). + * \since 13.20.0 + * + * \param transport Transport to monitor for shutdown. +@@ -3421,8 +3442,29 @@ enum ast_transport_monitor_reg { + enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data); + ++/*! ++ * \brief Register a reliable transport shutdown monitor callback. ++ * ++ * \param transport_key Key for the transport to monitor for shutdown. ++ * Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR. ++ * \param cb Who to call when transport is shutdown. ++ * \param ao2_data Data to pass with the callback. ++ * ++ * \note The data object passed will have its reference count automatically ++ * incremented by this call and automatically decremented after the callback ++ * runs or when the callback is unregistered. ++ * ++ * There is no checking for duplicate registrations. ++ * ++ * \return enum ast_transport_monitor_reg ++ */ ++enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key( ++ const char *transport_key, ast_transport_monitor_shutdown_cb cb, ++ void *ao2_data); ++ + /*! + * \brief Register a reliable transport shutdown monitor callback replacing any duplicate. ++ * \deprecated Replaced with ast_sip_transport_monitor_register_replace_key(). + * \since 13.26.0 + * \since 16.3.0 + * +@@ -3444,8 +3486,32 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transpor + enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches); + ++/*! ++ * \brief Register a reliable transport shutdown monitor callback replacing any duplicate. ++ * ++ * \param transport_key Key for the transport to monitor for shutdown. ++ * Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR. ++ * \param cb Who to call when transport is shutdown. ++ * \param ao2_data Data to pass with the callback. ++ * \param matches Matcher function that returns true if data matches a previously ++ * registered data object ++ * ++ * \note The data object passed will have its reference count automatically ++ * incremented by this call and automatically decremented after the callback ++ * runs or when the callback is unregistered. ++ * ++ * This function checks for duplicates, and overwrites/replaces the old monitor ++ * with the given one. ++ * ++ * \return enum ast_transport_monitor_reg ++ */ ++enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key( ++ const char *transport_key, ast_transport_monitor_shutdown_cb cb, ++ void *ao2_data, ast_transport_monitor_data_matcher matches); ++ + /*! + * \brief Unregister a reliable transport shutdown monitor ++ * \deprecated Replaced with ast_sip_transport_monitor_unregister_key(). + * \since 13.20.0 + * + * \param transport Transport to monitor for shutdown. +@@ -3461,6 +3527,23 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_ + void ast_sip_transport_monitor_unregister(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches); + ++/*! ++ * \brief Unregister a reliable transport shutdown monitor ++ * ++ * \param transport_key Key for the transport to monitor for shutdown. ++ * Create the key with AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR. ++ * \param cb The callback that was used for the original register. ++ * \param data Data to pass to the matcher. May be NULL and does NOT need to be an ao2 object. ++ * If NULL, all monitors with the provided callback are unregistered. ++ * \param matches Matcher function that returns true if data matches the previously ++ * registered data object. If NULL, a simple pointer comparison is done. ++ * ++ * \note The data object passed into the original register will have its reference count ++ * automatically decremented. ++ */ ++void ast_sip_transport_monitor_unregister_key(const char *transport_key, ++ ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches); ++ + /*! + * \brief Unregister a transport shutdown monitor from all reliable transports + * \since 13.20.0 +diff --git a/res/res_pjsip/pjsip_transport_events.c b/res/res_pjsip/pjsip_transport_events.c +index a816f46..0e4705d 100644 +--- a/res/res_pjsip/pjsip_transport_events.c ++++ b/res/res_pjsip/pjsip_transport_events.c +@@ -30,6 +30,7 @@ + #include "asterisk.h" + + #include "asterisk/res_pjsip.h" ++#include "asterisk/res_pjsip_cli.h" + #include "include/res_pjsip_private.h" + #include "asterisk/linkedlists.h" + #include "asterisk/vector.h" +@@ -49,8 +50,14 @@ struct transport_monitor_notifier { + + /*! \brief Structure for transport to be monitored */ + struct transport_monitor { ++ /*! \brief Key : */ ++ char key[IP6ADDR_COLON_PORT_BUFLEN]; + /*! \brief The underlying PJSIP transport */ + pjsip_transport *transport; ++ /*! For debugging purposes, we save the obj_name ++ * in case the transport goes away. ++ */ ++ char *transport_obj_name; + /*! Who is interested in when this transport shuts down. */ + AST_VECTOR(, struct transport_monitor_notifier) monitors; + }; +@@ -64,12 +71,14 @@ static pjsip_tp_state_callback tpmgr_state_callback; + /*! List of registered transport state callbacks. */ + static AST_RWLIST_HEAD(, ast_sip_tpmgr_state_callback) transport_state_list; + +- + /*! \brief Hashing function for struct transport_monitor */ +-AO2_STRING_FIELD_HASH_FN(transport_monitor, transport->obj_name); ++AO2_STRING_FIELD_HASH_FN(transport_monitor, key); + + /*! \brief Comparison function for struct transport_monitor */ +-AO2_STRING_FIELD_CMP_FN(transport_monitor, transport->obj_name); ++AO2_STRING_FIELD_CMP_FN(transport_monitor, key); ++ ++/*! \brief Sort function for struct transport_monitor */ ++AO2_STRING_FIELD_SORT_FN(transport_monitor, key); + + static const char *transport_state2str(pjsip_transport_state state) + { +@@ -112,6 +121,11 @@ static void transport_monitor_dtor(void *vdoomed) + ao2_cleanup(notifier->data); + } + AST_VECTOR_FREE(&monitored->monitors); ++ ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : state:MONITOR_DESTROYED\n", ++ monitored->key, monitored->transport->obj_name, ++ monitored->transport->type_name,pj_atomic_get(monitored->transport->ref_cnt)); ++ ast_free(monitored->transport_obj_name); ++ pjsip_transport_dec_ref(monitored->transport); + } + + /*! +@@ -125,8 +139,11 @@ static void transport_monitor_dtor(void *vdoomed) + static void transport_state_do_reg_callbacks(struct ao2_container *transports, pjsip_transport *transport) + { + struct transport_monitor *monitored; ++ char key[IP6ADDR_COLON_PORT_BUFLEN]; ++ ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); + +- monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_UNLINK); ++ monitored = ao2_find(transports, key, OBJ_SEARCH_KEY | OBJ_UNLINK); + if (monitored) { + int idx; + +@@ -134,8 +151,10 @@ static void transport_state_do_reg_callbacks(struct ao2_container *transports, p + struct transport_monitor_notifier *notifier; + + notifier = AST_VECTOR_GET_ADDR(&monitored->monitors, idx); +- ast_debug(3, "running callback %p(%p) for transport %s\n", +- notifier->cb, notifier->data, transport->obj_name); ++ ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : running callback %p(%p)\n", ++ monitored->key, monitored->transport->obj_name, ++ monitored->transport->type_name, ++ pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data); + notifier->cb(notifier->data); + } + ao2_ref(monitored, -1); +@@ -269,8 +288,11 @@ static void transport_state_callback(pjsip_transport *transport, + && (transports = ao2_global_obj_ref(active_transports))) { + struct transport_monitor *monitored; + +- ast_debug(3, "Reliable transport '%s' state:%s\n", +- transport->obj_name, transport_state2str(state)); ++ ast_debug(3, "Transport " PJSTR_PRINTF_SPEC ":%d(%s,%s): RefCnt: %ld state:%s\n", ++ PJSTR_PRINTF_VAR(transport->remote_name.host), ++ transport->remote_name.port, transport->obj_name, ++ transport->type_name, ++ pj_atomic_get(transport->ref_cnt), transport_state2str(state)); + switch (state) { + case PJSIP_TP_STATE_CONNECTED: + if (PJSIP_TRANSPORT_IS_SECURE(transport) && +@@ -285,10 +307,18 @@ static void transport_state_callback(pjsip_transport *transport, + break; + } + monitored->transport = transport; ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, monitored->key); ++ monitored->transport_obj_name = ast_strdup(transport->obj_name); ++ + if (AST_VECTOR_INIT(&monitored->monitors, 5)) { + ao2_ref(monitored, -1); + break; + } ++ pjsip_transport_add_ref(monitored->transport); ++ ast_debug(3, "Transport %s(%s,%s): RefCnt: %ld state:MONITOR_CREATED\n", ++ monitored->key, monitored->transport_obj_name, ++ monitored->transport->type_name, ++ pj_atomic_get(monitored->transport->ref_cnt)); + + ao2_link(transports, monitored); + ao2_ref(monitored, -1); +@@ -362,8 +392,10 @@ static int transport_monitor_unregister_cb(void *obj, void *arg, int flags) + || cb_data->matches(cb_data->data, notifier->data))) { + ao2_cleanup(notifier->data); + AST_VECTOR_REMOVE_UNORDERED(&monitored->monitors, idx); +- ast_debug(3, "Unregistered monitor %p(%p) from transport %s\n", +- notifier->cb, notifier->data, monitored->transport->obj_name); ++ ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Unregistered monitor %p(%p)\n", ++ monitored->key, monitored->transport_obj_name, ++ monitored->transport->type_name, ++ pj_atomic_get(monitored->transport->ref_cnt), notifier->cb, notifier->data); + } + } + return 0; +@@ -396,11 +428,19 @@ void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb + + void ast_sip_transport_monitor_unregister(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches) ++{ ++ char key[IP6ADDR_COLON_PORT_BUFLEN]; ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); ++ ast_sip_transport_monitor_unregister_key(key, cb, data, matches); ++} ++ ++void ast_sip_transport_monitor_unregister_key(const char *transport_key, ++ ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches) + { + struct ao2_container *transports; + struct transport_monitor *monitored; + +- ast_assert(transport != NULL && cb != NULL); ++ ast_assert(transport_key != NULL && cb != NULL); + + transports = ao2_global_obj_ref(active_transports); + if (!transports) { +@@ -408,7 +448,7 @@ void ast_sip_transport_monitor_unregister(pjsip_transport *transport, + } + + ao2_lock(transports); +- monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); ++ monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (monitored) { + struct callback_data cb_data = { + .cb = cb, +@@ -426,17 +466,35 @@ void ast_sip_transport_monitor_unregister(pjsip_transport *transport, + enum ast_transport_monitor_reg ast_sip_transport_monitor_register(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data) + { +- return ast_sip_transport_monitor_register_replace(transport, cb, ao2_data, NULL); ++ char key[IP6ADDR_COLON_PORT_BUFLEN]; ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); ++ ++ return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL); ++} ++ ++enum ast_transport_monitor_reg ast_sip_transport_monitor_register_key(const char *transport_key, ++ ast_transport_monitor_shutdown_cb cb, void *ao2_data) ++{ ++ return ast_sip_transport_monitor_register_replace_key(transport_key, cb, ao2_data, NULL); + } + + enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport, + ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches) ++{ ++ char key[IP6ADDR_COLON_PORT_BUFLEN]; ++ ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(transport, key); ++ return ast_sip_transport_monitor_register_replace_key(key, cb, ao2_data, NULL); ++} ++ ++enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key, ++ ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches) + { + struct ao2_container *transports; + struct transport_monitor *monitored; + enum ast_transport_monitor_reg res = AST_TRANSPORT_MONITOR_REG_NOT_FOUND; + +- ast_assert(transport != NULL && cb != NULL); ++ ast_assert(transport_key != NULL && cb != NULL); + + transports = ao2_global_obj_ref(active_transports); + if (!transports) { +@@ -444,7 +502,7 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_ + } + + ao2_lock(transports); +- monitored = ao2_find(transports, transport->obj_name, OBJ_SEARCH_KEY | OBJ_NOLOCK); ++ monitored = ao2_find(transports, transport_key, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (monitored) { + struct transport_monitor_notifier new_monitor; + struct callback_data cb_data = { +@@ -461,12 +519,15 @@ enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_ + if (AST_VECTOR_APPEND(&monitored->monitors, new_monitor)) { + ao2_cleanup(ao2_data); + res = AST_TRANSPORT_MONITOR_REG_FAILED; +- ast_debug(3, "Register monitor %p(%p) to transport %s FAILED\n", +- cb, ao2_data, transport->obj_name); ++ ast_debug(3, "Transport %s(%s) RefCnt: %ld : Monitor registration failed %p(%p)\n", ++ monitored->key, monitored->transport_obj_name, ++ pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data); + } else { + res = AST_TRANSPORT_MONITOR_REG_SUCCESS; +- ast_debug(3, "Registered monitor %p(%p) to transport %s\n", +- cb, ao2_data, transport->obj_name); ++ ast_debug(3, "Transport %s(%s,%s) RefCnt: %ld : Registered monitor %p(%p)\n", ++ monitored->key, monitored->transport_obj_name, ++ monitored->transport->type_name, ++ pj_atomic_get(monitored->transport->ref_cnt), cb, ao2_data); + } + + ao2_ref(monitored, -1); +@@ -499,10 +560,120 @@ void ast_sip_transport_state_register(struct ast_sip_tpmgr_state_callback *eleme + AST_RWLIST_UNLOCK(&transport_state_list); + } + ++static char *cli_show_monitors(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) ++{ ++ char *cli_rc = CLI_FAILURE; ++ int rc = 0; ++ int using_regex = 0; ++ regex_t regex = { 0, }; ++ int container_count; ++ struct ao2_iterator iter; ++ struct ao2_container *sorted_monitors = NULL; ++ struct ao2_container *transports; ++ struct transport_monitor *monitored; ++ ++ switch (cmd) { ++ case CLI_INIT: ++ e->command = "pjsip show transport-monitors"; ++ e->usage = "Usage: pjsip show transport-monitors [ like ]\n" ++ " Show pjsip transport monitors\n"; ++ return NULL; ++ case CLI_GENERATE: ++ return NULL; ++ } ++ ++ if (a->argc != 3 && a->argc != 5) { ++ return CLI_SHOWUSAGE; ++ } ++ ++ if (a->argc == 5) { ++ int regrc; ++ if (strcasecmp(a->argv[3], "like")) { ++ return CLI_SHOWUSAGE; ++ } ++ regrc = regcomp(®ex, a->argv[4], REG_EXTENDED | REG_ICASE | REG_NOSUB); ++ if (regrc) { ++ char err[256]; ++ regerror(regrc, ®ex, err, 256); ++ ast_cli(a->fd, "PJSIP Transport Monitor: Error: %s\n", err); ++ return CLI_FAILURE; ++ } ++ using_regex = 1; ++ } ++ ++ /* Get a sorted snapshot of the scheduled tasks */ ++ sorted_monitors = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, ++ transport_monitor_sort_fn, NULL); ++ if (!sorted_monitors) { ++ ast_cli(a->fd, "PJSIP Transport Monitor: Unable to allocate temporary container\n"); ++ goto error; ++ } ++ ++ transports = ao2_global_obj_ref(active_transports); ++ if (!transports) { ++ ast_cli(a->fd, "PJSIP Transport Monitor: Unable to get transports\n"); ++ goto error; ++ } ++ ++ ao2_lock(transports); ++ rc = ao2_container_dup(sorted_monitors, transports, 0); ++ ao2_unlock(transports); ++ ao2_ref(transports, -1); ++ if (rc != 0) { ++ ast_cli(a->fd, "PJSIP Transport Monitors: Unable to sort temporary container\n"); ++ goto error; ++ } ++ container_count = ao2_container_count(sorted_monitors); ++ ++ ast_cli(a->fd, "PJSIP Transport Monitors:\n\n"); ++ ++ ast_cli(a->fd, ++ " \n"); ++ ++ iter = ao2_iterator_init(sorted_monitors, AO2_ITERATOR_UNLINK); ++ for (; (monitored = ao2_iterator_next(&iter)); ao2_ref(monitored, -1)) { ++ char *state; ++ ++ if (using_regex && regexec(®ex, monitored->key, 0, NULL, 0) == REG_NOMATCH) { ++ continue; ++ } ++ ++ if (monitored->transport->is_destroying) { ++ state = "DESTROYING"; ++ } else if (monitored->transport->is_shutdown) { ++ state = "SHUTDOWN"; ++ } else { ++ state = "ACTIVE"; ++ } ++ ++ ast_cli(a->fd, " %-46.46s %-10s %-9s %6ld %8" PRIu64 " %s\n", ++ monitored->key, state, ++ monitored->transport->dir == PJSIP_TP_DIR_OUTGOING ? "Outgoing" : "Incoming", ++ pj_atomic_get(monitored->transport->ref_cnt), ++ AST_VECTOR_SIZE(&monitored->monitors), monitored->transport->obj_name); ++ } ++ ao2_iterator_destroy(&iter); ++ ast_cli(a->fd, "\nTotal Transport Monitors: %d\n\n", container_count); ++ cli_rc = CLI_SUCCESS; ++error: ++ if (using_regex) { ++ regfree(®ex); ++ } ++ ao2_cleanup(sorted_monitors); ++ ++ return cli_rc; ++} ++ ++static struct ast_cli_entry cli_commands[] = { ++ AST_CLI_DEFINE(cli_show_monitors, "Show pjsip transport monitors"), ++}; ++ + void ast_sip_destroy_transport_events(void) + { + pjsip_tpmgr *tpmgr; + ++ ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); ++ + tpmgr = pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()); + if (tpmgr) { + pjsip_tpmgr_set_state_cb(tpmgr, tpmgr_state_callback); +@@ -522,7 +693,7 @@ int ast_sip_initialize_transport_events(void) + } + + transports = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, +- ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, NULL, ++ ACTIVE_TRANSPORTS_BUCKETS, transport_monitor_hash_fn, transport_monitor_sort_fn, + transport_monitor_cmp_fn); + if (!transports) { + return -1; +@@ -533,5 +704,8 @@ int ast_sip_initialize_transport_events(void) + tpmgr_state_callback = pjsip_tpmgr_get_state_cb(tpmgr); + pjsip_tpmgr_set_state_cb(tpmgr, &transport_state_callback); + ++ ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands)); ++ ++ + return 0; + } +diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c +index b00221a..34e25fc 100644 +--- a/res/res_pjsip_outbound_registration.c ++++ b/res/res_pjsip_outbound_registration.c +@@ -803,6 +803,8 @@ struct registration_response { + pjsip_rx_data *rdata; + /*! \brief Request for which the response was received */ + pjsip_tx_data *old_request; ++ /*! \brief Key for the reliable transport in use */ ++ char transport_key[IP6ADDR_COLON_PORT_BUFLEN]; + }; + + /*! \brief Registration response structure destructor */ +@@ -918,13 +920,10 @@ static int monitor_matcher(void *a, void *b) + return strcmp(ma, mb) == 0; + } + +-static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name) ++static void registration_transport_monitor_setup(const char *transport_key, const char *registration_name) + { + char *monitor; + +- if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) { +- return; +- } + monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL, + AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!monitor) { +@@ -937,8 +936,8 @@ static void registration_transport_monitor_setup(pjsip_transport *transport, con + * register the monitor. We might get into a message spamming infinite + * loop of registration, shutdown, reregistration... + */ +- ast_sip_transport_monitor_register(transport, registration_transport_shutdown_cb, +- monitor); ++ ast_sip_transport_monitor_register_replace_key(transport_key, registration_transport_shutdown_cb, ++ monitor, monitor_matcher); + ao2_ref(monitor, -1); + } + +@@ -1022,14 +1021,18 @@ static int handle_registration_response(void *data) + schedule_registration(response->client_state, next_registration_round); + + /* See if we should monitor for transport shutdown */ +- registration_transport_monitor_setup(response->rdata->tp_info.transport, +- response->client_state->registration_name); ++ if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) { ++ registration_transport_monitor_setup(response->transport_key, ++ response->client_state->registration_name); ++ } + } else { + ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri); + update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED); +- ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport, +- registration_transport_shutdown_cb, response->client_state->registration_name, +- monitor_matcher); ++ if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) { ++ ast_sip_transport_monitor_unregister_key(response->transport_key, ++ registration_transport_shutdown_cb, response->client_state->registration_name, ++ monitor_matcher); ++ } + } + } else if (response->client_state->destroy) { + /* We need to deal with the pending destruction instead. */ +@@ -1143,6 +1146,9 @@ static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *par + response->old_request = tsx->last_tx; + pjsip_tx_data_add_ref(response->old_request); + pjsip_rx_data_clone(param->rdata, 0, &response->rdata); ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(param->rdata->tp_info.transport, ++ response->transport_key); ++ + } else { + /* old_request steals the reference */ + response->old_request = client_state->last_tdata; +diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c +index d0f3717..a10678d 100644 +--- a/res/res_pjsip_pubsub.c ++++ b/res/res_pjsip_pubsub.c +@@ -389,8 +389,8 @@ struct subscription_persistence { + char src_name[PJ_INET6_ADDRSTRLEN]; + /*! Source port of the message */ + int src_port; +- /*! Local transport key type */ +- char transport_key[32]; ++ /*! Local transport type (UDP,TCP,TLS)*/ ++ char transport_type[32]; + /*! Local transport address */ + char local_name[PJ_INET6_ADDRSTRLEN]; + /*! Local transport port */ +@@ -474,7 +474,7 @@ struct sip_subscription_tree { + /*! The transport the subscription was received on. + * Only used for reliable transports. + */ +- pjsip_transport *transport; ++ char transport_key[IP6ADDR_COLON_PORT_BUFLEN]; + /*! Indicator if initial notify should be generated. + * Used to refresh modified RLS. + */ +@@ -711,8 +711,9 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr + rdata->tp_info.transport->obj_name, + sub_tree->persistence->endpoint, sub_tree->root->resource, + sub_tree->persistence->prune_on_boot); +- sub_tree->transport = rdata->tp_info.transport; +- ast_sip_transport_monitor_register(rdata->tp_info.transport, ++ AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(rdata->tp_info.transport, ++ sub_tree->transport_key); ++ ast_sip_transport_monitor_register_key(sub_tree->transport_key, + sub_tree_transport_cb, sub_tree); + /* + * FYI: ast_sip_transport_monitor_register holds a reference to the sub_tree +@@ -746,8 +747,8 @@ static void subscription_persistence_update(struct sip_subscription_tree *sub_tr + ast_copy_string(sub_tree->persistence->src_name, rdata->pkt_info.src_name, + sizeof(sub_tree->persistence->src_name)); + sub_tree->persistence->src_port = rdata->pkt_info.src_port; +- ast_copy_string(sub_tree->persistence->transport_key, rdata->tp_info.transport->type_name, +- sizeof(sub_tree->persistence->transport_key)); ++ ast_copy_string(sub_tree->persistence->transport_type, rdata->tp_info.transport->type_name, ++ sizeof(sub_tree->persistence->transport_type)); + ast_copy_pj_str(sub_tree->persistence->local_name, &rdata->tp_info.transport->local_name.host, + sizeof(sub_tree->persistence->local_name)); + sub_tree->persistence->local_port = rdata->tp_info.transport->local_name.port; +@@ -763,12 +764,12 @@ static void subscription_persistence_remove(struct sip_subscription_tree *sub_tr + return; + } + +- if (sub_tree->persistence->prune_on_boot && sub_tree->transport) { ++ if (sub_tree->persistence->prune_on_boot && !ast_strlen_zero(sub_tree->transport_key)) { + ast_debug(3, "Unregistering transport monitor on %s '%s->%s'\n", +- sub_tree->transport->obj_name, ++ sub_tree->transport_key, + sub_tree->endpoint ? ast_sorcery_object_get_id(sub_tree->endpoint) : "Unknown", + sub_tree->root ? sub_tree->root->resource : "Unknown"); +- ast_sip_transport_monitor_unregister(sub_tree->transport, ++ ast_sip_transport_monitor_unregister_key(sub_tree->transport_key, + sub_tree_transport_cb, sub_tree, NULL); + } + +@@ -1743,7 +1744,7 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags) + rdata.tp_info.pool = pool; + + if (ast_sip_create_rdata_with_contact(&rdata, persistence->packet, persistence->src_name, +- persistence->src_port, persistence->transport_key, persistence->local_name, ++ persistence->src_port, persistence->transport_type, persistence->local_name, + persistence->local_port, persistence->contact_uri)) { + ast_log(LOG_WARNING, "Failed recreating '%s' subscription: The message could not be parsed\n", + persistence->endpoint); +@@ -5739,7 +5740,7 @@ static int load_module(void) + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "src_port", "0", OPT_UINT_T, 0, + FLDSET(struct subscription_persistence, src_port)); + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "transport_key", "0", OPT_CHAR_ARRAY_T, 0, +- CHARFLDSET(struct subscription_persistence, transport_key)); ++ CHARFLDSET(struct subscription_persistence, transport_type)); + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_name", "", OPT_CHAR_ARRAY_T, 0, + CHARFLDSET(struct subscription_persistence, local_name)); + ast_sorcery_object_field_register(sorcery, "subscription_persistence", "local_port", "0", OPT_UINT_T, 0, diff -Nru asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42706.patch asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42706.patch --- asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42706.patch 1970-01-01 00:00:00.000000000 +0000 +++ asterisk-16.28.0~dfsg/debian/patches/CVE-2022-42706.patch 2023-02-22 22:11:00.000000000 +0000 @@ -0,0 +1,166 @@ +From: Markus Koschany +Date: Wed, 22 Feb 2023 16:40:47 +0100 +Subject: CVE-2022-42706 + +Origin: https://downloads.asterisk.org/pub/security/AST-2022-009.html +--- + configs/samples/asterisk.conf.sample | 11 +++--- + .../manager_config_live_dangerously.txt | 8 +++++ + include/asterisk/manager.h | 12 +++++++ + main/manager.c | 42 ++++++++++++++++++++++ + main/options.c | 1 + + 5 files changed, 70 insertions(+), 4 deletions(-) + create mode 100644 doc/UPGRADE-staging/manager_config_live_dangerously.txt + +diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample +index efb3386..97f1e77 100644 +--- a/configs/samples/asterisk.conf.sample ++++ b/configs/samples/asterisk.conf.sample +@@ -95,10 +95,13 @@ documentation_language = en_US ; Set the language you want documentation + ; documented in extensions.conf.sample. + ; Default gosub. + ;live_dangerously = no ; Enable the execution of 'dangerous' dialplan +- ; functions from external sources (AMI, +- ; etc.) These functions (such as SHELL) are +- ; considered dangerous because they can allow +- ; privilege escalation. ++ ; functions and configuration file access from ++ ; external sources (AMI, etc.) These functions ++ ; (such as SHELL) are considered dangerous ++ ; because they can allow privilege escalation. ++ ; Configuration files are considered dangerous ++ ; if they exist outside of the Asterisk ++ ; configuration directory. + ; Default no + ;entityid=00:11:22:33:44:55 ; Entity ID. + ; This is in the form of a MAC address. +diff --git a/doc/UPGRADE-staging/manager_config_live_dangerously.txt b/doc/UPGRADE-staging/manager_config_live_dangerously.txt +new file mode 100644 +index 0000000..56f39f9 +--- /dev/null ++++ b/doc/UPGRADE-staging/manager_config_live_dangerously.txt +@@ -0,0 +1,8 @@ ++Subject: AMI (Asterisk Manager Interface) ++ ++Previously, GetConfig and UpdateConfig were able to access files outside of ++the Asterisk configuration directory. Now this access is put behind the ++live_dangerously configuration option in asterisk.conf, which is disabled by ++default. If access to configuration files outside of the Asterisk configuation ++directory is required via AMI, then the live_dangerously configuration option ++must be set to yes. +diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h +index 47b1759..8a8a00b 100644 +--- a/include/asterisk/manager.h ++++ b/include/asterisk/manager.h +@@ -350,6 +350,18 @@ void astman_send_list_complete_start(struct mansession *s, const struct message + */ + void astman_send_list_complete_end(struct mansession *s); + ++/*! ++ * \brief Enable/disable the inclusion of 'dangerous' configurations outside ++ * of the ast_config_AST_CONFIG_DIR ++ * ++ * This function can globally enable/disable the loading of configuration files ++ * outside of ast_config_AST_CONFIG_DIR. ++ * ++ * \param new_live_dangerously If true, enable the access of files outside ++ * ast_config_AST_CONFIG_DIR from astman. ++ */ ++void astman_live_dangerously(int new_live_dangerously); ++ + void __attribute__((format(printf, 2, 3))) astman_append(struct mansession *s, const char *fmt, ...); + + /*! \brief Determine if a manager session ident is authenticated */ +diff --git a/main/manager.c b/main/manager.c +index 2cc7c85..07c034a 100644 +--- a/main/manager.c ++++ b/main/manager.c +@@ -1505,6 +1505,11 @@ static struct stasis_forward *rtp_topic_forwarder; + /*! \brief The \ref stasis_subscription for forwarding the Security topic to the AMI topic */ + static struct stasis_forward *security_topic_forwarder; + ++/*! ++ * \brief Set to true (non-zero) to globally allow all dangerous AMI actions to run ++ */ ++static int live_dangerously; ++ + #ifdef TEST_FRAMEWORK + /*! \brief The \ref stasis_subscription for forwarding the Test topic to the AMI topic */ + static struct stasis_forward *test_suite_forwarder; +@@ -3624,6 +3629,29 @@ static int action_ping(struct mansession *s, const struct message *m) + return 0; + } + ++void astman_live_dangerously(int new_live_dangerously) ++{ ++ if (new_live_dangerously && !live_dangerously) ++ { ++ ast_log(LOG_WARNING, "Manager Configuration load protection disabled.\n"); ++ } ++ ++ if (!new_live_dangerously && live_dangerously) ++ { ++ ast_log(LOG_NOTICE, "Manager Configuration load protection enabled.\n"); ++ } ++ live_dangerously = new_live_dangerously; ++} ++ ++static int restrictedFile(const char *filename) ++{ ++ if (!live_dangerously && !strncasecmp(filename, "/", 1) && ++ strncasecmp(filename, ast_config_AST_CONFIG_DIR, strlen(ast_config_AST_CONFIG_DIR))) { ++ return 1; ++ } ++ return 0; ++} ++ + static int action_getconfig(struct mansession *s, const struct message *m) + { + struct ast_config *cfg; +@@ -3642,6 +3670,11 @@ static int action_getconfig(struct mansession *s, const struct message *m) + return 0; + } + ++ if (restrictedFile(fn)) { ++ astman_send_error(s, m, "File requires escalated priveledges"); ++ return 0; ++ } ++ + cfg = ast_config_load2(fn, "manager", config_flags); + if (cfg == CONFIG_STATUS_FILEMISSING) { + astman_send_error(s, m, "Config file not found"); +@@ -3769,6 +3802,11 @@ static int action_getconfigjson(struct mansession *s, const struct message *m) + return 0; + } + ++ if (restrictedFile(fn)) { ++ astman_send_error(s, m, "File requires escalated priveledges"); ++ return 0; ++ } ++ + if (!(cfg = ast_config_load2(fn, "manager", config_flags))) { + astman_send_error(s, m, "Config file not found"); + return 0; +@@ -4120,6 +4158,10 @@ static int action_updateconfig(struct mansession *s, const struct message *m) + astman_send_error(s, m, "Filename not specified"); + return 0; + } ++ if (restrictedFile(sfn) || restrictedFile(dfn)) { ++ astman_send_error(s, m, "File requires escalated priveledges"); ++ return 0; ++ } + if (!(cfg = ast_config_load2(sfn, "manager", config_flags))) { + astman_send_error(s, m, "Config file not found"); + return 0; +diff --git a/main/options.c b/main/options.c +index 11c2cf9..217588e 100644 +--- a/main/options.c ++++ b/main/options.c +@@ -483,6 +483,7 @@ void load_asterisk_conf(void) + } + if (!ast_opt_remote) { + pbx_live_dangerously(live_dangerously); ++ astman_live_dangerously(live_dangerously); + } + + option_debug += option_debug_new; diff -Nru asterisk-16.28.0~dfsg/debian/patches/series asterisk-16.28.0~dfsg/debian/patches/series --- asterisk-16.28.0~dfsg/debian/patches/series 2022-11-17 11:46:39.000000000 +0000 +++ asterisk-16.28.0~dfsg/debian/patches/series 2023-02-22 22:11:00.000000000 +0000 @@ -16,3 +16,6 @@ ffmpeg-includes.patch reproducible-build.patch autoreconf-pjproject.patch +CVE-2022-37325.patch +CVE-2022-42705.patch +CVE-2022-42706.patch Binary files /srv/release.debian.org/tmp/PLkfOsVmaz/asterisk-16.28.0~dfsg/debian/pjproject_2.12.1~dfsg.orig.tar.bz2 and /srv/release.debian.org/tmp/Zf1XepuSfN/asterisk-16.28.0~dfsg/debian/pjproject_2.12.1~dfsg.orig.tar.bz2 differ