Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78140234 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '4.14-smb3-fixes-for-stable' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Various SMB3 fixes for 4.14 and stable"

* tag '4.14-smb3-fixes-for-stable' of git://git.samba.org/sfrench/cifs-2.6:
  SMB3: Validate negotiate request must always be signed
  SMB: fix validate negotiate info uninitialised memory use
  SMB: fix leak of validate negotiate info response buffer
  CIFS: Fix NULL pointer deref on SMB2_tcon() failure
  CIFS: do not send invalid input buffer on QUERY_INFO requests
  cifs: Select all required crypto modules
  CIFS: SMBD: Fix the definition for SMB2_CHANNEL_RDMA_V1_INVALIDATE
  cifs: handle large EA requests more gracefully in smb2+
  Fix encryption labels and lengths for SMB3.1.1
parents c9f27f9f 4587eee0
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -5,9 +5,14 @@ config CIFS
	select CRYPTO
	select CRYPTO_MD4
	select CRYPTO_MD5
	select CRYPTO_SHA256
	select CRYPTO_CMAC
	select CRYPTO_HMAC
	select CRYPTO_ARC4
	select CRYPTO_AEAD2
	select CRYPTO_CCM
	select CRYPTO_ECB
	select CRYPTO_AES
	select CRYPTO_DES
	help
	  This is the client VFS module for the SMB3 family of NAS protocols,
+6 −2
Original line number Diff line number Diff line
@@ -661,7 +661,9 @@ struct TCP_Server_Info {
#endif
	unsigned int	max_read;
	unsigned int	max_write;
	__u8		preauth_hash[512];
#ifdef CONFIG_CIFS_SMB311
	__u8	preauth_sha_hash[64]; /* save initital negprot hash */
#endif /* 3.1.1 */
	struct delayed_work reconnect; /* reconnect workqueue job */
	struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
	unsigned long echo_interval;
@@ -849,7 +851,9 @@ struct cifs_ses {
	__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
	__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
	__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
	__u8 preauth_hash[512];
#ifdef CONFIG_CIFS_SMB311
	__u8 preauth_sha_hash[64];
#endif /* 3.1.1 */
};

static inline bool
+1 −1
Original line number Diff line number Diff line
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
	{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
	{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
	{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
	{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
	{STATUS_BUFFER_OVERFLOW, -E2BIG, "STATUS_BUFFER_OVERFLOW"},
	{STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
	{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
	{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
+25 −6
Original line number Diff line number Diff line
@@ -522,6 +522,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
	struct cifs_open_parms oparms;
	struct cifs_fid fid;
	struct smb2_file_full_ea_info *smb2_data;
	int ea_buf_size = SMB2_MIN_EA_BUF;

	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
	if (!utf16_path)
@@ -541,14 +542,32 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
		return rc;
	}

	smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
	while (1) {
		smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
		if (smb2_data == NULL) {
		SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
			SMB2_close(xid, tcon, fid.persistent_fid,
				   fid.volatile_fid);
			return -ENOMEM;
		}

	rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
			    smb2_data);
		rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
				    fid.volatile_fid,
				    ea_buf_size, smb2_data);

		if (rc != -E2BIG)
			break;

		kfree(smb2_data);
		ea_buf_size <<= 1;

		if (ea_buf_size > SMB2_MAX_EA_BUF) {
			cifs_dbg(VFS, "EA size is too large\n");
			SMB2_close(xid, tcon, fid.persistent_fid,
				   fid.volatile_fid);
			return -ENOMEM;
		}
	}

	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);

	if (!rc)
+22 −11
Original line number Diff line number Diff line
@@ -648,7 +648,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
{
	int rc = 0;
	struct validate_negotiate_info_req vneg_inbuf;
	struct validate_negotiate_info_rsp *pneg_rsp;
	struct validate_negotiate_info_rsp *pneg_rsp = NULL;
	u32 rsplen;
	u32 inbuflen; /* max of 4 dialects */

@@ -727,8 +727,9 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
			 rsplen);

		/* relax check since Mac returns max bufsize allowed on ioctl */
		if (rsplen > CIFSMaxBufSize)
			return -EIO;
		if ((rsplen > CIFSMaxBufSize)
		     || (rsplen < sizeof(struct validate_negotiate_info_rsp)))
			goto err_rsp_free;
	}

	/* check validate negotiate info response matches what we got earlier */
@@ -747,10 +748,13 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)

	/* validate negotiate successful */
	cifs_dbg(FYI, "validate negotiate info successful\n");
	kfree(pneg_rsp);
	return 0;

vneg_out:
	cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n");
err_rsp_free:
	kfree(pneg_rsp);
	return -EIO;
}

@@ -1255,7 +1259,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
	struct smb2_tree_connect_req *req;
	struct smb2_tree_connect_rsp *rsp = NULL;
	struct kvec iov[2];
	struct kvec rsp_iov;
	struct kvec rsp_iov = { NULL, 0 };
	int rc = 0;
	int resp_buftype;
	int unc_path_len;
@@ -1372,7 +1376,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
	return rc;

tcon_error_exit:
	if (rsp->hdr.sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
	if (rsp && rsp->hdr.sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
		cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
	}
	goto tcon_exit;
@@ -1975,6 +1979,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
	} else
		iov[0].iov_len = get_rfc1002_length(req) + 4;

	/* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */
	if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
		req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED;

	rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
	cifs_small_buf_release(req);
@@ -2191,9 +2198,13 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
	req->PersistentFileId = persistent_fid;
	req->VolatileFileId = volatile_fid;
	req->AdditionalInformation = cpu_to_le32(additional_info);
	/* 4 for rfc1002 length field and 1 for Buffer */
	req->InputBufferOffset =
		cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);

	/*
	 * We do not use the input buffer (do not send extra byte)
	 */
	req->InputBufferOffset = 0;
	inc_rfc1001_len(req, -1);

	req->OutputBufferLength = cpu_to_le32(output_len);

	iov[0].iov_base = (char *)req;
@@ -2234,11 +2245,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,

int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
		   u64 persistent_fid, u64 volatile_fid,
	struct smb2_file_full_ea_info *data)
		   int ea_buf_size, struct smb2_file_full_ea_info *data)
{
	return query_info(xid, tcon, persistent_fid, volatile_fid,
			  FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
			  SMB2_MAX_EA_BUF,
			  ea_buf_size,
			  sizeof(struct smb2_file_full_ea_info),
			  (void **)&data,
			  NULL);
Loading