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 | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/server/fd.c b/server/fd.c index fc7f7be92b9..dd2238b8eae 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1939,6 +1939,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 */ @@ -1950,6 +1963,7 @@ 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; if ((path = dup_fd_name( root, name ))) @@ -1961,11 +1975,12 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam closed_fd->unix_fd = fd->unix_fd; closed_fd->disp_flags = 0; closed_fd->unix_name = fd->unix_name; - fstat( fd->unix_fd, &st ); + 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 );