You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by wr...@apache.org on 2019/03/20 23:03:02 UTC

svn commit: r1855949 - in /apr/apr/trunk: CHANGES file_io/win32/dir.c file_io/win32/filestat.c include/arch/win32/apr_arch_file_io.h

Author: wrowe
Date: Wed Mar 20 23:03:02 2019
New Revision: 1855949

URL: http://svn.apache.org/viewvc?rev=1855949&view=rev
Log:
Narrow symbolic link detection on NTFS

Read the WIN32_FIND_DATA::dwReserved0 field to determine whether reparse point
is a "name surrogate".

It's probably more safe to bind to specifig tags. If provided structure
(wininfo) was not resulted from FindFile* call, then additional FindFirstFile
call is performed. However this may be unnecessary, because the alternate
GetFileInformation call is used in the case of an open file handle, and
APR_FINFO_LINK has no meaning when it comes to open files.


Submitted by: Oleg Liatte <olegliatte gmail.com>


Modified:
    apr/apr/trunk/CHANGES
    apr/apr/trunk/file_io/win32/dir.c
    apr/apr/trunk/file_io/win32/filestat.c
    apr/apr/trunk/include/arch/win32/apr_arch_file_io.h

Modified: apr/apr/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr/trunk/CHANGES?rev=1855949&r1=1855948&r2=1855949&view=diff
==============================================================================
--- apr/apr/trunk/CHANGES [utf-8] (original)
+++ apr/apr/trunk/CHANGES [utf-8] Wed Mar 20 23:03:02 2019
@@ -1,6 +1,10 @@
                                                      -*- coding: utf-8 -*-
 Changes for APR 2.0.0
 
+  *) apr_file_info: [Win32 only] Treat only "name surrogate" reparse points
+     as symlinks, and not other reparse tag types. PR47630
+     [Oleg Liatte <olegliatte gmail.com>]
+
   *) Test %ld vs. %lld to avoid compiler emits using APR_OFF_T_FMT, in the
      case of apparently equivilant long and long long types. [William Rowe] 
 

Modified: apr/apr/trunk/file_io/win32/dir.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/file_io/win32/dir.c?rev=1855949&r1=1855948&r2=1855949&view=diff
==============================================================================
--- apr/apr/trunk/file_io/win32/dir.c (original)
+++ apr/apr/trunk/file_io/win32/dir.c Wed Mar 20 23:03:02 2019
@@ -210,7 +210,7 @@ APR_DECLARE(apr_status_t) apr_dir_read(a
 #endif
 
     fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry, 
-                    0, wanted);
+                    0, 1, fname, wanted);
     finfo->pool = thedir->pool;
 
     finfo->valid |= APR_FINFO_NAME;

Modified: apr/apr/trunk/file_io/win32/filestat.c
URL: http://svn.apache.org/viewvc/apr/apr/trunk/file_io/win32/filestat.c?rev=1855949&r1=1855948&r2=1855949&view=diff
==============================================================================
--- apr/apr/trunk/file_io/win32/filestat.c (original)
+++ apr/apr/trunk/file_io/win32/filestat.c Wed Mar 20 23:03:02 2019
@@ -210,6 +210,71 @@ static apr_status_t guess_protection_bit
     return ((wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS);
 }
 
+static int reparse_point_is_link(WIN32_FILE_ATTRIBUTE_DATA *wininfo,
+    int finddata, const char *fname)
+{
+    int tag = 0;
+
+    if (!(wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+    {
+        return 0;
+    }
+
+    if (finddata)
+    {
+        // no matter A or W as we don't need file name
+        tag = ((WIN32_FIND_DATAA*)wininfo)->dwReserved0;
+    }
+    else
+    {
+        if (test_safe_name(fname) != APR_SUCCESS) {
+            return 0;
+        }
+
+#if APR_HAS_UNICODE_FS
+        IF_WIN_OS_IS_UNICODE
+        {
+            apr_wchar_t wfname[APR_PATH_MAX];
+            HANDLE hFind;
+            WIN32_FIND_DATAW fd;
+
+            if (utf8_to_unicode_path(wfname, APR_PATH_MAX, fname) != APR_SUCCESS) {
+                return 0;
+            }
+
+            hFind = FindFirstFileW(wfname, &fd);
+            if (hFind == INVALID_HANDLE_VALUE) {
+                return 0;
+            }
+
+            FindClose(hFind);
+
+            tag = fd.dwReserved0;
+        }
+#endif
+#if APR_HAS_ANSI_FS || 1
+        ELSE_WIN_OS_IS_ANSI
+        {
+            HANDLE hFind;
+            WIN32_FIND_DATAA fd;
+
+            hFind = FindFirstFileA(fname, &fd);
+            if (hFind == INVALID_HANDLE_VALUE) {
+                return 0;
+            }
+
+            FindClose(hFind);
+
+            tag = fd.dwReserved0;
+        }
+#endif
+    }
+
+    // Test "Name surrogate bit" to detect any kind of symbolic link
+    // See https://docs.microsoft.com/en-us/windows/desktop/fileio/reparse-point-tags
+    return tag & 0x20000000;
+}
+
 apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile, 
                         apr_int32_t wanted, int whatfile)
 {
@@ -351,7 +416,10 @@ apr_status_t more_finfo(apr_finfo_t *fin
  */
 int fillin_fileinfo(apr_finfo_t *finfo, 
                     WIN32_FILE_ATTRIBUTE_DATA *wininfo, 
-                    int byhandle, apr_int32_t wanted) 
+                    int byhandle,
+                    int finddata,
+                    const char *fname,
+                    apr_int32_t wanted)
 {
     DWORD *sizes = &wininfo->nFileSizeHigh + byhandle;
     int warn = 0;
@@ -372,7 +440,7 @@ int fillin_fileinfo(apr_finfo_t *finfo,
 #endif
 
     if (wanted & APR_FINFO_LINK &&
-        wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+        reparse_point_is_link(wininfo, finddata, fname)) {
         finfo->filetype = APR_LNK;
     }
     else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
@@ -449,7 +517,7 @@ APR_DECLARE(apr_status_t) apr_file_info_
         return apr_get_os_error();
     }
 
-    fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, wanted);
+    fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 1, 0, thefile->fname, wanted);
 
     if (finfo->filetype == APR_REG)
     {
@@ -520,6 +588,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
         WIN32_FIND_DATAA n;
         WIN32_FILE_ATTRIBUTE_DATA i;
     } FileInfo;
+    int finddata = 0;
     
     /* Catch fname length == MAX_PATH since GetFileAttributesEx fails 
      * with PATH_NOT_FOUND.  We would rather indicate length error than 
@@ -555,7 +624,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
         if ((rv = utf8_to_unicode_path(wfname, sizeof(wfname) 
                                             / sizeof(apr_wchar_t), fname)))
             return rv;
-        if (!(wanted & APR_FINFO_NAME)) {
+        if (!(wanted & (APR_FINFO_NAME | APR_FINFO_LINK))) {
             if (!GetFileAttributesExW(wfname, GetFileExInfoStandard, 
                                       &FileInfo.i))
                 return apr_get_os_error();
@@ -565,7 +634,6 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
              * since we want the true name, and set aside a long
              * enough string to handle the longest file name.
              */
-            char tmpname[APR_FILE_MAX * 3 + 1];
             HANDLE hFind;
             if ((rv = test_safe_name(fname)) != APR_SUCCESS) {
                 return rv;
@@ -574,11 +642,17 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
             if (hFind == INVALID_HANDLE_VALUE)
                 return apr_get_os_error();
             FindClose(hFind);
-            if (unicode_to_utf8_path(tmpname, sizeof(tmpname), 
-                                     FileInfo.w.cFileName)) {
-                return APR_ENAMETOOLONG;
+            finddata = 1;
+
+            if (wanted & APR_FINFO_NAME)
+            {
+                char tmpname[APR_FILE_MAX * 3 + 1];
+                if (unicode_to_utf8_path(tmpname, sizeof(tmpname),
+                                         FileInfo.w.cFileName)) {
+                    return APR_ENAMETOOLONG;
+                }
+                filename = apr_pstrdup(pool, tmpname);
             }
-            filename = apr_pstrdup(pool, tmpname);
         }
     }
 #endif
@@ -590,7 +664,7 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
         rv = apr_filepath_root(&root, &test, APR_FILEPATH_NATIVE, pool);
         isroot = (root && *root && !(*test));
 
-        if ((apr_os_level >= APR_WIN_98) && (!(wanted & APR_FINFO_NAME) || isroot))
+        if ((apr_os_level >= APR_WIN_98) && (!(wanted & (APR_FINFO_NAME | APR_FINFO_LINK)) || isroot))
         {
             /* cannot use FindFile on a Win98 root, it returns \*
              * GetFileAttributesExA is not available on Win95
@@ -632,16 +706,19 @@ APR_DECLARE(apr_status_t) apr_stat(apr_f
             hFind = FindFirstFileA(fname, &FileInfo.n);
             if (hFind == INVALID_HANDLE_VALUE) {
                 return apr_get_os_error();
-    	    } 
+            } 
             FindClose(hFind);
-            filename = apr_pstrdup(pool, FileInfo.n.cFileName);
+            finddata = 1;
+            if (wanted & APR_FINFO_NAME) {
+                filename = apr_pstrdup(pool, FileInfo.n.cFileName);
+            }
         }
     }
 #endif
 
     if (ident_rv != APR_INCOMPLETE) {
         if (fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) &FileInfo, 
-                            0, wanted))
+                            0, finddata, fname, wanted))
         {
             /* Go the extra mile to assure we have a file.  WinNT/2000 seems
              * to reliably translate char devices to the path '\\.\device'

Modified: apr/apr/trunk/include/arch/win32/apr_arch_file_io.h
URL: http://svn.apache.org/viewvc/apr/apr/trunk/include/arch/win32/apr_arch_file_io.h?rev=1855949&r1=1855948&r2=1855949&view=diff
==============================================================================
--- apr/apr/trunk/include/arch/win32/apr_arch_file_io.h (original)
+++ apr/apr/trunk/include/arch/win32/apr_arch_file_io.h Wed Mar 20 23:03:02 2019
@@ -135,7 +135,8 @@ void *res_name_from_filename(const char
 
 /* Private function for apr_stat/lstat/getfileinfo/dir_read */
 int fillin_fileinfo(apr_finfo_t *finfo, WIN32_FILE_ATTRIBUTE_DATA *wininfo, 
-                    int byhandle, apr_int32_t wanted);
+                    int byhandle, int finddata, const char *fname,
+                    apr_int32_t wanted);
 
 /* Private function that extends apr_stat/lstat/getfileinfo/dir_read */
 apr_status_t more_finfo(apr_finfo_t *finfo, const void *ufile,