Various SMB3 fixes for 4.14 and stable
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQGcBAABAgAGBQJZ81hKAAoJEIosvXAHck9R7K4L/R4vPpYn19s/xPUf0fUYMOWO JOIghfeCmmfCd2kTZF+fcDRNBpGnJjjs4ZPloxIbF7bQF0VbjrkToxthF6f9aYIJ gt0jH1ntGUvraDpkZelTAGRj1BZou2IBzJF3Or1sL83ZX76fyXm9cJUx8Y+l2Mlx BJMOL0Au38oRKOGnGk3GPtrflgNxe+6cTpNhLmVa9CBNDMQYjobrALgGPpbGf5h3 6l1i0IxMXuxeXjqFva0GKCjTsQSON44gNNHQoggIfHvE3nBVpSZLCwNwrVHOfd8q 4FlEXPzr3ME4WzASWqw1kAX+aij2NqbaLgDs7USkn4mUheIvZcHhC0LPVZJrZ1b4 2c3RHkOV0aZQunPJyq5vtO9B4TJC6MLcHS46iwQ6lao9hTVT8OqV7R40qmzQyt06 KwdIGObEm76J7u4lgVlAsapVKgPLOPuObQKhYUdNvRarorNaxgtadnHOhXM20G3S PE23XvNJYwKl6SJbP97ih8Uq0//7vNCxd/khdnq4FQ== =8LHe -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7814023404
@ -5,9 +5,14 @@ config CIFS
|
|||||||
select CRYPTO
|
select CRYPTO
|
||||||
select CRYPTO_MD4
|
select CRYPTO_MD4
|
||||||
select CRYPTO_MD5
|
select CRYPTO_MD5
|
||||||
|
select CRYPTO_SHA256
|
||||||
|
select CRYPTO_CMAC
|
||||||
select CRYPTO_HMAC
|
select CRYPTO_HMAC
|
||||||
select CRYPTO_ARC4
|
select CRYPTO_ARC4
|
||||||
|
select CRYPTO_AEAD2
|
||||||
|
select CRYPTO_CCM
|
||||||
select CRYPTO_ECB
|
select CRYPTO_ECB
|
||||||
|
select CRYPTO_AES
|
||||||
select CRYPTO_DES
|
select CRYPTO_DES
|
||||||
help
|
help
|
||||||
This is the client VFS module for the SMB3 family of NAS protocols,
|
This is the client VFS module for the SMB3 family of NAS protocols,
|
||||||
|
@ -661,7 +661,9 @@ struct TCP_Server_Info {
|
|||||||
#endif
|
#endif
|
||||||
unsigned int max_read;
|
unsigned int max_read;
|
||||||
unsigned int max_write;
|
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 delayed_work reconnect; /* reconnect workqueue job */
|
||||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||||
unsigned long echo_interval;
|
unsigned long echo_interval;
|
||||||
@ -849,7 +851,9 @@ struct cifs_ses {
|
|||||||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||||
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
|
__u8 smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
|
||||||
__u8 smb3decryptionkey[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
|
static inline bool
|
||||||
|
@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
|||||||
{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
|
{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
|
||||||
{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
|
{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
|
||||||
{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
|
{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_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
|
||||||
{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
|
{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
|
||||||
{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
|
{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
|
||||||
|
@ -522,6 +522,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
struct cifs_open_parms oparms;
|
struct cifs_open_parms oparms;
|
||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
struct smb2_file_full_ea_info *smb2_data;
|
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);
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
@ -541,14 +542,32 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
|
while (1) {
|
||||||
if (smb2_data == NULL) {
|
smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
if (smb2_data == NULL) {
|
||||||
return -ENOMEM;
|
SMB2_close(xid, tcon, fid.persistent_fid,
|
||||||
|
fid.volatile_fid);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
||||||
smb2_data);
|
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
@ -648,7 +648,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct validate_negotiate_info_req vneg_inbuf;
|
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 rsplen;
|
||||||
u32 inbuflen; /* max of 4 dialects */
|
u32 inbuflen; /* max of 4 dialects */
|
||||||
|
|
||||||
@ -727,8 +727,9 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
|
|||||||
rsplen);
|
rsplen);
|
||||||
|
|
||||||
/* relax check since Mac returns max bufsize allowed on ioctl */
|
/* relax check since Mac returns max bufsize allowed on ioctl */
|
||||||
if (rsplen > CIFSMaxBufSize)
|
if ((rsplen > CIFSMaxBufSize)
|
||||||
return -EIO;
|
|| (rsplen < sizeof(struct validate_negotiate_info_rsp)))
|
||||||
|
goto err_rsp_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check validate negotiate info response matches what we got earlier */
|
/* 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 */
|
/* validate negotiate successful */
|
||||||
cifs_dbg(FYI, "validate negotiate info successful\n");
|
cifs_dbg(FYI, "validate negotiate info successful\n");
|
||||||
|
kfree(pneg_rsp);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vneg_out:
|
vneg_out:
|
||||||
cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n");
|
cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n");
|
||||||
|
err_rsp_free:
|
||||||
|
kfree(pneg_rsp);
|
||||||
return -EIO;
|
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_req *req;
|
||||||
struct smb2_tree_connect_rsp *rsp = NULL;
|
struct smb2_tree_connect_rsp *rsp = NULL;
|
||||||
struct kvec iov[2];
|
struct kvec iov[2];
|
||||||
struct kvec rsp_iov;
|
struct kvec rsp_iov = { NULL, 0 };
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int resp_buftype;
|
int resp_buftype;
|
||||||
int unc_path_len;
|
int unc_path_len;
|
||||||
@ -1372,7 +1376,7 @@ tcon_exit:
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
tcon_error_exit:
|
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);
|
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
|
||||||
}
|
}
|
||||||
goto tcon_exit;
|
goto tcon_exit;
|
||||||
@ -1975,6 +1979,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
|||||||
} else
|
} else
|
||||||
iov[0].iov_len = get_rfc1002_length(req) + 4;
|
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);
|
rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
|
||||||
cifs_small_buf_release(req);
|
cifs_small_buf_release(req);
|
||||||
@ -2191,9 +2198,13 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
req->PersistentFileId = persistent_fid;
|
req->PersistentFileId = persistent_fid;
|
||||||
req->VolatileFileId = volatile_fid;
|
req->VolatileFileId = volatile_fid;
|
||||||
req->AdditionalInformation = cpu_to_le32(additional_info);
|
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);
|
req->OutputBufferLength = cpu_to_le32(output_len);
|
||||||
|
|
||||||
iov[0].iov_base = (char *)req;
|
iov[0].iov_base = (char *)req;
|
||||||
@ -2233,12 +2244,12 @@ qinf_exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int SMB2_query_eas(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,
|
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,
|
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||||
FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
|
FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
|
||||||
SMB2_MAX_EA_BUF,
|
ea_buf_size,
|
||||||
sizeof(struct smb2_file_full_ea_info),
|
sizeof(struct smb2_file_full_ea_info),
|
||||||
(void **)&data,
|
(void **)&data,
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -832,7 +832,7 @@ struct smb2_flush_rsp {
|
|||||||
/* Channel field for read and write: exactly one of following flags can be set*/
|
/* Channel field for read and write: exactly one of following flags can be set*/
|
||||||
#define SMB2_CHANNEL_NONE 0x00000000
|
#define SMB2_CHANNEL_NONE 0x00000000
|
||||||
#define SMB2_CHANNEL_RDMA_V1 0x00000001 /* SMB3 or later */
|
#define SMB2_CHANNEL_RDMA_V1 0x00000001 /* SMB3 or later */
|
||||||
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
|
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000002 /* SMB3.02 or later */
|
||||||
|
|
||||||
/* SMB2 read request without RFC1001 length at the beginning */
|
/* SMB2 read request without RFC1001 length at the beginning */
|
||||||
struct smb2_read_plain_req {
|
struct smb2_read_plain_req {
|
||||||
@ -1178,7 +1178,8 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
|
|||||||
char FileName[0]; /* Name to be assigned to new link */
|
char FileName[0]; /* Name to be assigned to new link */
|
||||||
} __packed; /* level 11 Set */
|
} __packed; /* level 11 Set */
|
||||||
|
|
||||||
#define SMB2_MAX_EA_BUF 2048
|
#define SMB2_MIN_EA_BUF 2048
|
||||||
|
#define SMB2_MAX_EA_BUF 65536
|
||||||
|
|
||||||
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
||||||
__le32 next_entry_offset;
|
__le32 next_entry_offset;
|
||||||
|
@ -134,6 +134,7 @@ extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
|||||||
u64 persistent_file_id, u64 volatile_file_id);
|
u64 persistent_file_id, u64 volatile_file_id);
|
||||||
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id,
|
u64 persistent_file_id, u64 volatile_file_id,
|
||||||
|
int ea_buf_size,
|
||||||
struct smb2_file_full_ea_info *data);
|
struct smb2_file_full_ea_info *data);
|
||||||
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id,
|
u64 persistent_file_id, u64 volatile_file_id,
|
||||||
|
@ -390,6 +390,7 @@ generate_smb30signingkey(struct cifs_ses *ses)
|
|||||||
return generate_smb3signingkey(ses, &triplet);
|
return generate_smb3signingkey(ses, &triplet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_SMB311
|
||||||
int
|
int
|
||||||
generate_smb311signingkey(struct cifs_ses *ses)
|
generate_smb311signingkey(struct cifs_ses *ses)
|
||||||
|
|
||||||
@ -398,25 +399,26 @@ generate_smb311signingkey(struct cifs_ses *ses)
|
|||||||
struct derivation *d;
|
struct derivation *d;
|
||||||
|
|
||||||
d = &triplet.signing;
|
d = &triplet.signing;
|
||||||
d->label.iov_base = "SMB2AESCMAC";
|
d->label.iov_base = "SMBSigningKey";
|
||||||
d->label.iov_len = 12;
|
d->label.iov_len = 14;
|
||||||
d->context.iov_base = "SmbSign";
|
d->context.iov_base = ses->preauth_sha_hash;
|
||||||
d->context.iov_len = 8;
|
d->context.iov_len = 64;
|
||||||
|
|
||||||
d = &triplet.encryption;
|
d = &triplet.encryption;
|
||||||
d->label.iov_base = "SMB2AESCCM";
|
d->label.iov_base = "SMBC2SCipherKey";
|
||||||
d->label.iov_len = 11;
|
d->label.iov_len = 16;
|
||||||
d->context.iov_base = "ServerIn ";
|
d->context.iov_base = ses->preauth_sha_hash;
|
||||||
d->context.iov_len = 10;
|
d->context.iov_len = 64;
|
||||||
|
|
||||||
d = &triplet.decryption;
|
d = &triplet.decryption;
|
||||||
d->label.iov_base = "SMB2AESCCM";
|
d->label.iov_base = "SMBS2CCipherKey";
|
||||||
d->label.iov_len = 11;
|
d->label.iov_len = 16;
|
||||||
d->context.iov_base = "ServerOut";
|
d->context.iov_base = ses->preauth_sha_hash;
|
||||||
d->context.iov_len = 10;
|
d->context.iov_len = 64;
|
||||||
|
|
||||||
return generate_smb3signingkey(ses, &triplet);
|
return generate_smb3signingkey(ses, &triplet);
|
||||||
}
|
}
|
||||||
|
#endif /* 311 */
|
||||||
|
|
||||||
int
|
int
|
||||||
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user