Skip to content

Commit 5161ceb

Browse files
committed
Fix bug #52752 by not using mmap() to lex files
Using mmap() is unsafe under concurrent modification. If the file is truncated, access past the end of the file may occur, which will generate a SIGBUS error. Even if the length does not change, the contents may, which is a situation that the lexer certainly is not prepared to deal with either. Reproduce with test.php: <?php file_put_contents(__DIR__ . '/test.tpl', 'AAA<?php $string = "' . str_repeat('A', mt_rand(1, 256 * 1024)) . '"; ?>BBB' . "\r\n"); require_once __DIR__ . '/test.tpl'; And: for ((n=0;n<100;n++)); do sapi/cli/php test.php & done
1 parent 292354f commit 5161ceb

File tree

4 files changed

+3
-110
lines changed

4 files changed

+3
-110
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ PHP NEWS
88
(Nikita)
99
. Fixed bug #78066 (PHP eats the first byte of a program that comes from
1010
process substitution). (Nikita)
11+
. Fixed bug #52752 (Crash when lexing). (Nikita)
1112

1213
- Libxml:
1314
. Fixed bug #78279 (libxml_disable_entity_loader settings is shared between

Zend/zend_stream.c

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,6 @@
2323
#include "zend_compile.h"
2424
#include "zend_stream.h"
2525

26-
#if HAVE_MMAP
27-
# if HAVE_UNISTD_H
28-
# include <unistd.h>
29-
# if defined(_SC_PAGESIZE)
30-
# define REAL_PAGE_SIZE sysconf(_SC_PAGESIZE);
31-
# elif defined(_SC_PAGE_SIZE)
32-
# define REAL_PAGE_SIZE sysconf(_SC_PAGE_SIZE);
33-
# endif
34-
# endif
35-
# if HAVE_SYS_MMAN_H
36-
# include <sys/mman.h>
37-
# endif
38-
# ifndef REAL_PAGE_SIZE
39-
# ifdef PAGE_SIZE
40-
# define REAL_PAGE_SIZE PAGE_SIZE
41-
# else
42-
# define REAL_PAGE_SIZE 4096
43-
# endif
44-
# endif
45-
#endif
46-
4726
ZEND_DLIMPORT int isatty(int fd);
4827

4928
static size_t zend_stream_stdio_reader(void *handle, char *buf, size_t len) /* {{{ */
@@ -73,17 +52,10 @@ static size_t zend_stream_stdio_fsizer(void *handle) /* {{{ */
7352
} /* }}} */
7453

7554
static void zend_stream_unmap(zend_stream *stream) { /* {{{ */
76-
#if HAVE_MMAP
77-
if (stream->mmap.map) {
78-
munmap(stream->mmap.map, stream->mmap.len + ZEND_MMAP_AHEAD);
79-
} else
80-
#endif
8155
if (stream->mmap.buf) {
8256
efree(stream->mmap.buf);
8357
}
8458
stream->mmap.len = 0;
85-
stream->mmap.pos = 0;
86-
stream->mmap.map = 0;
8759
stream->mmap.buf = 0;
8860
stream->handle = stream->mmap.old_handle;
8961
} /* }}} */
@@ -197,7 +169,6 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
197169
break;
198170

199171
case ZEND_HANDLE_MAPPED:
200-
file_handle->handle.stream.mmap.pos = 0;
201172
*buf = file_handle->handle.stream.mmap.buf;
202173
*len = file_handle->handle.stream.mmap.len;
203174
return SUCCESS;
@@ -215,30 +186,6 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
215186
file_handle->type = ZEND_HANDLE_STREAM; /* we might still be _FP but we need fsize() work */
216187

217188
if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) {
218-
#if HAVE_MMAP
219-
size_t page_size = REAL_PAGE_SIZE;
220-
221-
if (file_handle->handle.fp &&
222-
size != 0 &&
223-
((size - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD) {
224-
/* *buf[size] is zeroed automatically by the kernel */
225-
*buf = mmap(0, size + ZEND_MMAP_AHEAD, PROT_READ, MAP_PRIVATE, fileno(file_handle->handle.fp), 0);
226-
if (*buf != MAP_FAILED) {
227-
zend_long offset = ftell(file_handle->handle.fp);
228-
file_handle->handle.stream.mmap.map = *buf;
229-
230-
if (offset != -1) {
231-
*buf += offset;
232-
size -= offset;
233-
}
234-
file_handle->handle.stream.mmap.buf = *buf;
235-
file_handle->handle.stream.mmap.len = size;
236-
237-
goto return_mapped;
238-
}
239-
}
240-
#endif
241-
file_handle->handle.stream.mmap.map = 0;
242189
file_handle->handle.stream.mmap.buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD);
243190
file_handle->handle.stream.mmap.len = zend_stream_read(file_handle, *buf, size);
244191
} else {
@@ -255,7 +202,6 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
255202
remain = size;
256203
}
257204
}
258-
file_handle->handle.stream.mmap.map = 0;
259205
file_handle->handle.stream.mmap.len = size;
260206
if (size && remain < ZEND_MMAP_AHEAD) {
261207
*buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD);
@@ -271,11 +217,7 @@ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t
271217
if (ZEND_MMAP_AHEAD) {
272218
memset(file_handle->handle.stream.mmap.buf + file_handle->handle.stream.mmap.len, 0, ZEND_MMAP_AHEAD);
273219
}
274-
#if HAVE_MMAP
275-
return_mapped:
276-
#endif
277220
file_handle->type = ZEND_HANDLE_MAPPED;
278-
file_handle->handle.stream.mmap.pos = 0;
279221
file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle;
280222
file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer;
281223
file_handle->handle.stream.handle = &file_handle->handle.stream;

Zend/zend_stream.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ typedef enum {
4444

4545
typedef struct _zend_mmap {
4646
size_t len;
47-
size_t pos;
48-
void *map;
4947
char *buf;
5048
void *old_handle;
5149
zend_stream_closer_t old_closer;

main/main.c

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -84,27 +84,6 @@
8484
#include "rfc1867.h"
8585

8686
#include "ext/standard/html_tables.h"
87-
88-
#if HAVE_MMAP || defined(PHP_WIN32)
89-
# if HAVE_UNISTD_H
90-
# include <unistd.h>
91-
# if defined(_SC_PAGESIZE)
92-
# define REAL_PAGE_SIZE sysconf(_SC_PAGESIZE);
93-
# elif defined(_SC_PAGE_SIZE)
94-
# define REAL_PAGE_SIZE sysconf(_SC_PAGE_SIZE);
95-
# endif
96-
# endif
97-
# if HAVE_SYS_MMAN_H
98-
# include <sys/mman.h>
99-
# endif
100-
# ifndef REAL_PAGE_SIZE
101-
# ifdef PAGE_SIZE
102-
# define REAL_PAGE_SIZE PAGE_SIZE
103-
# else
104-
# define REAL_PAGE_SIZE 4096
105-
# endif
106-
# endif
107-
#endif
10887
/* }}} */
10988

11089
PHPAPI int (*php_register_internal_extensions_func)(void) = php_register_internal_extensions;
@@ -1583,13 +1562,6 @@ static void php_zend_stream_closer(void *handle) /* {{{ */
15831562
}
15841563
/* }}} */
15851564

1586-
static void php_zend_stream_mmap_closer(void *handle) /* {{{ */
1587-
{
1588-
php_stream_mmap_unmap((php_stream*)handle);
1589-
php_zend_stream_closer(handle);
1590-
}
1591-
/* }}} */
1592-
15931565
static size_t php_zend_stream_fsizer(void *handle) /* {{{ */
15941566
{
15951567
php_stream_statbuf ssb;
@@ -1608,38 +1580,18 @@ static int php_stream_open_for_zend(const char *filename, zend_file_handle *hand
16081580

16091581
PHPAPI int php_stream_open_for_zend_ex(const char *filename, zend_file_handle *handle, int mode) /* {{{ */
16101582
{
1611-
char *p;
1612-
size_t len, mapped_len;
16131583
php_stream *stream = php_stream_open_wrapper((char *)filename, "rb", mode, &handle->opened_path);
16141584

16151585
if (stream) {
1616-
#if HAVE_MMAP || defined(PHP_WIN32)
1617-
size_t page_size = REAL_PAGE_SIZE;
1618-
#endif
1619-
1586+
handle->type = ZEND_HANDLE_STREAM;
16201587
handle->filename = (char*)filename;
16211588
handle->free_filename = 0;
16221589
handle->handle.stream.handle = stream;
16231590
handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
16241591
handle->handle.stream.fsizer = php_zend_stream_fsizer;
16251592
handle->handle.stream.isatty = 0;
1626-
/* can we mmap immediately? */
16271593
memset(&handle->handle.stream.mmap, 0, sizeof(handle->handle.stream.mmap));
1628-
len = php_zend_stream_fsizer(stream);
1629-
if (len != 0
1630-
#if HAVE_MMAP || defined(PHP_WIN32)
1631-
&& ((len - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD
1632-
#endif
1633-
&& php_stream_mmap_possible(stream)
1634-
&& (p = php_stream_mmap_range(stream, 0, len, PHP_STREAM_MAP_MODE_SHARED_READONLY, &mapped_len)) != NULL) {
1635-
handle->handle.stream.closer = php_zend_stream_mmap_closer;
1636-
handle->handle.stream.mmap.buf = p;
1637-
handle->handle.stream.mmap.len = mapped_len;
1638-
handle->type = ZEND_HANDLE_MAPPED;
1639-
} else {
1640-
handle->handle.stream.closer = php_zend_stream_closer;
1641-
handle->type = ZEND_HANDLE_STREAM;
1642-
}
1594+
handle->handle.stream.closer = php_zend_stream_closer;
16431595
/* suppress warning if this stream is not explicitly closed */
16441596
php_stream_auto_cleanup(stream);
16451597

0 commit comments

Comments
 (0)