fix #71609: Segmentation fault on ZTS with gethostbyname

This commit is contained in:
Joe Watkins 2016-03-31 12:39:01 +01:00
parent ed06d130f7
commit 233115ea23
10 changed files with 315 additions and 10 deletions

197
TSRM/m4/gethostbyname.m4 Normal file
View file

@ -0,0 +1,197 @@
# =================================================================================
# http://www.gnu.org/software/autoconf-archive/ax_func_which_gethostbyname_r.html
# =================================================================================
#
# SYNOPSIS
#
# AX_FUNC_WHICH_GETHOSTBYNAME_R
#
# DESCRIPTION
#
# Determines which historical variant of the gethostbyname_r() call
# (taking three, five, or six arguments) is available on the system and
# defines one of the following macros accordingly:
#
# HAVE_FUNC_GETHOSTBYNAME_R_6
# HAVE_FUNC_GETHOSTBYNAME_R_5
# HAVE_FUNC_GETHOSTBYNAME_R_3
#
# as well as
#
# HAVE_GETHOSTBYNAME_R
#
# If used in conjunction with gethostname.c, the API demonstrated in
# test.c can be used regardless of which gethostbyname_r() is available.
# These example files can be found at
# http://www.csn.ul.ie/~caolan/publink/gethostbyname_r
#
# based on David Arnold's autoconf suggestion in the threads faq
#
# Originally named "AC_caolan_FUNC_WHICH_GETHOSTBYNAME_R". Rewritten for
# Autoconf 2.5x, and updated for 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Caolan McNamara <caolan@skynet.ie>
# Copyright (c) 2008 Daniel Richard G. <skunk@iskunk.org>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AC_DEFUN([AX_FUNC_WHICH_GETHOSTBYNAME_R], [
AC_LANG_PUSH([C])
AC_MSG_CHECKING([how many arguments gethostbyname_r() takes])
AC_CACHE_VAL([ac_cv_func_which_gethostbyname_r], [
################################################################
ac_cv_func_which_gethostbyname_r=unknown
#
# ONE ARGUMENT (sanity check)
#
# This should fail, as there is no variant of gethostbyname_r() that takes
# a single argument. If it actually compiles, then we can assume that
# netdb.h is not declaring the function, and the compiler is thereby
# assuming an implicit prototype. In which case, we're out of luck.
#
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
[
char *name = "www.gnu.org";
(void)gethostbyname_r(name) /* ; */
])],
[ac_cv_func_which_gethostbyname_r=no])
#
# SIX ARGUMENTS
# (e.g. Linux)
#
if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
[
char *name = "www.gnu.org";
struct hostent ret, *retp;
char buf@<:@1024@:>@;
int buflen = 1024;
int my_h_errno;
(void)gethostbyname_r(name, &ret, buf, buflen, &retp, &my_h_errno) /* ; */
])],
[ac_cv_func_which_gethostbyname_r=six])
fi
#
# FIVE ARGUMENTS
# (e.g. Solaris)
#
if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
[
char *name = "www.gnu.org";
struct hostent ret;
char buf@<:@1024@:>@;
int buflen = 1024;
int my_h_errno;
(void)gethostbyname_r(name, &ret, buf, buflen, &my_h_errno) /* ; */
])],
[ac_cv_func_which_gethostbyname_r=five])
fi
#
# THREE ARGUMENTS
# (e.g. AIX, HP-UX, Tru64)
#
if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>],
[
char *name = "www.gnu.org";
struct hostent ret;
struct hostent_data data;
(void)gethostbyname_r(name, &ret, &data) /* ; */
])],
[ac_cv_func_which_gethostbyname_r=three])
fi
################################################################
]) dnl end AC_CACHE_VAL
case "$ac_cv_func_which_gethostbyname_r" in
three|five|six)
AC_DEFINE([HAVE_GETHOSTBYNAME_R], [1],
[Define to 1 if you have some form of gethostbyname_r().])
;;
esac
case "$ac_cv_func_which_gethostbyname_r" in
three)
AC_MSG_RESULT([three])
AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_3], [1],
[Define to 1 if you have the three-argument form of gethostbyname_r().])
;;
five)
AC_MSG_RESULT([five])
AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_5], [1],
[Define to 1 if you have the five-argument form of gethostbyname_r().])
;;
six)
AC_MSG_RESULT([six])
AC_DEFINE([HAVE_FUNC_GETHOSTBYNAME_R_6], [1],
[Define to 1 if you have the six-argument form of gethostbyname_r().])
;;
no)
AC_MSG_RESULT([cannot find function declaration in netdb.h])
;;
unknown)
AC_MSG_RESULT([can't tell])
;;
*)
AC_MSG_ERROR([internal error])
;;
esac
AC_LANG_POP
]) dnl end AC_DEFUN

View file

@ -1,3 +1,4 @@
m4_include([TSRM/m4/gethostbyname.m4])
dnl TSRM_CHECK_GCC_ARG(ARG, ACTION-IF-FOUND, ACTION-IF-NOT_FOUND)
AC_DEFUN([TSRM_CHECK_GCC_ARG],[
@ -32,6 +33,8 @@ AC_CHECK_HEADERS(stdarg.h)
AC_CHECK_FUNCS(sigprocmask)
AX_FUNC_WHICH_GETHOSTBYNAME_R()
])
@ -89,7 +92,6 @@ else
fi
])
AC_DEFUN([TSRM_THREADS_CHECKS],[
dnl For the thread implementations, we always use --with-*

View file

@ -90,7 +90,7 @@ int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_soc
if (inet_aton(string, &tmp)) {
sin->sin_addr.s_addr = tmp.s_addr;
} else {
if (strlen(string) > MAXFQDNLEN || ! (host_entry = gethostbyname(string))) {
if (strlen(string) > MAXFQDNLEN || ! (host_entry = php_network_gethostbyname(string))) {
/* Note: < -10000 indicates a host lookup error */
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());

View file

@ -425,9 +425,9 @@ static int php_open_listen_sock(php_socket **php_sock, int port, int backlog) /*
*php_sock = sock;
#ifndef PHP_WIN32
if ((hp = gethostbyname("0.0.0.0")) == NULL) {
if ((hp = php_network_gethostbyname("0.0.0.0")) == NULL) {
#else
if ((hp = gethostbyname("localhost")) == NULL) {
if ((hp = php_network_gethostbyname("localhost")) == NULL) {
#endif
efree(sock);
return 0;

View file

@ -251,7 +251,7 @@ PHP_FUNCTION(gethostbynamel)
RETURN_FALSE;
}
hp = gethostbyname(hostname);
hp = php_network_gethostbyname(hostname);
if (hp == NULL || hp->h_addr_list == NULL) {
RETURN_FALSE;
}
@ -272,7 +272,7 @@ static zend_string *php_gethostbyname(char *name)
struct in_addr in;
char *address;
hp = gethostbyname(name);
hp = php_network_gethostbyname(name);
if (!hp || !*(hp->h_addr_list)) {
return zend_string_init(name, strlen(name), 0);

View file

@ -159,6 +159,11 @@ static void file_globals_ctor(php_file_globals *file_globals_p)
static void file_globals_dtor(php_file_globals *file_globals_p)
{
#if defined(HAVE_GETHOSTBYNAME_R)
if (file_globals_p->tmp_host_buf) {
free(file_globals_p->tmp_host_buf);
}
#endif
}
PHP_INI_BEGIN()

View file

@ -129,6 +129,11 @@ typedef struct {
HashTable *stream_filters; /* per-request copy of stream_filters_hash */
HashTable *wrapper_errors; /* key: wrapper address; value: linked list of char* */
int pclose_wait;
#if defined(HAVE_GETHOSTBYNAME_R)
struct hostent tmp_host_info;
char *tmp_host_buf;
size_t tmp_host_buf_len;
#endif
} php_file_globals;
#ifdef ZTS

View file

@ -692,7 +692,7 @@ int fcgi_listen(const char *path, int backlog)
if(strlen(host) > MAXFQDNLEN) {
hep = NULL;
} else {
hep = gethostbyname(host);
hep = php_network_gethostbyname(host);
}
if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
fcgi_log(FCGI_ERROR, "Cannot resolve host name '%s'!\n", host);

View file

@ -176,6 +176,8 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
# endif
struct addrinfo hints, *res, *sai;
#else
char *tmp_host_buf = NULL;
struct hostent tmp_host_info;
struct hostent *host_info;
struct in_addr in;
#endif
@ -245,12 +247,11 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
freeaddrinfo(res);
#else
if (!inet_aton(host, &in)) {
/* XXX NOT THREAD SAFE (is safe under win32) */
if(strlen(host) > MAXFQDNLEN) {
host_info = NULL;
errno = E2BIG;
} else {
host_info = gethostbyname(host);
host_info = php_network_gethostbyname(host, &tmp_host_info, &tmp_host_buf);
}
if (host_info == NULL) {
if (error_string) {
@ -271,6 +272,9 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
((struct sockaddr_in *)*sap)->sin_addr = in;
sap++;
n = 1;
if (tmp_host_buf) {
efree(tmp_host_buf);
}
#endif
*sap = NULL;
@ -1257,9 +1261,95 @@ PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
}
return n;
}
#endif
#if defined(HAVE_GETHOSTBYNAME_R)
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_6
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
{
struct hostent *hp;
int herr,res;
if (*hstbuflen == 0) {
*hstbuflen = 1024;
*tmphstbuf = (char *)malloc (*hstbuflen);
}
while (( res =
gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr))
&& (errno == ERANGE)) {
/* Enlarge the buffer. */
*hstbuflen *= 2;
*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
}
if (res != SUCCESS) {
return NULL;
}
return hp;
}
#endif
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_5
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
{
struct hostent *hp;
int herr;
if (*hstbuflen == 0) {
*hstbuflen = 1024;
*tmphstbuf = (char *)malloc (*hstbuflen);
}
while ((NULL == ( hp =
gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr)))
&& (errno == ERANGE)) {
/* Enlarge the buffer. */
*hstbuflen *= 2;
*tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen);
}
return hp;
}
#endif
#ifdef HAVE_FUNC_GETHOSTBYNAME_R_3
struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen)
{
if (*hstbuflen == 0) {
*hstbuflen = sizeof(struct hostent_data);
*tmphstbuf = (char *)malloc (*hstbuflen);
} else {
if (*hstbuflen < sizeof(struct hostent_data)) {
*hstbuflen = sizeof(struct hostent_data);
*tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen);
}
}
memset((void *)(*tmphstbuf),0,*hstbuflen);
if (SUCCESS != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) {
return NULL;
}
return hostbuf;
}
#endif
#endif
PHPAPI struct hostent* php_network_gethostbyname(char *name) {
#if !defined(HAVE_GETHOSTBYNAME_R)
return gethostbyname(name);
#else
if (FG(tmp_host_buf)) {
free(FG(tmp_host_buf));
}
FG(tmp_host_buf) = NULL;
FG(tmp_host_buf_len) = 0;
memset(&FG(tmp_host_info), 0, sizeof(struct hostent));
return gethostname_re(name, &FG(tmp_host_info), &FG(tmp_host_buf), &FG(tmp_host_buf_len));
#endif
}
/*
* Local variables:

View file

@ -74,6 +74,10 @@ END_EXTERN_C()
#include <sys/socket.h>
#endif
#ifdef HAVE_GETHOSTBYNAME_R
#include <netdb.h>
#endif
/* These are here, rather than with the win32 counterparts above,
* since <sys/socket.h> defines them. */
#ifndef SHUT_RD
@ -309,6 +313,8 @@ PHPAPI void php_network_populate_name_from_sockaddr(
PHPAPI int php_network_parse_network_address_with_port(const char *addr,
zend_long addrlen, struct sockaddr *sa, socklen_t *sl);
PHPAPI struct hostent* php_network_gethostbyname(char *name);
END_EXTERN_C()
#define php_stream_sock_open_from_socket(socket, persistent) _php_stream_sock_open_from_socket((socket), (persistent) STREAMS_CC)