]> granicus.if.org Git - php/commitdiff
Add mitigation for CVE-2015-0235 (bug #68925)
authorStanislav Malyshev <stas@php.net>
Sun, 1 Feb 2015 02:59:18 +0000 (18:59 -0800)
committerStanislav Malyshev <stas@php.net>
Sun, 1 Feb 2015 03:08:13 +0000 (19:08 -0800)
NEWS
ext/standard/dns.c
ext/standard/tests/network/bug68925.phpt [new file with mode: 0644]
main/network.c
sapi/cgi/fastcgi.c

diff --git a/NEWS b/NEWS
index 248211f15b35987acfa5cc6c4bca66d85d8a024d..2e45ad877ce93694dce7db5e8c1128c09ec9bd05 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 20?? PHP 5.4.38
 
+- Core:
+  . Fixed bug #68925 (Mitigation for CVE-2015-0235 – GHOST: glibc gethostbyname
+    buffer overflow). (Stas)
+
 22 Jan 2015 PHP 5.4.37
 - Core:
   . Fixed bug #68710 (Use After Free Vulnerability in PHP's unserialize()).
index 0b5e69ca58cc13b9f4e7f78dbac0c89aa5fb5e26..e21aca4919798b6815f966ae07a09149930286ad 100644 (file)
@@ -222,6 +222,11 @@ PHP_FUNCTION(gethostbyname)
                return;
        }
 
+       if(hostname_len > MAXHOSTNAMELEN) {
+               /* name too long, protect from CVE-2015-0235 */
+               php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXHOSTNAMELEN);
+               RETURN_STRINGL(hostname, hostname_len, 1);
+       }
        addr = php_gethostbyname(hostname);
 
        RETVAL_STRING(addr, 0);
@@ -242,6 +247,12 @@ PHP_FUNCTION(gethostbynamel)
                return;
        }
 
+       if(hostname_len > MAXHOSTNAMELEN) {
+               /* name too long, protect from CVE-2015-0235 */
+               php_error_docref(NULL, E_WARNING, "Host name is too long, the limit is %d characters", MAXHOSTNAMELEN);
+               RETURN_FALSE;
+       }
+
        hp = gethostbyname(hostname);
        if (hp == NULL || hp->h_addr_list == NULL) {
                RETURN_FALSE;
diff --git a/ext/standard/tests/network/bug68925.phpt b/ext/standard/tests/network/bug68925.phpt
new file mode 100644 (file)
index 0000000..e710d72
--- /dev/null
@@ -0,0 +1,13 @@
+--TEST--
+Bug #68925 (CVE-2015-0235 – GHOST: glibc gethostbyname buffer overflow)
+--FILE--
+<?php
+var_dump(gethostbyname(str_repeat("0", 2501)));
+var_dump(gethostbynamel(str_repeat("0", 2501)));
+?>
+--EXPECTF--
+Warning: gethostbyname(): Host name is too long, the limit is 256 characters in %s/bug68925.php on line %d
+string(2501) "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+
+Warning: gethostbynamel(): Host name is too long, the limit is 256 characters in %s/bug68925.php on line %d
+bool(false)
index 5e44b0e6a8ed229c4419e4178a2b2f09fbe918f5..41b2cfa0ba2372e4f259f20d7f515cf2f20d623f 100644 (file)
@@ -24,6 +24,7 @@
 #include "php.h"
 
 #include <stddef.h>
+#include <errno.h>
 
 #ifdef PHP_WIN32
 # include "win32/inet.h"
@@ -102,6 +103,10 @@ const struct in6_addr in6addr_any = {0}; /* IN6ADDR_ANY_INIT; */
 # define PHP_TIMEOUT_ERROR_VALUE               ETIMEDOUT
 #endif
 
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 255
+#endif
+
 #if HAVE_GETADDRINFO
 #ifdef HAVE_GAI_STRERROR
 #  define PHP_GAI_STRERROR(x) (gai_strerror(x))
@@ -243,7 +248,12 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka
 #else
        if (!inet_aton(host, &in)) {
                /* XXX NOT THREAD SAFE (is safe under win32) */
-               host_info = gethostbyname(host);
+               if(strlen(host) > MAXHOSTNAMELEN) {
+                       host_info = NULL;
+                       errno = E2BIG;
+               } else {
+                       host_info = gethostbyname(host);
+               }
                if (host_info == NULL) {
                        if (error_string) {
                                spprintf(error_string, 0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
index 8ddc2e4577265ea5382ade870de7abff889db725..4c6ea4c0a35927df12e3c1870a5ccc84c9d43ddb 100644 (file)
@@ -611,7 +611,11 @@ int fcgi_listen(const char *path, int backlog)
                        if (sa.sa_inet.sin_addr.s_addr == INADDR_NONE) {
                                struct hostent *hep;
 
-                               hep = gethostbyname(host);
+                               if(strlen(host) > MAXHOSTNAMELEN) {
+                                       hep = NULL;
+                               } else {
+                                       hep = gethostbyname(host);
+                               }
                                if (!hep || hep->h_addrtype != AF_INET || !hep->h_addr_list[0]) {
                                        fprintf(stderr, "Cannot resolve host name '%s'!\n", host);
                                        return -1;