Skip to content

Commit 94fa2a4

Browse files
committed
Fix potential OOB read in zend_dirname() on Windows
Only on Windows `IS_SLASH_P()` may read the previous byte, and so may in unlikely cases read one byte out of bounds. Since `IS_SLASH_P()` is in a public header (albeit not likely to be used by external extensions or SAPIs), we introduce `IS_SLASH_P_EX()` which accepts a second argument to prevent that OOB read. It should be noted that the PHP userland function `dirname()` is not affected by this issue, since it does not call `zend_dirname()` on Windows. Closes GH-16995.
1 parent 9bae893 commit 94fa2a4

File tree

3 files changed

+9
-3
lines changed

3 files changed

+9
-3
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ PHP NEWS
1919
. Fixed bug GH-16630 (UAF in lexer with encoding translation and heredocs).
2020
(nielsdos)
2121
. Fix is_zend_ptr() huge block comparison. (nielsdos)
22+
. Fixed potential OOB read in zend_dirname() on Windows. (cmb)
2223

2324
- Curl:
2425
. Fix various memory leaks in curl mime handling. (nielsdos)

Zend/zend_compile.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,7 +1997,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
19971997
}
19981998

19991999
/* Strip trailing slashes */
2000-
while (end >= path && IS_SLASH_P(end)) {
2000+
while (end >= path && IS_SLASH_P_EX(end, end == path)) {
20012001
end--;
20022002
}
20032003
if (end < path) {
@@ -2008,7 +2008,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
20082008
}
20092009

20102010
/* Strip filename */
2011-
while (end >= path && !IS_SLASH_P(end)) {
2011+
while (end >= path && !IS_SLASH_P_EX(end, end == path)) {
20122012
end--;
20132013
}
20142014
if (end < path) {
@@ -2019,7 +2019,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
20192019
}
20202020

20212021
/* Strip slashes which came before the file name */
2022-
while (end >= path && IS_SLASH_P(end)) {
2022+
while (end >= path && IS_SLASH_P_EX(end, end == path)) {
20232023
end--;
20242024
}
20252025
if (end < path) {

Zend/zend_virtual_cwd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,11 @@ typedef unsigned short mode_t;
7373
#define DEFAULT_SLASH '\\'
7474
#define DEFAULT_DIR_SEPARATOR ';'
7575
#define IS_SLASH(c) ((c) == '/' || (c) == '\\')
76+
// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead
7677
#define IS_SLASH_P(c) (*(c) == '/' || \
7778
(*(c) == '\\' && !IsDBCSLeadByte(*(c-1))))
79+
#define IS_SLASH_P_EX(c, first_byte) (*(c) == '/' || \
80+
(*(c) == '\\' && ((first_byte) || !IsDBCSLeadByte(*(c-1)))))
7881

7982
/* COPY_WHEN_ABSOLUTE is 2 under Win32 because by chance both regular absolute paths
8083
in the file system and UNC paths need copying of two characters */
@@ -98,7 +101,9 @@ typedef unsigned short mode_t;
98101
#endif
99102

100103
#define IS_SLASH(c) ((c) == '/')
104+
// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead
101105
#define IS_SLASH_P(c) (*(c) == '/')
106+
#define IS_SLASH_P_EX(c, first_byte) IS_SLASH_P(c)
102107

103108
#endif
104109

0 commit comments

Comments
 (0)