From 9dae73edb8871f017251ddcba959e09457923a8e Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 6 Jan 2019 22:39:45 +0100 Subject: [PATCH] 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 --- 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 e32c219d3..d02b9a913 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 06d37c0e6..0c0452ab4 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 9d9972740..e659d7ae0 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 af10321c5..2b885045d 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 00b3ed623..90dfd2b7c 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 8eb3c43ea..c4881c7f8 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 &);