From: Ally Sommers dropbear.sh@gmail.com
Deleting the socket file is a common pattern with AF_UNIX sockets, and is analogous to unbinding. --- server/fd.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/server/fd.c b/server/fd.c index bb0e90d99d0..e844441f55b 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1951,6 +1951,19 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode ); }
+ /* POSIX requires that open(2) throws EOPNOTSUPP when `path` is a Unix + * socket. *BSD throws EOPNOTSUPP in this case and the additional case of + * O_SHLOCK or O_EXLOCK being passed when `path` resides on a filesystem + * without lock support. + * + * Contrary to POSIX, Linux returns ENXIO in this case, so we also check + * that error code here. */ + if (errno == EOPNOTSUPP || errno == ENXIO) + { + if (!stat(name, &st) && S_ISSOCK(st.st_mode) && (options & FILE_DELETE_ON_CLOSE)) + goto skip_open_fail; + } + if (fd->unix_fd == -1) { /* check for trailing slash on file path */ @@ -1962,13 +1975,24 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam } }
+skip_open_fail: fd->nt_name = dup_nt_name( root, nt_name, &fd->nt_namelen ); fd->unix_name = NULL; - fstat( fd->unix_fd, &st ); + if ((path = dup_fd_name( root, name ))) + { + fd->unix_name = realpath( path, NULL ); + free( path ); + } + + closed_fd->unix_fd = fd->unix_fd; + closed_fd->disp_flags = 0; + closed_fd->unix_name = fd->unix_name; + if (fd->unix_fd != -1) + fstat( fd->unix_fd, &st ); *mode = st.st_mode;
- /* only bother with an inode for normal files and directories */ - if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) + /* only bother with an inode for normal files, directories, and socket files */ + if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode)) { unsigned int err; struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );