]> granicus.if.org Git - php/commitdiff
Fixed bug #69511 Off-by-one bufferoverflow in php_sys_readlink
authorAnatol Belski <ab@php.net>
Tue, 19 May 2015 13:44:55 +0000 (15:44 +0200)
committerAnatol Belski <ab@php.net>
Tue, 19 May 2015 13:44:55 +0000 (15:44 +0200)
NEWS
Zend/zend_virtual_cwd.c

diff --git a/NEWS b/NEWS
index 2a3019a4c9a17700c190fda8e389b434ff5685e9..7ca0e337480d4cb368a31be653ecaf5f28e1b143 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,8 @@
   . Implemented the RFC `Fix "foreach" behavior`. (Dmitry)
   . Implemented the RFC `Generator Delegation`. (Bob)
   . Implemented the RFC ` Anonymous Class Support`. (Joe, Nikita, Dmitry)
+  . Fixed bug #69511 (Off-by-one buffer overflow in php_sys_readlink).
+    (Jan Starke, Anatol)
 
 - Curl:
   . Fixed bug #68937 (Segfault in curl_multi_exec). (Laruence)
index 28cc7f6eedd13369eb0c25ceb92b9d9d9052919c..e880775ea7cc9818731ded1eb9b09aa989d4e152 100644 (file)
@@ -237,6 +237,10 @@ CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){
        typedef BOOL (WINAPI *gfpnh_func)(HANDLE, LPTSTR, DWORD, DWORD);
        gfpnh_func pGetFinalPathNameByHandle;
 
+       if (!target_len) {
+               return -1;
+       }
+
        kernel32 = LoadLibrary("kernel32.dll");
 
        if (kernel32) {
@@ -260,8 +264,14 @@ CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){
                        return -1;
        }
 
-       dwRet = pGetFinalPathNameByHandle(hFile, target, MAXPATHLEN, VOLUME_NAME_DOS);
-       if(dwRet >= MAXPATHLEN || dwRet == 0) {
+       /* Despite MSDN has documented it won't to, the length returned by
+               GetFinalPathNameByHandleA includes the length of the
+               null terminator. This behavior is at least reproducible
+               with VS2012 and earlier, and seems not to be fixed till
+               now. Thus, correcting target_len so it's suddenly don't
+               overflown. */
+       dwRet = pGetFinalPathNameByHandle(hFile, target, target_len - 1, VOLUME_NAME_DOS);
+       if(dwRet >= target_len || dwRet >= MAXPATHLEN || dwRet == 0) {
                return -1;
        }