Re: [PATCH] Cygwin: normalize_win32_path: allow drive without trailing backslash

2020-01-17 Thread Corinna Vinschen
On Jan 15 17:46, Ken Brown wrote:
> Commit 283cb372, "Cygwin: normalize_win32_path: improve error
> checking", required a prefix '\\?\' or '\??\' in the source path to be
> followed by 'UNC\' or 'X:\', where X is a drive letter.  That was too
> restrictive, since it disallowed the paths '\\?\X: and '\??\X:'.  This
> caused problems when a user tried to use the root of a drive as the
> Cygwin installation root, as reported here:
> 
>   https://cygwin.com/ml/cygwin/2020-01/msg00111.html
> 
> Modify the requirement so that '\??\X:' and '\\?\X:' are now allowed
> as source paths, without a trailing backslash.
> ---
>  winsup/cygwin/path.cc | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
> index c8e73c64c..a00270210 100644
> --- a/winsup/cygwin/path.cc
> +++ b/winsup/cygwin/path.cc
> @@ -1411,7 +1411,7 @@ normalize_win32_path (const char *src, char *dst, char 
> *&tail)
>&& src[2] == '?' && isdirsep (src[3]))
>  {
>src += 4;
> -  if (isdrive (src) && isdirsep (src[2]))
> +  if (isdrive (src) && (isdirsep (src[2]) || !src[2]))
>   beg_src_slash = false;
>else if (!strncmp (src, "UNC", 3) && isdirsep (src[3]))
>   /* native UNC path */
> -- 
> 2.21.0

Looks good, please push.


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer


signature.asc
Description: PGP signature


Re: [PATCH] Cygwin: allow opening an AF_LOCAL/AF_UNIX socket with O_PATH

2020-01-17 Thread Corinna Vinschen
On Jan 16 18:34, Ken Brown wrote:
> If that flag is not set, or if an attempt is made to open a different
> type of socket, the errno is now EOPNOTSUPP instead of ENXIO.  This is
> consistent with POSIX, starting with the 2016 edition.  Earlier
> editions were silent on this issue.
> ---
>  winsup/cygwin/fhandler.h   |  2 ++
>  winsup/cygwin/fhandler_socket.cc   |  2 +-
>  winsup/cygwin/fhandler_socket_local.cc | 16 
>  winsup/cygwin/fhandler_socket_unix.cc  | 16 
>  winsup/cygwin/release/3.1.3|  7 +++
>  winsup/doc/new-features.xml|  6 ++
>  6 files changed, 48 insertions(+), 1 deletion(-)

I'm a bit concerned here that some function calls might succeed
accidentally or even crash, given that the original socket code doesn't
cope with the nohandle flag.  Did you perform some basic testing?


Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer


signature.asc
Description: PGP signature


Re: [PATCH] Cygwin: allow opening an AF_LOCAL/AF_UNIX socket with O_PATH

2020-01-17 Thread Corinna Vinschen
On Jan 17 10:48, Corinna Vinschen wrote:
> On Jan 16 18:34, Ken Brown wrote:
> > If that flag is not set, or if an attempt is made to open a different
> > type of socket, the errno is now EOPNOTSUPP instead of ENXIO.  This is
> > consistent with POSIX, starting with the 2016 edition.  Earlier
> > editions were silent on this issue.
> > ---
> >  winsup/cygwin/fhandler.h   |  2 ++
> >  winsup/cygwin/fhandler_socket.cc   |  2 +-
> >  winsup/cygwin/fhandler_socket_local.cc | 16 
> >  winsup/cygwin/fhandler_socket_unix.cc  | 16 
> >  winsup/cygwin/release/3.1.3|  7 +++
> >  winsup/doc/new-features.xml|  6 ++
> >  6 files changed, 48 insertions(+), 1 deletion(-)
> 
> I'm a bit concerned here that some function calls might succeed
> accidentally or even crash, given that the original socket code doesn't
> cope with the nohandle flag.  Did you perform some basic testing?

Iow, do the usual socket calls on a fhandler_socket_local return EBADF
now?  Ignoring fhandler_socket_unix for now.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer


signature.asc
Description: PGP signature


Re: [PATCH v3 2/3] Cygwin: readlinkat, fchownat: allow pathname to be empty

2020-01-17 Thread Corinna Vinschen
On Jan 16 20:50, Ken Brown wrote:
> Following Linux, allow the pathname argument to be an empty string,
> provided the dirfd argument refers to a symlink opened with O_PATH and
> O_NOFOLLOW.  The readlinkat or fchownat call then operates on that
> symlink.  In the case of fchownat, the call must specify the
> AT_EMPTY_PATH flag.
> ---
>  winsup/cygwin/syscalls.cc | 40 ++-
>  1 file changed, 35 insertions(+), 5 deletions(-)
> 
> diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
> index 038a316db..3d87fd685 100644
> --- a/winsup/cygwin/syscalls.cc
> +++ b/winsup/cygwin/syscalls.cc
> @@ -4785,14 +4785,29 @@ fchownat (int dirfd, const char *pathname, uid_t uid, 
> gid_t gid, int flags)
>tmp_pathbuf tp;
>__try
>  {
> -  if (flags & ~AT_SYMLINK_NOFOLLOW)
> +  if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
>   {
> set_errno (EINVAL);
> __leave;
>   }
>char *path = tp.c_get ();
> -  if (gen_full_path_at (path, dirfd, pathname))
> - __leave;
> +  int res = gen_full_path_at (path, dirfd, pathname);
> +  if (res)
> + {
> +   if (!(errno == ENOENT && (flags & AT_EMPTY_PATH)))
> + __leave;
> +   /* pathname is an empty string.  This is OK if dirfd refers
> +  to a symlink that was opened with O_PATH and O_NOFOLLOW.
> +  In this case, fchownat operates on the symlink. */
> +   cygheap_fdget cfd (dirfd);
> +   if (cfd < 0)
> + __leave;
> +   if (!(cfd->issymlink ()
> + && cfd->get_flags () & O_PATH
> + && cfd->get_flags () & O_NOFOLLOW))
> + __leave;

I think this is not quite right.  Per the Linux man page of fchownat,
if AT_EMPTY_PATH is given, any file type is ok as dirfd:

   AT_EMPTY_PATH (since Linux 2.6.39)
  If pathname is an empty string, operate on the file referred  to
  by  dirfd (which may have been obtained using the open(2) O_PATH
  flag).  In this case, dirfd can refer to any type of  file,  not
  just  a  directory...

Additionally AT_FDCWD is allowed, too:

... If dirfd is AT_FDCWD, the call operates on
  the current working directory.

> +   return lchown (cfd->get_name (), uid, gid);

Instead of calling lchown, this code could also just tweak the flags
and fall through to the below chown_worker call, I think, just as in
readlinkat below:

  strcpy (path, cfd->get_name ());
  flags = AT_SYMLINK_NOFOLLOW;

> + }
>return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
>? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
>  }
> @@ -4979,8 +4994,23 @@ readlinkat (int dirfd, const char *__restrict 
> pathname, char *__restrict buf,
>__try
>  {
>char *path = tp.c_get ();
> -  if (gen_full_path_at (path, dirfd, pathname))
> - __leave;
> +  int res = gen_full_path_at (path, dirfd, pathname);
> +  if (res)
> + {
> +   if (errno != ENOENT)
> + __leave;
> +   /* pathname is an empty string.  This is OK if dirfd refers
> +  to a symlink that was opened with O_PATH and O_NOFOLLOW.
> +  In this case, readlinkat operates on the symlink. */
> +   cygheap_fdget cfd (dirfd);
> +   if (cfd < 0)
> + __leave;
> +   if (!(cfd->issymlink ()
> + && cfd->get_flags () & O_PATH
> + && cfd->get_flags () & O_NOFOLLOW))
> + __leave;
> +   strcpy (path, cfd->get_name ());
> + }
>return readlink (path, buf, bufsize);
>  }
>__except (EFAULT) {}
> -- 
> 2.21.0

Thanks,
Corinna

-- 
Corinna Vinschen
Cygwin Maintainer


signature.asc
Description: PGP signature


[PATCH v4 1/4] Cygwin: allow opening a symlink with O_PATH | O_NOFOLLOW

2020-01-17 Thread Ken Brown
Up to now, opening a symlink with O_NOFOLLOW fails with ELOOP.
Following Linux, allow this to succeed if O_PATH is also specified.
---
 winsup/cygwin/syscalls.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 20126ce10..038a316db 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1470,7 +1470,7 @@ open (const char *unix_path, int flags, ...)
 
   if (!(fh = build_fh_name (unix_path, opt, stat_suffixes)))
__leave;/* errno already set */
-  if ((flags & O_NOFOLLOW) && fh->issymlink ())
+  if ((flags & O_NOFOLLOW) && fh->issymlink () && !(flags & O_PATH))
{
  set_errno (ELOOP);
  __leave;
-- 
2.21.0



[PATCH v4 0/4] Support opening a symlink with O_PATH | O_NOFOLLOW

2020-01-17 Thread Ken Brown
Currently, opening a symlink with O_NOFOLLOW fails with ELOOP.
Following Linux, the first patch in this series allows the call to
succeed if O_PATH is also specified.

According to the Linux man page for open(2), "the call returns a file
descriptor referring to the symbolic link.  This file descriptor can
be used as the dirfd argument in calls to fchownat(2), fstatat(2),
linkat(2), and readlinkat(2) with an empty pathname to have the calls
operate on the symbolic link."

The second patch achieves this for readlinkat.  The third patch does
this for fstatat and fchownat by adding support for the AT_EMPTY_PATH
flag.  Nothing needs to be done for linkat, which already supports the
AT_EMPTY_PATH flag.


Ken Brown (4):
  Cygwin: allow opening a symlink with O_PATH | O_NOFOLLOW
  Cygwin: readlinkat: allow pathname to be empty
  Cygwin: fstatat, fchownat: support the AT_EMPTY_PATH flag
  Cygwin: document recent changes

 winsup/cygwin/release/3.1.3 | 19 +--
 winsup/cygwin/syscalls.cc   | 68 -
 winsup/doc/new-features.xml | 19 +++
 3 files changed, 94 insertions(+), 12 deletions(-)

-- 
2.21.0



[PATCH v4 2/4] Cygwin: readlinkat: allow pathname to be empty

2020-01-17 Thread Ken Brown
Following Linux, allow the pathname argument to be an empty string,
provided the dirfd argument refers to a symlink opened with
O_PATH | O_NOFOLLOW.  The readlinkat call then operates on that
symlink.
---
 winsup/cygwin/syscalls.cc | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 038a316db..282d9e0ee 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -4979,8 +4979,23 @@ readlinkat (int dirfd, const char *__restrict pathname, 
char *__restrict buf,
   __try
 {
   char *path = tp.c_get ();
-  if (gen_full_path_at (path, dirfd, pathname))
-   __leave;
+  int res = gen_full_path_at (path, dirfd, pathname);
+  if (res)
+   {
+ if (errno != ENOENT)
+   __leave;
+ /* pathname is an empty string.  This is OK if dirfd refers
+to a symlink that was opened with O_PATH | O_NOFOLLOW.
+In this case, readlinkat operates on the symlink. */
+ cygheap_fdget cfd (dirfd);
+ if (cfd < 0)
+   __leave;
+ if (!(cfd->issymlink ()
+   && cfd->get_flags () & O_PATH
+   && cfd->get_flags () & O_NOFOLLOW))
+   __leave;
+ strcpy (path, cfd->get_name ());
+   }
   return readlink (path, buf, bufsize);
 }
   __except (EFAULT) {}
-- 
2.21.0



[PATCH v4 4/4] Cygwin: document recent changes

2020-01-17 Thread Ken Brown
---
 winsup/cygwin/release/3.1.3 | 19 ---
 winsup/doc/new-features.xml | 15 +++
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/winsup/cygwin/release/3.1.3 b/winsup/cygwin/release/3.1.3
index 489741136..425d8bb2d 100644
--- a/winsup/cygwin/release/3.1.3
+++ b/winsup/cygwin/release/3.1.3
@@ -1,5 +1,18 @@
-Bug Fixes
--
+What changed:
+-
+
+- Allow symlinks to be opened with O_PATH | O_NOFOLLOW.
+
+- Allow the pathname argument to readlinkat(2) to be an empty string,
+  provided the dirfd argument refers to a symlink opened with
+  O_PATH | O_NOFOLLOW.  The readlinkat call then operates on that
+  symlink.
+
+- Support the Linux-specific AT_EMPTY_PATH flag for fchownat(2) and
+  fstatat(2).
+
+Bug Fixes:
+--
 
 - Define CPU_SETSIZE, as on Linux.
   Addresses: https://cygwin.com/ml/cygwin/2019-12/msg00248.html
@@ -7,6 +20,6 @@ Bug Fixes
 - Fix the problem which overrides the code page setting.
   Addresses: https://www.cygwin.com/ml/cygwin/2019-12/msg00292.html
 
-- Fix a regression that prevents the root of a drive from being the
+- Fix a regression that prevented the root of a drive from being the
   Cygwin installation root.
   Addresses: https://cygwin.com/ml/cygwin/2020-01/msg00111.html
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index 65bdc17ab..967c64ac5 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -54,6 +54,21 @@ Allow times(2) to have a NULL argument, as on Linux.
 Improve /proc/cpuinfo output and align more closely with Linux.
 
 
+
+Allow symlinks to be opened with O_PATH | O_NOFOLLOW.
+
+
+
+Allow the pathname argument to readlinkat(2) to be an empty string,
+provided the dirfd argument refers to a symlink opened with O_PATH |
+O_NOFOLLOW.  The readlinkat call then operates on that symlink.
+
+
+
+Support the Linux-specific AT_EMPTY_PATH flag for fchownat(2) and
+fstatat(2).
+
+
 
 
 
-- 
2.21.0



[PATCH v4 3/4] Cygwin: fstatat, fchownat: support the AT_EMPTY_PATH flag

2020-01-17 Thread Ken Brown
Following Linux, allow the pathname argument to be an empty string if
the AT_EMPTY_PATH flag is specified.  In this case the dirfd argument
can refer to any type of file, not just a directory, and the call
operates on that file.  In particular, dirfd can refer to a symlink
that was opened with O_PATH and O_NOFOLLOW.
---
 winsup/cygwin/syscalls.cc | 47 ++-
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 282d9e0ee..4956b6ff5 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -4785,14 +4785,36 @@ fchownat (int dirfd, const char *pathname, uid_t uid, 
gid_t gid, int flags)
   tmp_pathbuf tp;
   __try
 {
-  if (flags & ~AT_SYMLINK_NOFOLLOW)
+  if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
{
  set_errno (EINVAL);
  __leave;
}
   char *path = tp.c_get ();
-  if (gen_full_path_at (path, dirfd, pathname))
-   __leave;
+  int res = gen_full_path_at (path, dirfd, pathname);
+  if (res)
+   {
+ if (!(errno == ENOENT && (flags & AT_EMPTY_PATH)))
+   __leave;
+ /* pathname is an empty string.  Operate on dirfd. */
+ if (dirfd == AT_FDCWD)
+   {
+ cwdstuff::cwd_lock.acquire ();
+ strcpy (path, cygheap->cwd.get_posix ());
+ cwdstuff::cwd_lock.release ();
+   }
+ else
+   {
+ cygheap_fdget cfd (dirfd);
+ if (cfd < 0)
+   __leave;
+ strcpy (path, cfd->get_name ());
+ /* If dirfd refers to a symlink (which was necessarily
+opened with O_PATH | O_NOFOLLOW), we must operate
+directly on that symlink.. */
+ flags = AT_SYMLINK_NOFOLLOW;
+   }
+   }
   return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
 ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
 }
@@ -4808,14 +4830,27 @@ fstatat (int dirfd, const char *__restrict pathname, 
struct stat *__restrict st,
   tmp_pathbuf tp;
   __try
 {
-  if (flags & ~AT_SYMLINK_NOFOLLOW)
+  if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
{
  set_errno (EINVAL);
  __leave;
}
   char *path = tp.c_get ();
-  if (gen_full_path_at (path, dirfd, pathname))
-   __leave;
+  int res = gen_full_path_at (path, dirfd, pathname);
+  if (res)
+   {
+ if (!(errno == ENOENT && (flags & AT_EMPTY_PATH)))
+   __leave;
+ /* pathname is an empty string.  Operate on dirfd. */
+ if (dirfd == AT_FDCWD)
+   {
+ cwdstuff::cwd_lock.acquire ();
+ strcpy (path, cygheap->cwd.get_posix ());
+ cwdstuff::cwd_lock.release ();
+   }
+ else
+   return fstat (dirfd, st);
+   }
   path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW)
   ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
  | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
-- 
2.21.0