Skip to content

Commit 0c4e3b6

Browse files
committed
ext/standard: Keep IPTC headers local to each call
Give each iptcembed() invocation its own APP13 header so concurrent calls and reentrant output handlers cannot overwrite its pending segment length. Closes GH-24100
1 parent 808685f commit 0c4e3b6

3 files changed

Lines changed: 37 additions & 2 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ PHP NEWS
201201
- Standard:
202202
. Fixed sha1_file() returning a digest for incomplete data after a stream
203203
read failure. (Ilia Alshanetsky)
204+
. Fixed iptcembed() corrupting JPEG headers when called recursively from an
205+
output handler. (Ilia Alshanetsky)
204206
. Fixed three Windows-only proc_open() defects: an uninitialized
205207
PROCESS_INFORMATION, an indeterminate comspec pointer after a failed
206208
lookup, and an unchecked CreateFileA() failure. (Ilia Alshanetsky)

‎ext/standard/iptc.c‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,10 @@ static int php_iptc_next_marker(FILE *fp, int spool, unsigned char **spoolbuf, c
175175
}
176176
/* }}} */
177177

178-
static char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
179-
180178
/* {{{ Embed binary IPTC data into a JPEG image. */
181179
PHP_FUNCTION(iptcembed)
182180
{
181+
char psheader[] = "\xFF\xED\0\0Photoshop 3.0\08BIM\x04\x04\0\0\0\0";
183182
char *iptcdata, *jpeg_file;
184183
size_t iptcdata_len, jpeg_file_len;
185184
zend_long spool = 0;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
iptcembed() keeps APP13 headers local during reentrant output handling
3+
--FILE--
4+
<?php
5+
$file = __DIR__ . '/iptcembed_reentrant.jpg';
6+
file_put_contents($file, "\xff\xd8\xff\xe0\x00\x02\xff\xda\x00\x02");
7+
$output = '';
8+
$nested = false;
9+
ob_start(function ($chunk) use (&$output, &$nested, $file) {
10+
$output .= $chunk;
11+
if (!$nested && str_ends_with($output, "\xff\xed")) {
12+
$nested = true;
13+
iptcembed(str_repeat('B', 256), $file, 0);
14+
}
15+
return '';
16+
}, 1);
17+
iptcembed('AA', $file, 2);
18+
ob_end_flush();
19+
$start = strpos($output, "\xff\xed");
20+
echo "Nested call: ";
21+
var_dump($nested);
22+
echo "APP13 length: ";
23+
var_dump(unpack('n', substr($output, $start + 2, 2))[1]);
24+
echo "Outer payload: ";
25+
var_dump(substr($output, $start + 30, 2));
26+
?>
27+
--CLEAN--
28+
<?php
29+
unlink(__DIR__ . '/iptcembed_reentrant.jpg');
30+
?>
31+
--EXPECT--
32+
Nested call: bool(true)
33+
APP13 length: int(30)
34+
Outer payload: string(2) "AA"

0 commit comments

Comments
 (0)