Commit 45a99d5d authored by Pali Rohár's avatar Pali Rohár Committed by Steve French
Browse files

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: default avatarPali Rohár <pali@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 78f69467
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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)));

+2 −0
Original line number Diff line number Diff line
@@ -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;

+5 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+32 −0
Original line number Diff line number Diff line
@@ -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);