Skip to content

Commit e421f82

Browse files
committed
Fix use-after-free of CURLOPT_STDERR stream on cloned curl handle
_php_setup_easy_copy_handlers() copies the write, read and write_header streams but not std_err. The clone never checks that stream is still open, so libcurl keeps writing to a FILE* freed when the stream is closed. Copy std_err like the other handlers.
1 parent d5ab360 commit e421f82

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

‎ext/curl/interface.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,10 @@ void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source)
13051305
Z_ADDREF(source->handlers.write_header->stream);
13061306
}
13071307
ch->handlers.write_header->stream = source->handlers.write_header->stream;
1308+
if (!Z_ISUNDEF(source->handlers.std_err)) {
1309+
Z_ADDREF(source->handlers.std_err);
1310+
}
1311+
ch->handlers.std_err = source->handlers.std_err;
13081312

13091313
ch->handlers.write->fp = source->handlers.write->fp;
13101314
ch->handlers.write_header->fp = source->handlers.write_header->fp;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Cloning a curl handle keeps CURLOPT_STDERR tracked so a closed stream is detected on the clone too
3+
--EXTENSIONS--
4+
curl
5+
--FILE--
6+
<?php
7+
$srcfile = __DIR__ . '/curl_copy_handle_stderr_uaf_src.txt';
8+
file_put_contents($srcfile, "Test.");
9+
10+
$stderrfile = __DIR__ . '/curl_copy_handle_stderr_uaf_stderr.txt';
11+
$stream = fopen($stderrfile, 'w+');
12+
13+
$ch1 = curl_init();
14+
curl_setopt($ch1, CURLOPT_URL, "file://" . $srcfile);
15+
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
16+
curl_setopt($ch1, CURLOPT_VERBOSE, true);
17+
curl_setopt($ch1, CURLOPT_STDERR, $stream);
18+
19+
$ch2 = clone $ch1;
20+
21+
fclose($stream);
22+
23+
var_dump(curl_exec($ch1));
24+
var_dump(curl_exec($ch2));
25+
?>
26+
--CLEAN--
27+
<?php
28+
@unlink(__DIR__ . '/curl_copy_handle_stderr_uaf_src.txt');
29+
@unlink(__DIR__ . '/curl_copy_handle_stderr_uaf_stderr.txt');
30+
?>
31+
--EXPECTF--
32+
Warning: curl_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
33+
%A
34+
string(5) "Test."
35+
36+
Warning: curl_exec(): CURLOPT_STDERR resource has gone away, resetting to stderr in %s on line %d
37+
%A
38+
string(5) "Test."

0 commit comments

Comments
 (0)