cifs: Add support for creating native Windows sockets

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 <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Pali Rohár 2024-09-16 20:21:52 +02:00 committed by Steve French
parent 78f69467cb
commit 45a99d5d11
5 changed files with 45 additions and 0 deletions

View File

@ -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)));

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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);