From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 8351D395C834; Wed, 2 Dec 2020 15:16:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8351D395C834 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin] Cygwin: add flag to indicate reparse points unknown to WinAPI X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: e9bc4cccefbdc989bafb4b6c58c8892eb07ce277 X-Git-Newrev: aec6479820fee5f71d50930bf0dde2bbf386bd4b Message-Id: <20201202151628.8351D395C834@sourceware.org> Date: Wed, 2 Dec 2020 15:16:28 +0000 (GMT) X-BeenThere: cygwin-cvs@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin core component git logs List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Dec 2020 15:16:28 -0000 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=aec6479820fee5f71d50930bf0dde2bbf386bd4b commit aec6479820fee5f71d50930bf0dde2bbf386bd4b Author: Corinna Vinschen Date: Wed Dec 2 16:12:58 2020 +0100 Cygwin: add flag to indicate reparse points unknown to WinAPI https://cygwin.com/pipermail/cygwin/2020-December/246938.html reports a problem where, when adding a Cygwin default symlink to $PATH since Cygwin 3.1.5, $PATH handling appears to be broken. 3.1.5 switched to WSL symlinks as Cygwin default symlinks. A piece of code in path handling skips resolving reparse points if they are the last component in the path. Thus a reparse point in $PATH is not resolved but converted to Windows path syntax verbatim. If you do this with a WSL symlink, certain WinAPI functions fail. The underlying $PATH handling fails to recognize the reparse point in $PATH and returns with STATUS_IO_REPARSE_TAG_NOT_HANDLED. As a result, the calling WinAPI function fails, most prominently so CreateProcess. Fix this problem by adding a PATH_REP_NOAPI bit to path_types and a matching method path_conv::is_winapi_reparse_point(). Right now this flag is set for WSL symlinks and Cygwin AF_UNIX sockets (new type implemented as reparse points). The aforementioned code skipping repare point path resolution calls is_winapi_reparse_point() rather than is_known_reparse_point(), so now path resolution is only skipped for reparse points known to WinAPI. Signed-off-by: Corinna Vinschen Diff: --- winsup/cygwin/path.cc | 8 ++++---- winsup/cygwin/path.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 7e6243d32..abd3687df 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1017,7 +1017,7 @@ path_conv::check (const char *src, unsigned opt, { if (component == 0 && (!(opt & PC_SYM_FOLLOW) - || (is_known_reparse_point () + || (is_winapi_reparse_point () && (opt & PC_SYM_NOFOLLOW_REP)))) { /* Usually a trailing slash requires to follow a symlink, @@ -2622,7 +2622,7 @@ check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp, } RtlInitCountedUnicodeString (psymbuf, utf16_buf, utf16_bufsize * sizeof (WCHAR)); - return PATH_SYMLINK | PATH_REP; + return PATH_SYMLINK | PATH_REP | PATH_REP_NOAPI; } return -EIO; } @@ -2632,10 +2632,10 @@ check_reparse_point_target (HANDLE h, bool remote, PREPARSE_DATA_BUFFER rp, if (memcmp (CYGWIN_SOCKET_GUID, &rgp->ReparseGuid, sizeof (GUID)) == 0) #ifdef __WITH_AF_UNIX - return PATH_SOCKET | PATH_REP; + return PATH_SOCKET | PATH_REP | PATH_REP_NOAPI; #else /* Recognize this as a reparse point but not as a socket. */ - return PATH_REP; + return PATH_REP | PATH_REP_NOAPI; #endif } return 0; diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 45a047ad3..62bd5ddd5 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -71,6 +71,7 @@ enum path_types PATH_SYMLINK = _BIT ( 4), /* symlink understood by Cygwin */ PATH_SOCKET = _BIT ( 5), /* AF_UNIX socket file */ PATH_RESOLVE_PROCFD = _BIT ( 6), /* fd symlink via /proc */ + PATH_REP_NOAPI = _BIT ( 7), /* rep. point unknown to WinAPI */ PATH_DONT_USE = _BIT (31) /* conversion to signed happens. */ }; @@ -179,7 +180,18 @@ class path_conv } int issymlink () const {return path_flags & PATH_SYMLINK;} int is_lnk_symlink () const {return path_flags & PATH_LNK;} + /* This indicates any known reparse point */ int is_known_reparse_point () const {return path_flags & PATH_REP;} + /* This indicates any known reparse point, handled sanely by WinAPI. + The difference is crucial: WSL symlinks, for instance, are known + reparse points, so we want to open them as reparse points usually. + However they are foreign to WinAPI and not handled sanely. If one + is part of $PATH, WinAPI functions may fail under the hood with + STATUS_IO_REPARSE_TAG_NOT_HANDLED. */ + int is_winapi_reparse_point () const + { + return (path_flags & (PATH_REP | PATH_REP_NOAPI)) == PATH_REP; + } int isdevice () const {return dev.not_device (FH_FS) && dev.not_device (FH_FIFO);} int isfifo () const {return dev.is_device (FH_FIFO);} int isspecial () const {return dev.not_device (FH_FS);}