Re: [PATCH 6/7] cifs: Fix creating of SFU fifo and socket special files

From: Pali Rohár
Date: Fri Sep 13 2024 - 16:07:36 EST


On Thursday 12 September 2024 14:05:47 Pali Rohár wrote:
> SFU-style fifo is empty file with system attribute set. This format is used
> by old Microsoft POSIX subsystem and later also by OpenNT/Interix subsystem
> (which replaced Microsoft POSIX subsystem and is part of Microsoft SFU).
>
> SFU-style socket is file which has system attribute set and file content is
> one zero byte. This format was introduced in Interix 3.0 subsystem, as part
> of the Microsoft SFU 3.0 and is used also by all later versions. Previous
> versions had no UNIX domain socket support.
>
> Currently when sfu mount option is specified then CIFS creates fifo and
> socket special files with some strange LnxSOCK or LnxFIFO content which is
> not compatible with Microsoft SFU and neither recognized by other SMB
> implementations which have some SFU support, including older Linux cifs
> implementations.
>
> So when sfu mount option is specified, create all fifo and socket special
> files compatible with SFU format to achieve SFU interop, as it is expected
> by sfu mount option.
>
> Signed-off-by: Pali Rohár <pali@xxxxxxxxxx>

Fixes: 72bc63f5e23a ("smb3: fix creating FIFOs when mounting with "sfu" mount option")
Fixes: 518549c120e6 ("cifs: fix creating sockets when using sfu mount options")

I located commits which introduced those strange LnxSOCK or LnxFIFO
types which are not compatible with SFU. I would suggest to add those
two Fixes: tags into commit message for reference.

> ---
> fs/smb/client/cifssmb.c | 8 ++++----
> fs/smb/client/smb1ops.c | 2 +-
> fs/smb/client/smb2ops.c | 29 +++++++++++++++++++----------
> 3 files changed, 24 insertions(+), 15 deletions(-)
>
> diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
> index cfae2e918209..0ffc45aa5e2c 100644
> --- a/fs/smb/client/cifssmb.c
> +++ b/fs/smb/client/cifssmb.c
> @@ -1076,8 +1076,8 @@ SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
> pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
> pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
> pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
> - /* set file as system file if special file such
> - as fifo and server expecting SFU style and
> + /* set file as system file if special file such as fifo,
> + * socket, char or block and server expecting SFU style and
> no Unix extensions */
>
> if (create_options & CREATE_OPTION_SPECIAL)
> @@ -1193,8 +1193,8 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
> req->AllocationSize = 0;
>
> /*
> - * Set file as system file if special file such as fifo and server
> - * expecting SFU style and no Unix extensions.
> + * Set file as system file if special file such as fifo, socket, char
> + * or block and server expecting SFU style and no Unix extensions.
> */
> if (create_options & CREATE_OPTION_SPECIAL)
> req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
> diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
> index e1f2feb56f45..e03c91a49650 100644
> --- a/fs/smb/client/smb1ops.c
> +++ b/fs/smb/client/smb1ops.c
> @@ -1078,7 +1078,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
> /*
> * Check if mounted with mount parm 'sfu' mount parm.
> * SFU emulation should work with all servers, but only
> - * supports block and char device (no socket & fifo),
> + * supports block and char device, socket & fifo,
> * and was used by default in earlier versions of Windows
> */
> if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index 9c2d065d3cc4..9e90672caf60 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -5066,26 +5066,32 @@ static int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
> struct cifs_fid fid;
> unsigned int bytes_written;
> struct win_dev pdev = {};
> + size_t pdev_len = 0;
> struct kvec iov[2];
> __u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
> int rc;
>
> switch (mode & S_IFMT) {
> case S_IFCHR:
> + pdev_len = sizeof(pdev);
> memcpy(pdev.type, "IntxCHR\0", 8);
> pdev.major = cpu_to_le64(MAJOR(dev));
> pdev.minor = cpu_to_le64(MINOR(dev));
> break;
> case S_IFBLK:
> + pdev_len = sizeof(pdev);
> memcpy(pdev.type, "IntxBLK\0", 8);
> pdev.major = cpu_to_le64(MAJOR(dev));
> pdev.minor = cpu_to_le64(MINOR(dev));
> break;
> case S_IFSOCK:
> - strscpy(pdev.type, "LnxSOCK");
> + /* SFU socket is system file with one zero byte */
> + pdev_len = 1;
> + pdev.type[0] = '\0';
> break;
> case S_IFIFO:
> - strscpy(pdev.type, "LnxFIFO");
> + /* SFU fifo is system file which is empty */
> + pdev_len = 0;
> break;
> default:
> return -EPERM;
> @@ -5100,14 +5106,17 @@ static int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
> if (rc)
> return rc;
>
> - io_parms.pid = current->tgid;
> - io_parms.tcon = tcon;
> - io_parms.length = sizeof(pdev);
> - iov[1].iov_base = &pdev;
> - iov[1].iov_len = sizeof(pdev);
> + if (pdev_len > 0) {
> + io_parms.pid = current->tgid;
> + io_parms.tcon = tcon;
> + io_parms.length = pdev_len;
> + iov[1].iov_base = &pdev;
> + iov[1].iov_len = pdev_len;
> +
> + rc = server->ops->sync_write(xid, &fid, &io_parms,
> + &bytes_written, iov, 1);
> + }
>
> - rc = server->ops->sync_write(xid, &fid, &io_parms,
> - &bytes_written, iov, 1);
> server->ops->close(xid, tcon, &fid);
> return rc;
> }
> @@ -5149,7 +5158,7 @@ static int smb2_make_node(unsigned int xid, struct inode *inode,
> /*
> * Check if mounted with mount parm 'sfu' mount parm.
> * SFU emulation should work with all servers, but only
> - * supports block and char device (no socket & fifo),
> + * supports block and char device, socket & fifo,
> * and was used by default in earlier versions of Windows
> */
> if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
> --
> 2.20.1
>