diff --git a/libs/pjproject/Makefile b/libs/pjproject/Makefile index 31cdb82..c349657 100644 --- a/libs/pjproject/Makefile +++ b/libs/pjproject/Makefile @@ -9,12 +9,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=pjproject -PKG_VERSION:=2.4.5 +PKG_VERSION:=2.7.1 PKG_RELEASE:=1 PKG_SOURCE:=pjproject-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=http://www.pjsip.org/release/$(PKG_VERSION)/ -PKG_MD5SUM:=f58b3485977b3a700256203a554b3869 +PKG_MD5SUM:=99a64110fa5c2debff40e0e8d4676380 PKG_INSTALL:=1 PKG_FIXUP:=autoreconf @@ -31,7 +31,7 @@ define Package/pjproject/Default CATEGORY:=Libraries SUBMENU:=Telephony URL:=http://www.pjsip.org/ - DEPENDS:=+libuuid +libstdcpp +libpthread + DEPENDS:=+libopenssl +libuuid +libstdcpp +libpthread endef define Package/pjproject/install/lib @@ -54,46 +54,47 @@ $(call Package/pjproject/install/lib,$$(1),$2) endef CONFIGURE_ARGS += \ - --enable-shared \ - --disable-floating-point \ - --enable-g711-codec \ - --disable-l16-codec \ - --disable-g722-codec \ - --disable-g7221-codec \ - --disable-gsm-codec \ - --disable-ilbc-coder \ - --disable-ipp \ - --disable-ssl \ - --disable-oss \ - --disable-sound \ - --with-external-srtp="$(STAGING_DIR)/usr" \ - --without-external-gsm \ - --disable-small-filter \ - --disable-large-filter \ - --disable-speex-aec \ - --disable-g711-codec \ - --disable-l16-codec \ - --disable-gsm-codec \ - --disable-g722-codec \ - --disable-g7221-codec \ - --disable-speex-codec \ - --disable-ilbc-codec \ - --disable-resample-dll \ - --disable-sdl \ + $(if $(CONFIG_SOFT_FLOAT),--disable-floating-point) \ + --disable-bcg729 \ + --disable-ext-sound \ --disable-ffmpeg \ - --disable-v4l2 + --disable-g711-codec \ + --disable-g722-codec \ + --disable-g7221-codec \ + --disable-gsm-codec \ + --disable-ilbc-codec \ + --disable-ipp \ + --disable-l16-codec \ + --disable-libwebrtc \ + --disable-libyuv \ + --disable-opencore-amr \ + --disable-openh264 \ + --disable-opus \ + --disable-oss \ + --disable-resample \ + --disable-sdl \ + --disable-silk \ + --disable-sound \ + --disable-speex-aec \ + --disable-speex-codec \ + --disable-v4l2 \ + --disable-video \ + --enable-shared \ + --with-external-srtp="$(STAGING_DIR)/usr" \ + --with-ssl="$(STAGING_DIR)/usr" \ + --without-external-gsm \ + --without-external-pa \ + --without-external-webrtc -TARGET_LDFLAGS+=-lc $(LIBGCC) -lm -TARGET_CFLAGS+=$(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS) +TARGET_CFLAGS+=$(TARGET_CPPFLAGS) define Build/Compile $(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) endef PJPROJECT_LIBS = \ - libpj libpjlib-util libpjmedia-audiodev libpjmedia-codec \ - libpjmedia-videodev libpjmedia libpjnath libpjsip-simple \ - libpjsip-ua libpjsip libpjsua libpjsua2 libresample + libpj libpjlib-util libpjmedia libpjnath libpjsip-simple \ + libpjsip-ua libpjsip libpjsua libpjsua2 define Build/InstallDev $(INSTALL_DIR) $(1)/usr/{include,lib} @@ -102,16 +103,16 @@ define Build/InstallDev $(foreach m,$(PJPROJECT_LIBS),$(CP) $(PKG_INSTALL_DIR)/usr/lib/$(m)* $(1)/usr/lib/;) $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(SED) 's|$(TARGET_CFLAGS)||g' $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libpjproject.pc $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libpjproject.pc $(1)/usr/lib/pkgconfig/ endef $(eval $(call PJSIPpackage,libpj,libpj,+librt)) $(eval $(call PJSIPpackage,libpjlib-util,libpjlib-util,+libpj +librt)) -$(eval $(call PJSIPpackage,libpjmedia,libpjmedia*,+libpj +libpjlib-util +libpjnath +libresample +librt +libspeex +libsrtp)) +$(eval $(call PJSIPpackage,libpjmedia,libpjmedia*,+libpj +libpjlib-util +libpjnath +librt +libsrtp)) $(eval $(call PJSIPpackage,libpjnath,libpjnath,+libpj +libpjlib-util +librt)) -$(eval $(call PJSIPpackage,libpjsip-simple,libpjsip-simple,+libpj +libpjlib-util +libpjsip +libresample +librt +libspeex +libsrtp)) -$(eval $(call PJSIPpackage,libpjsip-ua,libpjsip-ua,+libpj +libpjlib-util +libpjmedia +libpjsip-simple +libpjsip +libresample +librt +libspeex +libsrtp)) -$(eval $(call PJSIPpackage,libpjsip,libpjsip,+libpj +libpjlib-util +libresample +librt +libspeex +libsrtp)) -$(eval $(call PJSIPpackage,libpjsua,libpjsua,+libpj +libpjlib-util +libpjmedia +libpjnath +libpjsip-simple +libpjsip-ua +libpjsip +libresample +librt +libspeex +libsrtp)) -$(eval $(call PJSIPpackage,libpjsua2,libpjsua2,+libpj +libpjlib-util +libpjmedia +libpjnath +libpjsip-simple +libpjsip-ua +libpjsip +libresample +librt +libspeex +libsrtp +libpjsua)) -$(eval $(call PJSIPpackage,libresample,libresample,)) +$(eval $(call PJSIPpackage,libpjsip-simple,libpjsip-simple,+libpj +libpjlib-util +libpjsip +librt)) +$(eval $(call PJSIPpackage,libpjsip-ua,libpjsip-ua,+libpj +libpjlib-util +libpjmedia +libpjsip-simple +libpjsip +librt)) +$(eval $(call PJSIPpackage,libpjsip,libpjsip,+libpj +libpjlib-util +librt +libsrtp)) +$(eval $(call PJSIPpackage,libpjsua,libpjsua,+libpj +libpjlib-util +libpjmedia +libpjnath +libpjsip-simple +libpjsip-ua +libpjsip +librt)) +$(eval $(call PJSIPpackage,libpjsua2,libpjsua2,+libpj +libpjlib-util +libpjmedia +libpjnath +libpjsip-simple +libpjsip-ua +libpjsip +librt +libpjsua)) diff --git a/libs/pjproject/patches/120-non-gnu-pthreads.patch b/libs/pjproject/patches/120-non-gnu-pthreads.patch index e01b542..23a9b3f 100644 --- a/libs/pjproject/patches/120-non-gnu-pthreads.patch +++ b/libs/pjproject/patches/120-non-gnu-pthreads.patch @@ -1,7 +1,5 @@ -Index: pjproject-2.4/pjlib/src/pj/os_core_unix.c -=================================================================== ---- pjproject-2.4.orig/pjlib/src/pj/os_core_unix.c -+++ pjproject-2.4/pjlib/src/pj/os_core_unix.c +--- pjproject-2.6/pjlib/src/pj/os_core_unix.c 2016-04-13 08:24:48.000000000 +0200 ++++ pjproject-new/pjlib/src/pj/os_core_unix.c 2017-05-08 09:51:49.980905420 +0200 @@ -1123,7 +1123,7 @@ static pj_status_t init_mutex(pj_mutex_t return PJ_RETURN_OS_ERROR(rc); @@ -9,7 +7,7 @@ Index: pjproject-2.4/pjlib/src/pj/os_core_unix.c -#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \ +#if (defined(PJ_LINUX) && PJ_LINUX!=0 && defined(__GLIBC__)) || \ defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE) - rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP); + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); #elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \ @@ -1133,7 +1133,7 @@ static pj_status_t init_mutex(pj_mutex_t rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); @@ -18,49 +16,5 @@ Index: pjproject-2.4/pjlib/src/pj/os_core_unix.c -#if (defined(PJ_LINUX) && PJ_LINUX!=0) || \ +#if (defined(PJ_LINUX) && PJ_LINUX!=0 && defined(__GLIBC__)) || \ defined(PJ_HAS_PTHREAD_MUTEXATTR_SETTYPE) - rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); #elif (defined(PJ_RTEMS) && PJ_RTEMS!=0) || \ -Index: pjproject-2.4/pjsip-apps/src/samples/siprtp.c -=================================================================== ---- pjproject-2.4.orig/pjsip-apps/src/samples/siprtp.c -+++ pjproject-2.4/pjsip-apps/src/samples/siprtp.c -@@ -1134,7 +1134,7 @@ static void boost_priority(void) - PJ_RETURN_OS_ERROR(rc)); - return; - } -- tp.__sched_priority = max_prio; -+ tp.sched_priority = max_prio; - - rc = sched_setscheduler(0, POLICY, &tp); - if (rc != 0) { -@@ -1143,7 +1143,7 @@ static void boost_priority(void) - } - - PJ_LOG(4, (THIS_FILE, "New process policy=%d, priority=%d", -- policy, tp.__sched_priority)); -+ policy, tp.sched_priority)); - - /* - * Adjust thread scheduling algorithm and priority -@@ -1156,10 +1156,10 @@ static void boost_priority(void) - } - - PJ_LOG(4, (THIS_FILE, "Old thread policy=%d, priority=%d", -- policy, tp.__sched_priority)); -+ policy, tp.sched_priority)); - - policy = POLICY; -- tp.__sched_priority = max_prio; -+ tp.sched_priority = max_prio; - - rc = pthread_setschedparam(pthread_self(), policy, &tp); - if (rc != 0) { -@@ -1169,7 +1169,7 @@ static void boost_priority(void) - } - - PJ_LOG(4, (THIS_FILE, "New thread policy=%d, priority=%d", -- policy, tp.__sched_priority)); -+ policy, tp.sched_priority)); - } - - #else diff --git a/libs/pjproject/patches/150-config_site.patch b/libs/pjproject/patches/150-config_site.patch new file mode 100644 index 0000000..5805137 --- /dev/null +++ b/libs/pjproject/patches/150-config_site.patch @@ -0,0 +1,95 @@ +--- /dev/null ++++ b/pjlib/include/pj/config_site.h +@@ -0,0 +1,92 @@ ++/* ++ * Asterisk config_site.h ++ */ ++ ++#include ++ ++/* ++ * Since both pjproject and asterisk source files will include config_site.h, ++ * we need to make sure that only pjproject source files include asterisk_malloc_debug.h. ++ */ ++ ++/* #if defined(MALLOC_DEBUG) && !defined(_ASTERISK_ASTMM_H) ++ * #include "asterisk_malloc_debug.h" ++ * #endif ++ */ ++ ++/* ++ * Defining PJMEDIA_HAS_SRTP to 0 does NOT disable Asterisk's ability to use srtp. ++ * It only disables the pjmedia srtp transport which Asterisk doesn't use. ++ * The reason for the disable is that while Asterisk works fine with older libsrtp ++ * versions, newer versions of pjproject won't compile with them. ++ */ ++ ++/* ++ * This doesn't disable SRTP completely, so we have to keep using the external ++ * libsrtp, otherwise pjsip would just build the internal one. ++ */ ++ ++#define PJMEDIA_HAS_SRTP 0 ++ ++/* ++ * Defining PJMEDIA_HAS_WEBRTC_AEC to 0 does NOT disable Asterisk's ability to use ++ * webrtc. It only disables the pjmedia webrtc transport which Asterisk doesn't use. ++ */ ++#define PJMEDIA_HAS_WEBRTC_AEC 0 ++ ++#define PJ_HAS_IPV6 1 ++#define NDEBUG 1 ++#define PJ_MAX_HOSTNAME (256) ++#define PJSIP_MAX_URL_SIZE (512) ++#ifdef PJ_HAS_LINUX_EPOLL ++#define PJ_IOQUEUE_MAX_HANDLES (5000) ++#else ++#define PJ_IOQUEUE_MAX_HANDLES (FD_SETSIZE) ++#endif ++#define PJ_IOQUEUE_HAS_SAFE_UNREG 1 ++#define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL (16) ++ ++#define PJ_SCANNER_USE_BITWISE 0 ++#define PJ_OS_HAS_CHECK_STACK 0 ++ ++#ifndef PJ_LOG_MAX_LEVEL ++#define PJ_LOG_MAX_LEVEL 6 ++#endif ++ ++#define PJ_ENABLE_EXTRA_CHECK 1 ++#define PJSIP_MAX_TSX_COUNT ((64*1024)-1) ++#define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1) ++#define PJSIP_UDP_SO_SNDBUF_SIZE (512*1024) ++#define PJSIP_UDP_SO_RCVBUF_SIZE (512*1024) ++#define PJ_DEBUG 0 ++#define PJSIP_SAFE_MODULE 0 ++#define PJ_HAS_STRICMP_ALNUM 0 ++ ++/* ++ * Do not ever enable PJ_HASH_USE_OWN_TOLOWER because the algorithm is ++ * inconsistently used when calculating the hash value and doesn't ++ * convert the same characters as pj_tolower()/tolower(). Thus you ++ * can get different hash values if the string hashed has certain ++ * characters in it. (ASCII '@', '[', '\\', ']', '^', and '_') ++ */ ++#undef PJ_HASH_USE_OWN_TOLOWER ++ ++/* ++ It is imperative that PJSIP_UNESCAPE_IN_PLACE remain 0 or undefined. ++ Enabling it will result in SEGFAULTS when URIs containing escape sequences are encountered. ++*/ ++#undef PJSIP_UNESCAPE_IN_PLACE ++#define PJSIP_MAX_PKT_LEN 6000 ++ ++#undef PJ_TODO ++#define PJ_TODO(x) ++ ++/* Defaults too low for WebRTC */ ++#define PJ_ICE_MAX_CAND 32 ++#define PJ_ICE_MAX_CHECKS (PJ_ICE_MAX_CAND * PJ_ICE_MAX_CAND) ++ ++/* Increase limits to allow more formats */ ++#define PJMEDIA_MAX_SDP_FMT 64 ++#define PJMEDIA_MAX_SDP_BANDW 4 ++#define PJMEDIA_MAX_SDP_ATTR (PJMEDIA_MAX_SDP_FMT*2 + 4) ++#define PJMEDIA_MAX_SDP_MEDIA 16 diff --git a/net/asterisk-11.x/Makefile b/net/asterisk-11.x/Makefile index 064a47a..28220e9 100644 --- a/net/asterisk-11.x/Makefile +++ b/net/asterisk-11.x/Makefile @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=asterisk11 PKG_VERSION:=11.22.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=asterisk-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://downloads.asterisk.org/pub/telephony/asterisk/releases/ @@ -146,6 +146,20 @@ $(foreach m,$(AST_EMB_MODULES),$(call Package/asterisk11/install/module,$(1),$(m $(INSTALL_BIN) ./files/asterisk.init $(1)/etc/init.d/asterisk endef +define Package/$(PKG_NAME)/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + echo + echo "o-------------------------------------------------------------------o" + echo "| Asterisk 11 WARNING |" + echo "o-------------------------------------------------------------------o" + echo "| Asterisk 11 is end-of-life. You should upgrade to Asterisk 13. |" + echo "o-------------------------------------------------------------=^_^=-o" + echo +fi +exit 0 +endef + define Package/asterisk11-sounds $(call Package/asterisk11/Default) TITLE:=Sounds support diff --git a/net/asterisk-11.x/patches/054-AST-2016-007.patch b/net/asterisk-11.x/patches/054-AST-2016-007.patch new file mode 100644 index 0000000..ae61d9d --- /dev/null +++ b/net/asterisk-11.x/patches/054-AST-2016-007.patch @@ -0,0 +1,117 @@ +From a503e4879cab7e35069e5481e0864b64b55e223d Mon Sep 17 00:00:00 2001 +From: Corey Farrell +Date: Mon, 8 Aug 2016 08:47:12 -0400 +Subject: [PATCH] Prevent leak of dialog RTP/SRTP instances. + +In some scenarios dialog_initialize_rtp can be called multiple times on +the same dialog. This can cause RTP instances to be leaked along with +multiple file descriptors for each instance. + +ASTERISK-26272 #close + +Change-Id: Id716c2b87762d890c062b42538524a95067018a8 +--- + channels/chan_sip.c | 61 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 39 insertions(+), 22 deletions(-) + +diff --git a/channels/chan_sip.c b/channels/chan_sip.c +index 9eaed58..2c29c9e 100644 +--- a/channels/chan_sip.c ++++ b/channels/chan_sip.c +@@ -5697,6 +5697,38 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket + *to_sock = *from_sock; + } + ++/*! Cleanup the RTP and SRTP portions of a dialog ++ * ++ * \note This procedure excludes vsrtp as it is initialized differently. ++ */ ++static void dialog_clean_rtp(struct sip_pvt *p) ++{ ++ if (p->rtp) { ++ ast_rtp_instance_destroy(p->rtp); ++ p->rtp = NULL; ++ } ++ ++ if (p->vrtp) { ++ ast_rtp_instance_destroy(p->vrtp); ++ p->vrtp = NULL; ++ } ++ ++ if (p->trtp) { ++ ast_rtp_instance_destroy(p->trtp); ++ p->trtp = NULL; ++ } ++ ++ if (p->srtp) { ++ sip_srtp_destroy(p->srtp); ++ p->srtp = NULL; ++ } ++ ++ if (p->tsrtp) { ++ sip_srtp_destroy(p->tsrtp); ++ p->tsrtp = NULL; ++ } ++} ++ + /*! \brief Initialize DTLS-SRTP support on an RTP instance */ + static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct sip_srtp **srtp) + { +@@ -5744,6 +5776,9 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) + return 0; + } + ++ /* Make sure previous RTP instances/FD's do not leak */ ++ dialog_clean_rtp(dialog); ++ + ast_sockaddr_copy(&bindaddr_tmp, &bindaddr); + if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) { + return -1; +@@ -6408,18 +6443,10 @@ static void sip_pvt_dtor(void *vdoomed) + ast_free(p->notify); + p->notify = NULL; + } +- if (p->rtp) { +- ast_rtp_instance_destroy(p->rtp); +- p->rtp = NULL; +- } +- if (p->vrtp) { +- ast_rtp_instance_destroy(p->vrtp); +- p->vrtp = NULL; +- } +- if (p->trtp) { +- ast_rtp_instance_destroy(p->trtp); +- p->trtp = NULL; +- } ++ ++ /* Free RTP and SRTP instances */ ++ dialog_clean_rtp(p); ++ + if (p->udptl) { + ast_udptl_destroy(p->udptl); + p->udptl = NULL; +@@ -6455,21 +6482,11 @@ static void sip_pvt_dtor(void *vdoomed) + + destroy_msg_headers(p); + +- if (p->srtp) { +- sip_srtp_destroy(p->srtp); +- p->srtp = NULL; +- } +- + if (p->vsrtp) { + sip_srtp_destroy(p->vsrtp); + p->vsrtp = NULL; + } + +- if (p->tsrtp) { +- sip_srtp_destroy(p->tsrtp); +- p->tsrtp = NULL; +- } +- + if (p->directmediaacl) { + p->directmediaacl = ast_free_acl_list(p->directmediaacl); + } +-- +2.5.5 + diff --git a/net/asterisk-11.x/patches/055-AST-2016-009-11.diff b/net/asterisk-11.x/patches/055-AST-2016-009-11.diff new file mode 100644 index 0000000..421da37 --- /dev/null +++ b/net/asterisk-11.x/patches/055-AST-2016-009-11.diff @@ -0,0 +1,27 @@ +diff --git a/channels/chan_sip.c b/channels/chan_sip.c +index 556db57..9c74acb 100644 +--- a/channels/chan_sip.c ++++ b/channels/chan_sip.c +@@ -8132,8 +8132,6 @@ static const char *__get_header(const struct sip_request *req, const char *name, + * one afterwards. If you shouldn't do it, what absolute idiot decided it was + * a good idea to say you can do it, and if you can do it, why in the hell would. + * you say you shouldn't. +- * Anyways, pedanticsipchecking controls whether we allow spaces before ':', +- * and we always allow spaces after that for compatibility. + */ + const char *sname = find_alias(name, NULL); + int x, len = strlen(name), slen = (sname ? 1 : 0); +@@ -8146,10 +8144,10 @@ static const char *__get_header(const struct sip_request *req, const char *name, + if (match || smatch) { + /* skip name */ + const char *r = header + (match ? len : slen ); +- if (sip_cfg.pedanticsipchecking) { +- r = ast_skip_blanks(r); ++ /* HCOLON has optional SP/HTAB; skip past those */ ++ while (*r == ' ' || *r == '\t') { ++ ++r; + } +- + if (*r == ':') { + *start = x+1; + return ast_skip_blanks(r+1); diff --git a/net/asterisk-11.x/patches/056-AST-2017-005-11.diff b/net/asterisk-11.x/patches/056-AST-2017-005-11.diff new file mode 100644 index 0000000..c263efd --- /dev/null +++ b/net/asterisk-11.x/patches/056-AST-2017-005-11.diff @@ -0,0 +1,195 @@ +From dc4c130439f053592b86f0b35c1fb219a0dc6587 Mon Sep 17 00:00:00 2001 +From: Joshua Colp +Date: Mon, 22 May 2017 15:36:38 +0000 +Subject: [PATCH] res_rtp_asterisk: Only learn a new source in learn state. + +This change moves the logic which learns a new source address +for RTP so it only occurs in the learning state. The learning +state is entered on initial allocation of RTP or if we are +told that the remote address for the media has changed. While +in the learning state if we continue to receive media from +the original source we restart the learning process. It is +only once we receive a sufficient number of RTP packets from +the new source that we will switch to it. Once this is done +the closed state is entered where all packets that do not +originate from the expected source are dropped. + +The learning process has also been improved to take into +account the time between received packets so a flood of them +while in the learning state does not cause media to be switched. + +Finally RTCP now drops packets which are not for the learned +SSRC if strict RTP is enabled. + +ASTERISK-27013 + +Change-Id: I56a96e993700906355e79bc880ad9d4ad3ab129c +--- + +diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c +index 4cdc750..4881171 100644 +--- a/res/res_rtp_asterisk.c ++++ b/res/res_rtp_asterisk.c +@@ -201,6 +201,7 @@ + struct rtp_learning_info { + int max_seq; /*!< The highest sequence number received */ + int packets; /*!< The number of remaining packets before the source is accepted */ ++ struct timeval received; /*!< The time of the last received packet */ + }; + + #ifdef HAVE_OPENSSL_SRTP +@@ -286,7 +287,6 @@ + * but these are in place to keep learning mode sequence values sealed from their normal counterparts. + */ + struct rtp_learning_info rtp_source_learn; /* Learning mode track for the expected RTP source */ +- struct rtp_learning_info alt_source_learn; /* Learning mode tracking for a new RTP source after one has been chosen */ + + struct rtp_red *red; + +@@ -2357,6 +2357,7 @@ + { + info->max_seq = seq - 1; + info->packets = learning_min_sequential; ++ memset(&info->received, 0, sizeof(info->received)); + } + + /*! +@@ -2371,6 +2372,13 @@ + */ + static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq) + { ++ if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) { ++ /* During the probation period the minimum amount of media we'll accept is ++ * 10ms so give a reasonable 5ms buffer just in case we get it sporadically. ++ */ ++ return 1; ++ } ++ + if (seq == info->max_seq + 1) { + /* packet is in sequence */ + info->packets--; +@@ -2379,6 +2387,7 @@ + info->packets = learning_min_sequential - 1; + } + info->max_seq = seq; ++ info->received = ast_tvnow(); + + return (info->packets == 0); + } +@@ -2540,7 +2549,6 @@ + rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); + if (strictrtp) { + rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); +- rtp_learning_seq_init(&rtp->alt_source_learn, (uint16_t)rtp->seqno); + } + + /* Create a new socket for us to listen on and use */ +@@ -3910,16 +3918,6 @@ + + packetwords = res / 4; + +- if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { +- /* Send to whoever sent to us */ +- if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) { +- ast_sockaddr_copy(&rtp->rtcp->them, &addr); +- if (rtpdebug) +- ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", +- ast_sockaddr_stringify(&rtp->rtcp->them)); +- } +- } +- + ast_debug(1, "Got RTCP report of %d bytes\n", res); + + while (position < packetwords) { +@@ -3939,6 +3937,24 @@ + if (rtpdebug) + ast_debug(1, "RTCP Read too short\n"); + return &ast_null_frame; ++ } ++ ++ if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (ntohl(rtcpheader[i + 1]) != rtp->themssrc)) { ++ /* Skip over this RTCP record as it does not contain the correct SSRC */ ++ position += (length + 1); ++ ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n", ++ rtp, ast_sockaddr_stringify(&addr), ntohl(rtcpheader[i + 1]), rtp->themssrc); ++ continue; ++ } ++ ++ if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) { ++ /* Send to whoever sent to us */ ++ if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) { ++ ast_sockaddr_copy(&rtp->rtcp->them, &addr); ++ if (rtpdebug) ++ ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n", ++ ast_sockaddr_stringify(&rtp->rtcp->them)); ++ } + } + + if (rtcp_debug_test_addr(&addr)) { +@@ -4330,24 +4346,11 @@ + + /* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */ + if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { +- ast_debug(1, "%p -- Probation learning mode pass with source address %s\n", rtp, ast_sockaddr_stringify(&addr)); +- /* For now, we always copy the address. */ +- ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); +- +- /* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/ +- if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { +- ast_debug(1, "%p -- Probation at seq %d with %d to go; discarding frame\n", +- rtp, rtp->rtp_source_learn.max_seq, rtp->rtp_source_learn.packets); +- return &ast_null_frame; +- } +- +- ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); +- rtp->strict_rtp_state = STRICT_RTP_CLOSED; +- } +- if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) { + if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { +- /* Always reset the alternate learning source */ +- rtp_learning_seq_init(&rtp->alt_source_learn, seqno); ++ /* We are learning a new address but have received traffic from the existing address, ++ * accept it but reset the current learning for the new source so it only takes over ++ * once sufficient traffic has been received. */ ++ rtp_learning_seq_init(&rtp->rtp_source_learn, seqno); + } else { + /* Hmm, not the strict address. Perhaps we're getting audio from the alternate? */ + if (!ast_sockaddr_cmp(&rtp->alt_rtp_address, &addr)) { +@@ -4359,15 +4362,21 @@ + * it, that means we've stopped getting RTP from the original source and we should + * switch to it. + */ +- if (rtp_learning_rtp_seq_update(&rtp->alt_source_learn, seqno)) { ++ if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) { + ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n", +- rtp, ast_sockaddr_stringify(&addr), rtp->alt_source_learn.packets); ++ rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets); + return &ast_null_frame; + } +- ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); + ast_sockaddr_copy(&rtp->strict_rtp_address, &addr); + } ++ ++ ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr)); ++ rtp->strict_rtp_state = STRICT_RTP_CLOSED; + } ++ } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) { ++ ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n", ++ rtp, ast_sockaddr_stringify(&addr)); ++ return &ast_null_frame; + } + + /* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */ +@@ -4762,7 +4771,11 @@ + + rtp->rxseqno = 0; + +- if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) { ++ if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) && ++ ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) { ++ /* We only need to learn a new strict source address if we've been told the source is ++ * changing to something different. ++ */ + rtp->strict_rtp_state = STRICT_RTP_LEARN; + rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno); + } diff --git a/net/asterisk-11.x/patches/057-AST-2017-006-11.diff b/net/asterisk-11.x/patches/057-AST-2017-006-11.diff new file mode 100644 index 0000000..ce8ed7a --- /dev/null +++ b/net/asterisk-11.x/patches/057-AST-2017-006-11.diff @@ -0,0 +1,397 @@ +From 31676ce058596b57e10fbf83ff1817ca7907c3b1 Mon Sep 17 00:00:00 2001 +From: Corey Farrell +Date: Sat, 01 Jul 2017 20:24:27 -0400 +Subject: [PATCH] AST-2017-006: Fix app_minivm application MinivmNotify command injection + +An admin can configure app_minivm with an externnotify program to be run +when a voicemail is received. The app_minivm application MinivmNotify +uses ast_safe_system() for this purpose which is vulnerable to command +injection since the Caller-ID name and number values given to externnotify +can come from an external untrusted source. + +* Add ast_safe_execvp() function. This gives modules the ability to run +external commands with greater safety compared to ast_safe_system(). +Specifically when some parameters are filled by untrusted sources the new +function does not allow malicious input to break argument encoding. This +may be of particular concern where CALLERID(name) or CALLERID(num) may be +used as a parameter to a script run by ast_safe_system() which could +potentially allow arbitrary command execution. + +* Changed app_minivm.c:run_externnotify() to use the new ast_safe_execvp() +instead of ast_safe_system() to avoid command injection. + +* Document code injection potential from untrusted data sources for other +shell commands that are under user control. + +ASTERISK-27103 + +Change-Id: I7552472247a84cde24e1358aaf64af160107aef1 +--- + +diff --git a/README-SERIOUSLY.bestpractices.txt b/README-SERIOUSLY.bestpractices.txt +index 281d0d3..d63f1df 100644 +--- a/README-SERIOUSLY.bestpractices.txt ++++ b/README-SERIOUSLY.bestpractices.txt +@@ -94,6 +94,13 @@ + ways in which you can mitigate this impact: stricter pattern matching, or using + the FILTER() dialplan function. + ++The CALLERID(num) and CALLERID(name) values are other commonly used values that ++are sources of data potentially supplied by outside sources. If you use these ++values as parameters to the System(), MixMonitor(), or Monitor() applications ++or the SHELL() dialplan function, you can allow injection of arbitrary operating ++system command execution. The FILTER() dialplan function is available to remove ++dangerous characters from untrusted strings to block the command injection. ++ + Strict Pattern Matching + ----------------------- + +diff --git a/apps/app_minivm.c b/apps/app_minivm.c +index ecdf9c6..8edc132 100644 +--- a/apps/app_minivm.c ++++ b/apps/app_minivm.c +@@ -1741,21 +1741,35 @@ + /*! \brief Run external notification for voicemail message */ + static void run_externnotify(struct ast_channel *chan, struct minivm_account *vmu) + { +- char arguments[BUFSIZ]; ++ char fquser[AST_MAX_CONTEXT * 2]; ++ char *argv[5] = { NULL }; ++ struct ast_party_caller *caller; ++ char *cid; ++ int idx; + +- if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify)) ++ if (ast_strlen_zero(vmu->externnotify) && ast_strlen_zero(global_externnotify)) { + return; ++ } + +- snprintf(arguments, sizeof(arguments), "%s %s@%s %s %s&", +- ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify, +- vmu->username, vmu->domain, +- (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) +- ? ast_channel_caller(chan)->id.name.str : "", +- (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) +- ? ast_channel_caller(chan)->id.number.str : ""); ++ snprintf(fquser, sizeof(fquser), "%s@%s", vmu->username, vmu->domain); + +- ast_debug(1, "Executing: %s\n", arguments); +- ast_safe_system(arguments); ++ caller = ast_channel_caller(chan); ++ idx = 0; ++ argv[idx++] = ast_strlen_zero(vmu->externnotify) ? global_externnotify : vmu->externnotify; ++ argv[idx++] = fquser; ++ cid = S_COR(caller->id.name.valid, caller->id.name.str, NULL); ++ if (cid) { ++ argv[idx++] = cid; ++ } ++ cid = S_COR(caller->id.number.valid, caller->id.number.str, NULL); ++ if (cid) { ++ argv[idx++] = cid; ++ } ++ argv[idx] = NULL; ++ ++ ast_debug(1, "Executing: %s %s %s %s\n", ++ argv[0], argv[1], argv[2] ?: "", argv[3] ?: ""); ++ ast_safe_execvp(1, argv[0], argv); + } + + /*!\internal +diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c +index 89a1d8c..96adb9a 100644 +--- a/apps/app_mixmonitor.c ++++ b/apps/app_mixmonitor.c +@@ -127,6 +127,11 @@ + Will be executed when the recording is over. + Any strings matching ^{X} will be unescaped to X. + All variables will be evaluated at the time MixMonitor is called. ++ Do not use untrusted strings such as CALLERID(num) ++ or CALLERID(name) as part of the command parameters. You ++ risk a command injection attack executing arbitrary commands if the untrusted ++ strings aren't filtered to remove dangerous characters. See function ++ FILTER(). + + + +@@ -143,6 +148,11 @@ + Will contain the filename used to record. + + ++ Do not use untrusted strings such as CALLERID(num) ++ or CALLERID(name) as part of ANY of the application's ++ parameters. You risk a command injection attack executing arbitrary commands ++ if the untrusted strings aren't filtered to remove dangerous characters. See ++ function FILTER(). + + + Monitor +diff --git a/apps/app_system.c b/apps/app_system.c +index 7fe453d..e868a07 100644 +--- a/apps/app_system.c ++++ b/apps/app_system.c +@@ -48,6 +48,11 @@ + + + Command to execute ++ Do not use untrusted strings such as CALLERID(num) ++ or CALLERID(name) as part of the command parameters. You ++ risk a command injection attack executing arbitrary commands if the untrusted ++ strings aren't filtered to remove dangerous characters. See function ++ FILTER(). + + + +@@ -73,6 +78,11 @@ + + + Command to execute ++ Do not use untrusted strings such as CALLERID(num) ++ or CALLERID(name) as part of the command parameters. You ++ risk a command injection attack executing arbitrary commands if the untrusted ++ strings aren't filtered to remove dangerous characters. See function ++ FILTER(). + + + +diff --git a/configs/minivm.conf.sample b/configs/minivm.conf.sample +index 55a39c8..3dcd59d 100644 +--- a/configs/minivm.conf.sample ++++ b/configs/minivm.conf.sample +@@ -51,7 +51,7 @@ + ; If you need to have an external program, i.e. /usr/bin/myapp called when a + ; voicemail is received by the server. The arguments are + ; +-; ++; + ; + ;externnotify=/usr/bin/myapp + ; The character set for voicemail messages can be specified here +diff --git a/funcs/func_shell.c b/funcs/func_shell.c +index e403efc..79b7f99 100644 +--- a/funcs/func_shell.c ++++ b/funcs/func_shell.c +@@ -84,6 +84,11 @@ + + + The command that the shell should execute. ++ Do not use untrusted strings such as CALLERID(num) ++ or CALLERID(name) as part of the command parameters. You ++ risk a command injection attack executing arbitrary commands if the untrusted ++ strings aren't filtered to remove dangerous characters. See function ++ FILTER(). + + + +diff --git a/include/asterisk/app.h b/include/asterisk/app.h +index d10a0a6..8cdaea1 100644 +--- a/include/asterisk/app.h ++++ b/include/asterisk/app.h +@@ -577,9 +577,34 @@ + int ast_vm_test_create_user(const char *context, const char *mailbox); + #endif + +-/*! \brief Safely spawn an external program while closing file descriptors +- \note This replaces the \b system call in all Asterisk modules +-*/ ++/*! ++ * \brief Safely spawn an external program while closing file descriptors ++ * ++ * \note This replaces the \b execvp call in all Asterisk modules ++ * ++ * \param dualfork Non-zero to simulate running the program in the ++ * background by forking twice. The option provides similar ++ * functionality to the '&' in the OS shell command "cmd &". The ++ * option allows Asterisk to run a reaper loop to watch the first fork ++ * which immediately exits after spaning the second fork. The actual ++ * program is run in the second fork. ++ * \param file execvp(file, argv) file parameter ++ * \param argv execvp(file, argv) argv parameter ++ */ ++int ast_safe_execvp(int dualfork, const char *file, char *const argv[]); ++ ++/*! ++ * \brief Safely spawn an OS shell command while closing file descriptors ++ * ++ * \note This replaces the \b system call in all Asterisk modules ++ * ++ * \param s - OS shell command string to execute. ++ * ++ * \warning Command injection can happen using this call if the passed ++ * in string is created using untrusted data from an external source. ++ * It is best not to use untrusted data. However, the caller could ++ * filter out dangerous characters to avoid command injection. ++ */ + int ast_safe_system(const char *s); + + /*! +diff --git a/main/asterisk.c b/main/asterisk.c +index ce1d153..92256bd 100644 +--- a/main/asterisk.c ++++ b/main/asterisk.c +@@ -1102,12 +1102,10 @@ + ast_mutex_unlock(&safe_system_lock); + } + +-int ast_safe_system(const char *s) ++/*! \brief fork and perform other preparations for spawning applications */ ++static pid_t safe_exec_prep(int dualfork) + { + pid_t pid; +- int res; +- struct rusage rusage; +- int status; + + #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK) + ast_replace_sigchld(); +@@ -1129,35 +1127,102 @@ + cap_free(cap); + #endif + #ifdef HAVE_WORKING_FORK +- if (ast_opt_high_priority) ++ if (ast_opt_high_priority) { + ast_set_priority(0); ++ } + /* Close file descriptors and launch system command */ + ast_close_fds_above_n(STDERR_FILENO); + #endif +- execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); +- _exit(1); +- } else if (pid > 0) { ++ if (dualfork) { ++#ifdef HAVE_WORKING_FORK ++ pid = fork(); ++#else ++ pid = vfork(); ++#endif ++ if (pid < 0) { ++ /* Second fork failed. */ ++ /* No logger available. */ ++ _exit(1); ++ } ++ ++ if (pid > 0) { ++ /* This is the first fork, exit so the reaper finishes right away. */ ++ _exit(0); ++ } ++ ++ /* This is the second fork. The first fork will exit immediately so ++ * Asterisk doesn't have to wait for completion. ++ * ast_safe_system("cmd &") would run in the background, but the '&' ++ * cannot be added with ast_safe_execvp, so we have to double fork. ++ */ ++ } ++ } ++ ++ if (pid < 0) { ++ ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); ++ } ++#else ++ ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(ENOTSUP)); ++ pid = -1; ++#endif ++ ++ return pid; ++} ++ ++/*! \brief wait for spawned application to complete and unreplace sigchld */ ++static int safe_exec_wait(pid_t pid) ++{ ++ int res = -1; ++ ++#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK) ++ if (pid > 0) { + for (;;) { ++ struct rusage rusage; ++ int status; ++ + res = wait4(pid, &status, 0, &rusage); + if (res > -1) { + res = WIFEXITED(status) ? WEXITSTATUS(status) : -1; + break; +- } else if (errno != EINTR) ++ } ++ if (errno != EINTR) { + break; ++ } + } +- } else { +- ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); +- res = -1; + } + + ast_unreplace_sigchld(); +-#else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */ +- res = -1; + #endif + + return res; + } + ++int ast_safe_execvp(int dualfork, const char *file, char *const argv[]) ++{ ++ pid_t pid = safe_exec_prep(dualfork); ++ ++ if (pid == 0) { ++ execvp(file, argv); ++ _exit(1); ++ /* noreturn from _exit */ ++ } ++ ++ return safe_exec_wait(pid); ++} ++ ++int ast_safe_system(const char *s) ++{ ++ pid_t pid = safe_exec_prep(0); ++ ++ if (pid == 0) { ++ execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); ++ _exit(1); ++ /* noreturn from _exit */ ++ } ++ ++ return safe_exec_wait(pid); ++} ++ + /*! + * \brief enable or disable a logging level to a specified console + */ +diff --git a/res/res_monitor.c b/res/res_monitor.c +index 76c43e1..12f478a 100644 +--- a/res/res_monitor.c ++++ b/res/res_monitor.c +@@ -57,17 +57,17 @@ + + + +- optional, if not set, defaults to wav ++ Optional. If not set, defaults to wav + + + + +- if set, changes the filename used to the one specified. ++ If set, changes the filename used to the one specified. + + + + +