res_pjsip_session: segfault on already disconnected session

On heavy loaded system the TCP/TLS incoming calls could be
disconnected by pjproject while these calls are being
processed by asterisk which could use the session's memory pools.
If the session in the disconnected state then the session memory
pools were already freed, so we get segfault.

This patch adds a lifetime control on an INVITE session to pjproject.
The lifetime of the session is manipulated by calling
pjsip_inv_add_ref/pjsip_inv_dec_ref.
This patch uses these functions to inform pjproject that the
session is in use.

This patch adds check if the session state is not disconnected
and also checks if the memory pool is not NULL.

This patch also places tasks 'session_end' and 'session_end_completion'
into session's serializer to avoid race condition.

ASTERISK-26291 #close

Change-Id: I4d28b1fb3b91f0492a911d110049d670fdc3c8d7
This commit is contained in:
Alexei Gradinari
2016-08-18 15:45:59 -04:00
parent e34f299a96
commit 7bb7f7b9d5
6 changed files with 403 additions and 9 deletions

123
configure vendored
View File

@@ -935,6 +935,10 @@ PBX_POPT
POPT_DIR
POPT_INCLUDE
POPT_LIB
PBX_PJSIP_INV_SESSION_REF
PJSIP_INV_SESSION_REF_DIR
PJSIP_INV_SESSION_REF_INCLUDE
PJSIP_INV_SESSION_REF_LIB
PBX_PJSIP_EVSUB_GRP_LOCK
PJSIP_EVSUB_GRP_LOCK_DIR
PJSIP_EVSUB_GRP_LOCK_INCLUDE
@@ -11001,6 +11005,18 @@ PBX_PJSIP_EVSUB_GRP_LOCK=0
PJSIP_INV_SESSION_REF_DESCRIP="PJSIP INVITE Session Reference Count support"
PJSIP_INV_SESSION_REF_OPTION=pjsip
PJSIP_INV_SESSION_REF_DIR=${PJPROJECT_DIR}
PBX_PJSIP_INV_SESSION_REF=0
POPT_DESCRIP="popt"
POPT_OPTION="popt"
@@ -25269,6 +25285,9 @@ $as_echo "#define HAVE_PJSIP_TLS_TRANSPORT_PROTO 1" >>confdefs.h
$as_echo "#define HAVE_PJSIP_EVSUB_GRP_LOCK 1" >>confdefs.h
$as_echo "#define HAVE_PJSIP_INV_SESSION_REF 1" >>confdefs.h
else
if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then
@@ -26089,6 +26108,110 @@ _ACEOF
fi
if test "x${PBX_PJSIP_INV_SESSION_REF}" != "x1" -a "${USE_PJSIP_INV_SESSION_REF}" != "no"; then
pbxlibdir=""
# if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it.
if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then
if test -d ${PJSIP_INV_SESSION_REF_DIR}/lib; then
pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}/lib"
else
pbxlibdir="-L${PJSIP_INV_SESSION_REF_DIR}"
fi
fi
pbxfuncname="pjsip_inv_add_ref"
if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
AST_PJSIP_INV_SESSION_REF_FOUND=yes
else
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} $PJPROJECT_CFLAGS"
as_ac_Lib=`$as_echo "ac_cv_lib_pjsip_${pbxfuncname}" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lpjsip" >&5
$as_echo_n "checking for ${pbxfuncname} in -lpjsip... " >&6; }
if eval \${$as_ac_Lib+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lpjsip ${pbxlibdir} $PJPROJECT_LIB $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char ${pbxfuncname} ();
int
main ()
{
return ${pbxfuncname} ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
eval "$as_ac_Lib=yes"
else
eval "$as_ac_Lib=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
AST_PJSIP_INV_SESSION_REF_FOUND=yes
else
AST_PJSIP_INV_SESSION_REF_FOUND=no
fi
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
fi
# now check for the header.
if test "${AST_PJSIP_INV_SESSION_REF_FOUND}" = "yes"; then
PJSIP_INV_SESSION_REF_LIB="${pbxlibdir} -lpjsip $PJPROJECT_LIB"
# if --with-PJSIP_INV_SESSION_REF=DIR has been specified, use it.
if test "x${PJSIP_INV_SESSION_REF_DIR}" != "x"; then
PJSIP_INV_SESSION_REF_INCLUDE="-I${PJSIP_INV_SESSION_REF_DIR}/include"
fi
PJSIP_INV_SESSION_REF_INCLUDE="${PJSIP_INV_SESSION_REF_INCLUDE} $PJPROJECT_CFLAGS"
if test "xpjsip.h" = "x" ; then # no header, assume found
PJSIP_INV_SESSION_REF_HEADER_FOUND="1"
else # check for the header
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${CPPFLAGS} ${PJSIP_INV_SESSION_REF_INCLUDE}"
ac_fn_c_check_header_mongrel "$LINENO" "pjsip.h" "ac_cv_header_pjsip_h" "$ac_includes_default"
if test "x$ac_cv_header_pjsip_h" = xyes; then :
PJSIP_INV_SESSION_REF_HEADER_FOUND=1
else
PJSIP_INV_SESSION_REF_HEADER_FOUND=0
fi
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
fi
if test "x${PJSIP_INV_SESSION_REF_HEADER_FOUND}" = "x0" ; then
PJSIP_INV_SESSION_REF_LIB=""
PJSIP_INV_SESSION_REF_INCLUDE=""
else
if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library
PJSIP_INV_SESSION_REF_LIB=""
fi
PBX_PJSIP_INV_SESSION_REF=1
cat >>confdefs.h <<_ACEOF
#define HAVE_PJSIP_INV_SESSION_REF 1
_ACEOF
fi
fi
fi
fi
fi