[newlib-cygwin] Cygwin: fix regression in O_TMPFILE | O_EXCL case

Corinna Vinschen corinna@sourceware.org
Sun Jan 6 21:40:00 GMT 2019


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=9dae73edb8871f017251ddcba959e09457923a8e

commit 9dae73edb8871f017251ddcba959e09457923a8e
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Sun Jan 6 22:39:45 2019 +0100

    Cygwin: fix regression in O_TMPFILE | O_EXCL case
    
    The new proc fd code accidentally allowed to linkat an O_TMPFILE
    even if the file has been opened with O_EXCL.  This patch fixes it.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/fhandler.h              |  2 +-
 winsup/cygwin/fhandler_process_fd.cc  | 18 ++++++++++++------
 winsup/cygwin/include/cygwin/signal.h |  5 ++++-
 winsup/cygwin/path.h                  |  5 +++++
 winsup/cygwin/pinfo.cc                | 11 ++++++++---
 winsup/cygwin/pinfo.h                 |  2 +-
 6 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index e32c219..d02b9a9 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -2578,7 +2578,7 @@ class fhandler_process: public fhandler_proc
 
 class fhandler_process_fd : public fhandler_process
 {
-  fhandler_base *fetch_fh (HANDLE &);
+  fhandler_base *fetch_fh (HANDLE &, uint32_t);
 
  public:
   fhandler_process_fd () : fhandler_process () {}
diff --git a/winsup/cygwin/fhandler_process_fd.cc b/winsup/cygwin/fhandler_process_fd.cc
index 06d37c0..0c0452a 100644
--- a/winsup/cygwin/fhandler_process_fd.cc
+++ b/winsup/cygwin/fhandler_process_fd.cc
@@ -29,7 +29,7 @@ details. */
 
 
 fhandler_base *
-fhandler_process_fd::fetch_fh (HANDLE &out_hdl)
+fhandler_process_fd::fetch_fh (HANDLE &out_hdl, uint32_t flags)
 {
   const char *path;
   char *e;
@@ -49,6 +49,12 @@ fhandler_process_fd::fetch_fh (HANDLE &out_hdl)
       cygheap_fdget cfd (fd, true);
       if (cfd < 0)
 	return NULL;
+      if ((flags & FFH_LINKAT)
+	 && (cfd->get_flags () & (O_TMPFILE | O_EXCL)) == (O_TMPFILE | O_EXCL))
+	{
+	  set_errno (ENOENT);
+	  return NULL;
+	}
       proc = GetCurrentProcess ();
       pc << cfd->pc;
       hdl = cfd->get_handle ();
@@ -68,10 +74,10 @@ fhandler_process_fd::fetch_fh (HANDLE &out_hdl)
 	  return NULL;
 	}
       size_t size;
-      void *buf = p->file_pathconv (fd, size);
+      void *buf = p->file_pathconv (fd, FFH_LINKAT, size);
       if (size == 0)
 	{
-	  set_errno (EPERM);
+	  set_errno (ENOENT);
 	  CloseHandle (proc);
 	  return NULL;
 	}
@@ -103,7 +109,7 @@ fhandler_process_fd::fd_reopen (int flags)
   fhandler_base *fh;
   HANDLE hdl;
 
-  fh = fetch_fh (hdl);
+  fh = fetch_fh (hdl, 0);
   if (!fh)
     return NULL;
   fh->set_io_handle (hdl);
@@ -126,7 +132,7 @@ fhandler_process_fd::fstat (struct stat *statbuf)
   fhandler_base *fh;
   HANDLE hdl;
 
-  fh = fetch_fh (hdl);
+  fh = fetch_fh (hdl, 0);
   if (!fh)
     return -1;
   fh->set_io_handle (hdl);
@@ -142,7 +148,7 @@ fhandler_process_fd::link (const char *newpath)
   fhandler_base *fh;
   HANDLE hdl;
 
-  fh = fetch_fh (hdl);
+  fh = fetch_fh (hdl, FFH_LINKAT);
   if (!fh)
     return -1;
   fh->set_io_handle (hdl);
diff --git a/winsup/cygwin/include/cygwin/signal.h b/winsup/cygwin/include/cygwin/signal.h
index 9d99727..e659d7a 100644
--- a/winsup/cygwin/include/cygwin/signal.h
+++ b/winsup/cygwin/include/cygwin/signal.h
@@ -187,7 +187,10 @@ struct _sigcommune
   void *_si_process_handle;
   __extension__ union
   {
-    int _si_fd;
+    struct {
+      int      _si_fd;
+      uint32_t _si_flags;
+    };
     int64_t _si_pipe_unique_id;
     char *_si_str;
   };
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index af10321..2b88504 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -73,6 +73,11 @@ enum path_types
   PATH_DONT_USE		= _BIT (31)	/* conversion to signed happens. */
 };
 
+enum fetch_fh_flags
+{
+  FFH_LINKAT	= (1 <<  0),
+};
+
 NTSTATUS file_get_fai (HANDLE, PFILE_ALL_INFORMATION);
 int check_reparse_point_target (HANDLE, bool, PREPARSE_DATA_BUFFER,
 				PUNICODE_STRING);
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 00b3ed6..90dfd2b 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -660,9 +660,13 @@ commune_process (void *arg)
       {
 	sigproc_printf ("processing PICOM_FILE_PATHCONV");
 	int fd = si._si_commune._si_fd;
+	uint32_t flags = si._si_commune._si_flags;
 	unsigned int n = 0;
 	cygheap_fdget cfd (fd);
-	if (cfd >= 0)
+	if (cfd >= 0
+	    && (!(flags & FFH_LINKAT)
+		|| (cfd->get_flags () & (O_TMPFILE | O_EXCL))
+		    != (O_TMPFILE | O_EXCL)))
 	  {
 	    fhandler_base *fh = cfd;
 	    void *ser_buf = fh->pc.serialize (fh->get_handle (), n);
@@ -763,6 +767,7 @@ _pinfo::commune_request (__uint32_t code, ...)
     case PICOM_FD:
     case PICOM_FILE_PATHCONV:
       si._si_commune._si_fd = va_arg (args, int);
+      si._si_commune._si_flags = va_arg (args, uint32_t);
       break;
 
     break;
@@ -852,13 +857,13 @@ _pinfo::pipe_fhandler (int64_t unique_id, size_t &n)
 }
 
 void *
-_pinfo::file_pathconv (int fd, size_t &n)
+_pinfo::file_pathconv (int fd, uint32_t flags, size_t &n)
 {
   if (!pid)
     return NULL;
   if (pid == myself->pid)
     return NULL;
-  commune_result cr = commune_request (PICOM_FILE_PATHCONV, fd);
+  commune_result cr = commune_request (PICOM_FILE_PATHCONV, fd, flags);
   n = cr.n;
   return (void *) cr.s;
 }
diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h
index 8eb3c43..c4881c7 100644
--- a/winsup/cygwin/pinfo.h
+++ b/winsup/cygwin/pinfo.h
@@ -103,7 +103,7 @@ public:
   commune_result commune_request (__uint32_t, ...);
   bool alive ();
   fhandler_pipe *pipe_fhandler (int64_t, size_t &);
-  void *file_pathconv (int, size_t &);
+  void *file_pathconv (int, uint32_t, size_t &);
   char *fd (int fd, size_t &);
   char *fds (size_t &);
   char *root (size_t &);



More information about the Cygwin-cvs mailing list