summaryrefslogtreecommitdiffstats
path: root/bug73549.patch
blob: 5c39852277a98e30d2e571b5bd6d5569e1d9c338 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
From 5049ef2f1c496c4964cd147e185c1f765ab0347b Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Thu, 17 Nov 2016 13:44:30 +0100
Subject: [PATCH] Fix #73549: Use after free when stream is passed to imagepng

If a stream is passed to imagepng() or other image output functions,
opposed to a filename, we must not close this stream.
---
 NEWS                       |  3 +++
 ext/gd/gd_ctx.c            | 18 +++++++++++++++++-
 ext/gd/tests/bug73549.phpt | 22 ++++++++++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 ext/gd/tests/bug73549.phpt

diff --git a/ext/gd/gd_ctx.c b/ext/gd/gd_ctx.c
index 34a9a00..acb96e1 100644
--- a/ext/gd/gd_ctx.c
+++ b/ext/gd/gd_ctx.c
@@ -62,6 +62,16 @@ static int _php_image_stream_putbuf(struct gdIOCtx *ctx, const void* buf, int l)
 
 static void _php_image_stream_ctxfree(struct gdIOCtx *ctx)
 {
+	if(ctx->data) {
+		ctx->data = NULL;
+	}
+	if(ctx) {
+		efree(ctx);
+	}
+} /* }}} */
+
+static void _php_image_stream_ctxfreeandclose(struct gdIOCtx *ctx) /* {{{ */
+{
 	TSRMLS_FETCH();
 
 	if(ctx->data) {
@@ -87,6 +97,7 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type,
 	gdIOCtx *ctx = NULL;
 	zval *to_zval = NULL;
 	php_stream *stream;
+	int close_stream = 1;
 
 	/* The third (quality) parameter for Wbmp stands for the threshold when called from image2wbmp().
 	 * The third (quality) parameter for Wbmp and Xbm stands for the foreground color index when called
@@ -123,6 +134,7 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type,
 			if (stream == NULL) {
 				RETURN_FALSE;
 			}
+			close_stream = 0;
 		} else if (Z_TYPE_P(to_zval) == IS_STRING) {
 			if (CHECK_ZVAL_NULL_PATH(to_zval)) {
 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid 2nd parameter, filename must not contain null bytes");
@@ -159,7 +171,11 @@ static void _php_image_output_ctx(INTERNAL_FUNCTION_PARAMETERS, int image_type,
 		ctx = emalloc(sizeof(gdIOCtx));
 		ctx->putC = _php_image_stream_putc;
 		ctx->putBuf = _php_image_stream_putbuf;
-		ctx->gd_free = _php_image_stream_ctxfree;
+		if (close_stream) {
+			ctx->gd_free = _php_image_stream_ctxfreeandclose;
+		} else {
+			ctx->gd_free = _php_image_stream_ctxfree;
+		}
 		ctx->data = (void *)stream;
 	}
 
diff --git a/ext/gd/tests/bug73549.phpt b/ext/gd/tests/bug73549.phpt
new file mode 100644
index 0000000..e0cc6cf
--- /dev/null
+++ b/ext/gd/tests/bug73549.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #73549 (Use after free when stream is passed to imagepng)
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip gd extension not available');
+?>
+--FILE--
+<?php
+$stream = fopen(__DIR__ . DIRECTORY_SEPARATOR . 'bug73549.png', 'w');
+$im = imagecreatetruecolor(8, 8);
+var_dump(imagepng($im, $stream));
+var_dump($stream);
+?>
+===DONE===
+--EXPECTF--
+bool(true)
+resource(%d) of type (stream)
+===DONE===
+--CLEAN--
+<?php
+unlink(__DIR__ . DIRECTORY_SEPARATOR . 'bug73549.png');
+?>
-- 
2.1.4