From 503c971bdf5cf2bd5a5ba8a6514551a607360a53 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 29 Nov 2024 18:08:25 +0100 Subject: [PATCH 1/2] 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. --- Zend/zend_compile.c | 6 +++--- Zend/zend_virtual_cwd.h | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 38d378a4175bb..52b3417234cf7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1997,7 +1997,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip trailing slashes */ - while (end >= path && IS_SLASH_P(end)) { + while (end >= path && IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { @@ -2008,7 +2008,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip filename */ - while (end >= path && !IS_SLASH_P(end)) { + while (end >= path && !IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { @@ -2019,7 +2019,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len) } /* Strip slashes which came before the file name */ - while (end >= path && IS_SLASH_P(end)) { + while (end >= path && IS_SLASH_P_EX(end, end == path)) { end--; } if (end < path) { diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h index 728e3ba69d888..f764927ea0193 100644 --- a/Zend/zend_virtual_cwd.h +++ b/Zend/zend_virtual_cwd.h @@ -73,8 +73,11 @@ typedef unsigned short mode_t; #define DEFAULT_SLASH '\\' #define DEFAULT_DIR_SEPARATOR ';' #define IS_SLASH(c) ((c) == '/' || (c) == '\\') +// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead #define IS_SLASH_P(c) (*(c) == '/' || \ (*(c) == '\\' && !IsDBCSLeadByte(*(c-1)))) +#define IS_SLASH_P_EX(c, first_byte) (*(c) == '/' || \ + (*(c) == '\\' && ((first_byte) || !IsDBCSLeadByte(*(c-1))))) /* COPY_WHEN_ABSOLUTE is 2 under Win32 because by chance both regular absolute paths in the file system and UNC paths need copying of two characters */ @@ -98,7 +101,9 @@ typedef unsigned short mode_t; #endif #define IS_SLASH(c) ((c) == '/') +// IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead #define IS_SLASH_P(c) (*(c) == '/') +#define IS_SLASH_P_EX(c, first_byte) (*(c) == '/') #endif From 3cc3ba3981e9c6d00ae677bf48e32858fb509c1a Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 29 Nov 2024 19:43:07 +0100 Subject: [PATCH 2/2] Update Zend/zend_virtual_cwd.h --- Zend/zend_virtual_cwd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h index f764927ea0193..28cbf6300b8ec 100644 --- a/Zend/zend_virtual_cwd.h +++ b/Zend/zend_virtual_cwd.h @@ -103,7 +103,7 @@ typedef unsigned short mode_t; #define IS_SLASH(c) ((c) == '/') // IS_SLASH_P() may read the previous char on Windows, which may be OOB; use IS_SLASH_P_EX() instead #define IS_SLASH_P(c) (*(c) == '/') -#define IS_SLASH_P_EX(c, first_byte) (*(c) == '/') +#define IS_SLASH_P_EX(c, first_byte) IS_SLASH_P(c) #endif