]> granicus.if.org Git - php/commitdiff
Fixed bug #69316 (Use-after-free in php_curl related to CURLOPT_FILE/_INFILE/_WRITEHE...
authorStanislav Malyshev <stas@php.net>
Sat, 4 Apr 2015 22:58:27 +0000 (15:58 -0700)
committerStanislav Malyshev <stas@php.net>
Sat, 11 Apr 2015 23:53:21 +0000 (16:53 -0700)
ext/curl/interface.c
ext/curl/tests/bug69316.phpt [new file with mode: 0644]

index 0423f71f9a8e35ccb5fa5f6419615cd7c2e151aa..7f8f276791bee0a96293787d831904daada19118 100644 (file)
@@ -1051,6 +1051,7 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_WRITEFUNCTION");
                                length = -1;
                        } else if (retval_ptr) {
+                               _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
                                if (Z_TYPE_P(retval_ptr) != IS_LONG) {
                                        convert_to_long_ex(&retval_ptr);
                                }
@@ -1124,6 +1125,7 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double
                        if (error == FAILURE) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot call the CURLOPT_PROGRESSFUNCTION");
                        } else if (retval_ptr) {
+                               _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
                                if (Z_TYPE_P(retval_ptr) != IS_LONG) {
                                        convert_to_long_ex(&retval_ptr);
                                }
@@ -1200,6 +1202,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
                                length = CURL_READFUNC_ABORT;
 #endif
                        } else if (retval_ptr) {
+                               _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
                                if (Z_TYPE_P(retval_ptr) == IS_STRING) {
                                        length = MIN((int) (size * nmemb), Z_STRLEN_P(retval_ptr));
                                        memcpy(data, Z_STRVAL_P(retval_ptr), length);
@@ -1274,6 +1277,7 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the CURLOPT_HEADERFUNCTION");
                                length = -1;
                        } else if (retval_ptr) {
+                               _php_curl_verify_handlers(ch, 1 TSRMLS_CC);
                                if (Z_TYPE_P(retval_ptr) != IS_LONG) {
                                        convert_to_long_ex(&retval_ptr);
                                }
diff --git a/ext/curl/tests/bug69316.phpt b/ext/curl/tests/bug69316.phpt
new file mode 100644 (file)
index 0000000..2a88eb2
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+Bug #69316: Use-after-free in php_curl related to CURLOPT_FILE/_INFILE/_WRITEHEADER
+--SKIPIF--
+<?php 
+if (!extension_loaded("curl")) exit("skip curl extension not loaded");
+if (false === getenv('PHP_CURL_HTTP_REMOTE_SERVER'))  exit("skip PHP_CURL_HTTP_REMOTE_SERVER env variable is not defined");
+?>
+--FILE--
+<?php
+  function hdr_callback($ch, $data) {
+      // close the stream, causing the FILE structure to be free()'d
+      if($GLOBALS['f_file']) {
+          fclose($GLOBALS['f_file']); $GLOBALS['f_file'] = 0;
+
+          // cause an allocation of approx the same size as a FILE structure, size varies a bit depending on platform/libc
+          $FILE_size = (PHP_INT_SIZE == 4 ? 0x160 : 0x238);
+          curl_setopt($ch, CURLOPT_COOKIE, str_repeat("a", $FILE_size - 1));
+      }
+      return strlen($data);
+  }
+  $host = getenv('PHP_CURL_HTTP_REMOTE_SERVER');
+  
+  $temp_file = dirname(__FILE__) . '/body.tmp';
+  $url = "{$host}/get.php?test=getpost";
+  $ch = curl_init();
+  $f_file = fopen($temp_file, "w") or die("failed to open file\n");
+  curl_setopt($ch, CURLOPT_BUFFERSIZE, 10);
+  curl_setopt($ch, CURLOPT_HEADERFUNCTION, "hdr_callback");
+  curl_setopt($ch, CURLOPT_FILE, $f_file);
+  curl_setopt($ch, CURLOPT_URL, $url);
+  curl_exec($ch);
+  curl_close($ch);
+?>
+===DONE===
+--CLEAN--
+<?php
+unlink(dirname(__FILE__) . '/body.tmp');
+?>
+--EXPECTF--
+Warning: curl_exec(): CURLOPT_FILE resource has gone away, resetting to default in %s on line %d
+===DONE===