Commit 4b96024e authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: handle lack of FSCTL_GET_REPARSE_POINT support



As per MS-FSA 2.1.5.10.14, support for FSCTL_GET_REPARSE_POINT is
optional and if the server doesn't support it,
STATUS_INVALID_DEVICE_REQUEST must be returned for the operation.

If we find files with reparse points and we can't read them due to
lack of client or server support, just ignore it and then treat them
as regular files or junctions.

Fixes: 5f71ebc4 ("smb: client: parse reparse point flag in create response")
Reported-by: default avatarSebastian Steinbeisser <Sebastian.Steinbeisser@lrz.de>
Tested-by: default avatarSebastian Steinbeisser <Sebastian.Steinbeisser@lrz.de>
Acked-by: default avatarTom Talpey <tom@talpey.com>
Signed-off-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 8400291e
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -1042,13 +1042,26 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
	}

	rc = -EOPNOTSUPP;
	switch ((data->reparse.tag = tag)) {
	case 0: /* SMB1 symlink */
	data->reparse.tag = tag;
	if (!data->reparse.tag) {
		if (server->ops->query_symlink) {
			rc = server->ops->query_symlink(xid, tcon,
							cifs_sb, full_path,
							&data->symlink_target);
		}
		if (rc == -EOPNOTSUPP)
			data->reparse.tag = IO_REPARSE_TAG_INTERNAL;
	}

	switch (data->reparse.tag) {
	case 0: /* SMB1 symlink */
		break;
	case IO_REPARSE_TAG_INTERNAL:
		rc = 0;
		if (le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY) {
			cifs_create_junction_fattr(fattr, sb);
			goto out;
		}
		break;
	case IO_REPARSE_TAG_MOUNT_POINT:
		cifs_create_junction_fattr(fattr, sb);
+4 −0
Original line number Diff line number Diff line
@@ -505,6 +505,10 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
	}

	switch (tag) {
	case IO_REPARSE_TAG_INTERNAL:
		if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
			return false;
		fallthrough;
	case IO_REPARSE_TAG_DFS:
	case IO_REPARSE_TAG_DFSR:
	case IO_REPARSE_TAG_MOUNT_POINT:
+17 −2
Original line number Diff line number Diff line
@@ -12,6 +12,12 @@
#include "fs_context.h"
#include "cifsglob.h"

/*
 * Used only by cifs.ko to ignore reparse points from files when client or
 * server doesn't support FSCTL_GET_REPARSE_POINT.
 */
#define IO_REPARSE_TAG_INTERNAL ((__u32)~0U)

static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
{
	u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer);
@@ -78,10 +84,19 @@ static inline u32 reparse_mode_wsl_tag(mode_t mode)
static inline bool reparse_inode_match(struct inode *inode,
				       struct cifs_fattr *fattr)
{
	struct cifsInodeInfo *cinode = CIFS_I(inode);
	struct timespec64 ctime = inode_get_ctime(inode);

	return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) &&
		CIFS_I(inode)->reparse_tag == fattr->cf_cifstag &&
	/*
	 * Do not match reparse tags when client or server doesn't support
	 * FSCTL_GET_REPARSE_POINT.  @fattr->cf_cifstag should contain correct
	 * reparse tag from query dir response but the client won't be able to
	 * read the reparse point data anyway.  This spares us a revalidation.
	 */
	if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL &&
	    cinode->reparse_tag != fattr->cf_cifstag)
		return false;
	return (cinode->cifsAttrs & ATTR_REPARSE) &&
		timespec64_equal(&ctime, &fattr->cf_ctime);
}

+2 −0
Original line number Diff line number Diff line
@@ -930,6 +930,8 @@ int smb2_query_path_info(const unsigned int xid,

	switch (rc) {
	case 0:
		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
		break;
	case -EOPNOTSUPP:
		/*
		 * BB TODO: When support for special files added to Samba