]> granicus.if.org Git - php/commitdiff
fix #71609: Segmentation fault on ZTS with gethostbyname
authorJoe Watkins <krakjoe@php.net>
Thu, 31 Mar 2016 11:39:01 +0000 (12:39 +0100)
committerJoe Watkins <krakjoe@php.net>
Thu, 31 Mar 2016 11:39:01 +0000 (12:39 +0100)
TSRM/m4/gethostbyname.m4 [new file with mode: 0644]
TSRM/tsrm.m4
ext/sockets/sockaddr_conv.c
ext/sockets/sockets.c
ext/standard/dns.c
ext/standard/file.c
ext/standard/file.h
main/fastcgi.c
main/network.c
main/php_network.h

diff --git a/TSRM/m4/gethostbyname.m4 b/TSRM/m4/gethostbyname.m4
new file mode 100644 (file)
index 0000000..ac3eb06
--- /dev/null
@@ -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
+
index b53a4bb805fffc168a26fd05aae11a7bf7656fe0..98aa2b8c912584ec842bd3b39f1c09910681be9d 100644 (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-*
index 73a008572037614bade8462680ec7841b99c2c82..1ce109ee8c06cfa2766126d1ef8402fc87ebd6c1 100644 (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());
index a207225f1c52dd48fea2c286ef785c45dad09262..6039ac65ba6d4fb5534c16c908c9fdea2761f261 100644 (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;
index a3394e0479fb7ca19355a13ddff2dfa9b384bc19..de40649e696ce3a339ac9dc4900d0cd9766923ef 100644 (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);
index 26f5c161cebe2527c9dc86cfedf1220b812af81b..cefdc4aecbb4af91b7d98395b59fd3fd80324c7e 100644 (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()
index d423475386dc358b42fe8b7bd46418076a8d3022..a9b96d6b38ec62dc3a720065db777fe191f65531 100644 (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
index ce333690457a6b30222d2abe3996225741af2804..fbc6f403a055ca96d48571e6a5aae4ae132fbc71 100644 (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);
index 138f86b3e4308d2f03a58d354c340bf4cd1c0a0a..6d1d97bc82dd86cbdd0694828c3c959cafa5cd85 100644 (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:
index daf9671132716ae10e9930bf6b92538c06e59163..4ddae5cd4ce300f60e6c9615c2997ded276fe90b 100644 (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)