From 7aca27b4fe553657d057dce90de13be97068fd4a Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 6 Jan 2019 20:18:14 +0100 Subject: [PATCH] Cygwin: introduce fhandler_process_fd and add stat(2) handling move special fd symlink code into own fhandler_process_fd class to simplify further additions to /proc/PID/fd/DESCRIPTOR symlink handling. Add a method to handle stat(2) on such a proc fd symlink by handle. This allows correct reply from stat(2) if the target file has been deleted. This eventually fixes `awk -f /dev/fd/3 3< --- winsup/cygwin/Makefile.in | 1 + winsup/cygwin/dtable.cc | 4 +- winsup/cygwin/fhandler.h | 32 +++++- winsup/cygwin/fhandler_process.cc | 160 --------------------------- winsup/cygwin/fhandler_process_fd.cc | 153 +++++++++++++++++++++++++ winsup/cygwin/syscalls.cc | 3 +- 6 files changed, 189 insertions(+), 164 deletions(-) create mode 100644 winsup/cygwin/fhandler_process_fd.cc diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index fb0195fc2..75c73bf92 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -288,6 +288,7 @@ DLL_OFILES:= \ fhandler_nodevice.o \ fhandler_proc.o \ fhandler_process.o \ + fhandler_process_fd.o \ fhandler_procnet.o \ fhandler_procsys.o \ fhandler_procsysvipc.o \ diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 0ebeef058..780deb524 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -552,9 +552,11 @@ fh_alloc (path_conv& pc) fh = cnew (fhandler_registry); break; case FH_PROCESS: - case FH_PROCESSFD: fh = cnew (fhandler_process); break; + case FH_PROCESSFD: + fh = cnew (fhandler_process_fd); + break; case FH_PROCNET: fh = cnew (fhandler_procnet); break; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 1c751c110..e32c219d3 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -2545,6 +2545,7 @@ class fhandler_registry: public fhandler_proc class pinfo; class fhandler_process: public fhandler_proc { + protected: pid_t pid; virtual_ftype_t fd_type; public: @@ -2554,8 +2555,6 @@ class fhandler_process: public fhandler_proc int closedir (DIR *); int __reg3 readdir (DIR *, dirent *); int open (int flags, mode_t mode = 0); - virtual fhandler_base *fd_reopen (int); - int __reg2 link (const char *); int __reg2 fstat (struct stat *buf); bool fill_filebuf (); @@ -2577,6 +2576,34 @@ class fhandler_process: public fhandler_proc } }; +class fhandler_process_fd : public fhandler_process +{ + fhandler_base *fetch_fh (HANDLE &); + + public: + fhandler_process_fd () : fhandler_process () {} + fhandler_process_fd (void *) {} + + virtual fhandler_base *fd_reopen (int); + int __reg2 fstat (struct stat *buf); + virtual int __reg2 link (const char *); + + void copyto (fhandler_base *x) + { + x->pc.free_strings (); + *reinterpret_cast (x) = *this; + x->reset (this); + } + + fhandler_process_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process_fd)); + fhandler_process_fd *fh = new (ptr) fhandler_process_fd (ptr); + copyto (fh); + return fh; + } +}; + class fhandler_procnet: public fhandler_proc { pid_t pid; @@ -2638,6 +2665,7 @@ typedef union char __pipe[sizeof (fhandler_pipe)]; char __proc[sizeof (fhandler_proc)]; char __process[sizeof (fhandler_process)]; + char __process_fd[sizeof (fhandler_process_fd)]; char __procnet[sizeof (fhandler_procnet)]; char __procsys[sizeof (fhandler_procsys)]; char __procsysvipc[sizeof (fhandler_procsysvipc)]; diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index a52314810..24ef7d00c 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -321,166 +321,6 @@ out: return res; } -fhandler_base * -fhandler_process::fd_reopen (int flags) -{ - const char *path; - char *e; - int fd; - HANDLE proc = NULL; - HANDLE hdl = NULL; - fhandler_base *fh = NULL; - - path = get_name () + proc_len + 1; - pid = strtoul (path, &e, 10); - path = e + 4; - fd = strtoul (path, &e, 10); - if (e == path || *e != '\0') - { - set_errno (ENOENT); - return NULL; - } - - if (pid == myself->pid) - { - cygheap_fdget cfd (fd); - if (cfd < 0) - return NULL; - fh = build_fh_pc (cfd->pc); - if (!fh) - goto err_out; - fh->set_io_handle (cfd->get_handle ()); - } - else - { - size_t size; - path_conv pc; - - pinfo p (pid); - if (!p) - { - set_errno (ENOENT); - return NULL; - } - if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) - { - __seterrno (); - return NULL; - } - void *buf = p->file_pathconv (fd, size); - if (size == 0) - { - set_errno (EPERM); - goto err_out; - } - hdl = pc.deserialize (buf); - if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - __seterrno (); - hdl = NULL; - goto err_out; - } - fh = build_fh_pc (pc); - if (!fh) - goto err_out; - fh->set_io_handle (hdl); - } - if (!fh->open_with_arch (flags, 0)) - { - delete fh; - fh = NULL; - } -err_out: - if (hdl) - CloseHandle (hdl); - if (proc) - CloseHandle (proc); - return fh; -} - -int -fhandler_process::link (const char *newpath) -{ - const char *path; - int fd; - char *e; - - path = get_name () + proc_len + 1; - pid = atoi (path); - while (*path != 0 && !isdirsep (*path)) - path++; - if (*path == 0) - goto err_out; - - virt_tab_t *entry; - entry = virt_tab_search (path + 1, true, process_tab, PROCESS_LINK_COUNT); - if (!entry || entry->fhandler != FH_PROCESSFD) - goto err_out; - if (path[3] != '/' || path[4] == '\0') - goto err_out; - - fd = strtoul (path + 4, &e, 10); - if (fd < 0 || e == path + 4 || (*e != '/' && *e != '\0')) - goto err_out; - if (pid == myself->pid) - { - cygheap_fdget cfd (fd); - if (cfd < 0) - goto err_out; - return cfd->link (newpath); - } - else - { - HANDLE proc; - size_t size; - void *buf; - path_conv pc; - HANDLE hdl; - fhandler_base *fh = NULL; - int ret = -1; - - pinfo p (pid); - if (!p) - { - set_errno (ENOENT); - return -1; - } - if (!(proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId))) - goto err_out; - buf = p->file_pathconv (fd, size); - if (size == 0) - { - set_errno (EPERM); - goto err_out_close_proc; - } - hdl = pc.deserialize (buf); - if (!DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - __seterrno (); - goto err_out_close_proc; - } - fh = build_fh_pc (pc); - if (!fh) - goto err_out_close_dup; - - fh->set_io_handle (hdl); - ret = fh->link (newpath); - delete fh; - -err_out_close_dup: - CloseHandle (hdl); -err_out_close_proc: - CloseHandle (proc); - return ret; - } - -err_out: - set_errno (EPERM); - return -1; -} - struct process_fd_t { const char *path; _pinfo *p; diff --git a/winsup/cygwin/fhandler_process_fd.cc b/winsup/cygwin/fhandler_process_fd.cc new file mode 100644 index 000000000..06d37c0e6 --- /dev/null +++ b/winsup/cygwin/fhandler_process_fd.cc @@ -0,0 +1,153 @@ +/* fhandler_process_fd.cc: fhandler for /proc//fd/ operations + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "fhandler_virtual.h" +#include "pinfo.h" +#include "shared_info.h" +#include "dtable.h" +#include "cygheap.h" +#include "ntdll.h" +#include "cygtls.h" +#include "mount.h" +#include "tls_pbuf.h" +#include +#include +#include + + +fhandler_base * +fhandler_process_fd::fetch_fh (HANDLE &out_hdl) +{ + const char *path; + char *e; + int fd; + HANDLE proc; + HANDLE hdl = NULL; + path_conv pc; + + path = get_name () + proc_len + 1; + pid = strtoul (path, &e, 10); + path = e + 4; + fd = strtoul (path, &e, 10); + + out_hdl = NULL; + if (pid == myself->pid) + { + cygheap_fdget cfd (fd, true); + if (cfd < 0) + return NULL; + proc = GetCurrentProcess (); + pc << cfd->pc; + hdl = cfd->get_handle (); + } + else + { + pinfo p (pid); + if (!p) + { + set_errno (ENOENT); + return NULL; + } + proc = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId); + if (!proc) + { + __seterrno (); + return NULL; + } + size_t size; + void *buf = p->file_pathconv (fd, size); + if (size == 0) + { + set_errno (EPERM); + CloseHandle (proc); + return NULL; + } + hdl = pc.deserialize (buf); + } + BOOL ret = DuplicateHandle (proc, hdl, GetCurrentProcess (), &hdl, + 0, FALSE, DUPLICATE_SAME_ACCESS); + if (proc != GetCurrentProcess ()) + CloseHandle (proc); + if (!ret) + { + __seterrno (); + CloseHandle (hdl); + return NULL; + } + fhandler_base *fh = build_fh_pc (pc); + if (!fh) + { + CloseHandle (hdl); + return NULL; + } + out_hdl = hdl; + return fh; +} + +fhandler_base * +fhandler_process_fd::fd_reopen (int flags) +{ + fhandler_base *fh; + HANDLE hdl; + + fh = fetch_fh (hdl); + if (!fh) + return NULL; + fh->set_io_handle (hdl); + int ret = fh->open_with_arch (flags, 0); + CloseHandle (hdl); + if (!ret) + { + delete fh; + fh = NULL; + } + return fh; +} + +int __reg2 +fhandler_process_fd::fstat (struct stat *statbuf) +{ + if (!pc.follow_fd_symlink ()) + return fhandler_process::fstat (statbuf); + + fhandler_base *fh; + HANDLE hdl; + + fh = fetch_fh (hdl); + if (!fh) + return -1; + fh->set_io_handle (hdl); + int ret = fh->fstat (statbuf); + CloseHandle (hdl); + delete fh; + return ret; +} + +int +fhandler_process_fd::link (const char *newpath) +{ + fhandler_base *fh; + HANDLE hdl; + + fh = fetch_fh (hdl); + if (!fh) + return -1; + fh->set_io_handle (hdl); + int ret = fh->link (newpath); + CloseHandle (hdl); + delete fh; + return ret; +} diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 60f66a63b..5bb33bf0a 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -2005,7 +2005,8 @@ extern "C" int stat64 (const char *__restrict name, struct stat *__restrict buf) { syscall_printf ("entering"); - path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE, + path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE + | PC_SYM_NOFOLLOW_PROCFD, stat_suffixes); return stat_worker (pc, buf); }