From 45a99d5d117300eb84eceaa312bb3c3262f8c85b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Mon, 16 Sep 2024 20:21:52 +0200 Subject: [PATCH] cifs: Add support for creating native Windows sockets MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Native Windows sockets created by WinSock on Windows 10 April 2018 Update (version 1803) or Windows Server 2019 (version 1809) or later versions is reparse point with IO_REPARSE_TAG_AF_UNIX tag, with empty reparse point data buffer and without any EAs. Create AF_UNIX sockets in this native format if -o nonativesocket was not specified. This change makes AF_UNIX sockets created by Linux CIFS client compatible with AF_UNIX sockets created by Windows applications on NTFS volumes. Signed-off-by: Pali Rohár Signed-off-by: Steve French --- fs/smb/client/cifsfs.c | 4 ++++ fs/smb/client/connect.c | 2 ++ fs/smb/client/fs_context.c | 5 +++++ fs/smb/client/fs_context.h | 2 ++ fs/smb/client/reparse.c | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 45 insertions(+) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index f2c852c9d6a11..6a3bd652d251d 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -715,6 +715,10 @@ cifs_show_options(struct seq_file *s, struct dentry *root) cifs_sb->ctx->backupgid)); seq_show_option(s, "reparse", cifs_reparse_type_str(cifs_sb->ctx->reparse_type)); + if (cifs_sb->ctx->nonativesocket) + seq_puts(s, ",nonativesocket"); + else + seq_puts(s, ",nativesocket"); seq_show_option(s, "symlink", cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb))); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index ebd20f48f6aac..f917de020dd5d 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -2849,6 +2849,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) return 0; if (old->ctx->reparse_type != new->ctx->reparse_type) return 0; + if (old->ctx->nonativesocket != new->ctx->nonativesocket) + return 0; if (old->ctx->symlink_type != new->ctx->symlink_type) return 0; diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 821eb149e4b88..e9b286d9a7ba3 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -133,6 +133,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("rootfs", Opt_rootfs), fsparam_flag("compress", Opt_compress), fsparam_flag("witness", Opt_witness), + fsparam_flag_no("nativesocket", Opt_nativesocket), /* Mount options which take uid or gid */ fsparam_uid("backupuid", Opt_backupuid), @@ -1784,6 +1785,9 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (parse_reparse_flavor(fc, param->string, ctx)) goto cifs_parse_mount_err; break; + case Opt_nativesocket: + ctx->nonativesocket = result.negated; + break; case Opt_symlink: if (parse_symlink_flavor(fc, param->string, ctx)) goto cifs_parse_mount_err; @@ -1918,6 +1922,7 @@ int smb3_init_fs_context(struct fs_context *fc) ctx->retrans = 1; ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; + ctx->nonativesocket = 0; /* * short int override_uid = -1; diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index 2ccdda350267f..881bfc08667e7 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -179,6 +179,7 @@ enum cifs_param { Opt_cache, Opt_reparse, Opt_upcalltarget, + Opt_nativesocket, Opt_symlink, Opt_symlinkroot, @@ -310,6 +311,7 @@ struct smb3_fs_context { bool dfs_automount:1; /* set for dfs automount only */ enum cifs_reparse_type reparse_type; enum cifs_symlink_type symlink_type; + bool nonativesocket:1; bool dfs_conn:1; /* set for dfs mounts */ char *dns_dom; char *symlinkroot; /* top level directory for native SMB symlinks in absolute format */ diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index 24a5f563df26a..34bf4e3f28d98 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -378,6 +378,35 @@ static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, return 0; } +static int create_native_socket(const unsigned int xid, struct inode *inode, + struct dentry *dentry, struct cifs_tcon *tcon, + const char *full_path) +{ + struct reparse_data_buffer buf = { + .ReparseTag = cpu_to_le32(IO_REPARSE_TAG_AF_UNIX), + .ReparseDataLength = cpu_to_le16(0), + }; + struct cifs_open_info_data data = { + .reparse_point = true, + .reparse = { .tag = IO_REPARSE_TAG_AF_UNIX, .buf = &buf, }, + }; + struct kvec iov = { + .iov_base = &buf, + .iov_len = sizeof(buf), + }; + struct inode *new; + int rc = 0; + + new = smb2_get_reparse_inode(&data, inode->i_sb, xid, + tcon, full_path, false, &iov, NULL); + if (!IS_ERR(new)) + d_instantiate(dentry, new); + else + rc = PTR_ERR(new); + cifs_free_open_info(&data); + return rc; +} + static int nfs_set_reparse_buf(struct reparse_nfs_data_buffer *buf, mode_t mode, dev_t dev, struct kvec *iov) @@ -601,6 +630,9 @@ int smb2_mknod_reparse(unsigned int xid, struct inode *inode, { struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; + if (S_ISSOCK(mode) && !ctx->nonativesocket && ctx->reparse_type != CIFS_REPARSE_TYPE_NONE) + return create_native_socket(xid, inode, dentry, tcon, full_path); + switch (ctx->reparse_type) { case CIFS_REPARSE_TYPE_NFS: return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL); -- 2.49.0