mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-01 22:54:01 +00:00
cifs: update smb2_check_message to handle PDUs without a 4 byte length header
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
b326614ea2
commit
98170fb535
1 changed files with 20 additions and 30 deletions
|
@ -94,7 +94,8 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_SMB311
|
#ifdef CONFIG_CIFS_SMB311
|
||||||
static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len,
|
||||||
|
__u32 non_ctxlen,
|
||||||
size_t hdr_preamble_size)
|
size_t hdr_preamble_size)
|
||||||
{
|
{
|
||||||
__u16 neg_count;
|
__u16 neg_count;
|
||||||
|
@ -131,25 +132,20 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, __u32 non_ctxlen,
|
||||||
#endif /* CIFS_SMB311 */
|
#endif /* CIFS_SMB311 */
|
||||||
|
|
||||||
int
|
int
|
||||||
smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *srvr)
|
||||||
{
|
{
|
||||||
struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
|
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)(buf + srvr->vals->header_preamble_size);
|
||||||
struct smb2_hdr *hdr = &pdu->hdr;
|
struct smb2_sync_pdu *pdu = (struct smb2_sync_pdu *)shdr;
|
||||||
struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
|
|
||||||
__u64 mid;
|
__u64 mid;
|
||||||
__u32 len = get_rfc1002_length(buf);
|
|
||||||
__u32 clc_len; /* calculated length */
|
__u32 clc_len; /* calculated length */
|
||||||
int command;
|
int command;
|
||||||
|
int pdu_size = sizeof(struct smb2_sync_pdu);
|
||||||
/* BB disable following printk later */
|
int hdr_size = sizeof(struct smb2_sync_hdr);
|
||||||
cifs_dbg(FYI, "%s length: 0x%x, smb_buf_length: 0x%x\n",
|
|
||||||
__func__, length, len);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add function to do table lookup of StructureSize by command
|
* Add function to do table lookup of StructureSize by command
|
||||||
* ie Validate the wct via smb2_struct_sizes table above
|
* ie Validate the wct via smb2_struct_sizes table above
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
||||||
struct smb2_transform_hdr *thdr =
|
struct smb2_transform_hdr *thdr =
|
||||||
(struct smb2_transform_hdr *)buf;
|
(struct smb2_transform_hdr *)buf;
|
||||||
|
@ -173,8 +169,8 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||||
}
|
}
|
||||||
|
|
||||||
mid = le64_to_cpu(shdr->MessageId);
|
mid = le64_to_cpu(shdr->MessageId);
|
||||||
if (length < sizeof(struct smb2_pdu)) {
|
if (len < pdu_size) {
|
||||||
if ((length >= sizeof(struct smb2_hdr))
|
if ((len >= hdr_size)
|
||||||
&& (shdr->Status != 0)) {
|
&& (shdr->Status != 0)) {
|
||||||
pdu->StructureSize2 = 0;
|
pdu->StructureSize2 = 0;
|
||||||
/*
|
/*
|
||||||
|
@ -227,31 +223,25 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srvr->vals->header_preamble_size + len != length) {
|
clc_len = smb2_calc_size(buf, srvr);
|
||||||
cifs_dbg(VFS, "Total length %u RFC1002 length %zu mismatch mid %llu\n",
|
|
||||||
length, srvr->vals->header_preamble_size + len, mid);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
clc_len = smb2_calc_size(hdr, srvr);
|
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_SMB311
|
#ifdef CONFIG_CIFS_SMB311
|
||||||
if (shdr->Command == SMB2_NEGOTIATE)
|
if (shdr->Command == SMB2_NEGOTIATE)
|
||||||
clc_len += get_neg_ctxt_len(hdr, len, clc_len,
|
clc_len += get_neg_ctxt_len(shdr, len, clc_len,
|
||||||
srvr->vals->header_preamble_size);
|
srvr->vals->header_preamble_size);
|
||||||
#endif /* SMB311 */
|
#endif /* SMB311 */
|
||||||
if (srvr->vals->header_preamble_size + len != clc_len) {
|
if (len != clc_len) {
|
||||||
cifs_dbg(FYI, "Calculated size %u length %zu mismatch mid %llu\n",
|
cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
|
||||||
clc_len, srvr->vals->header_preamble_size + len, mid);
|
clc_len, len, mid);
|
||||||
/* create failed on symlink */
|
/* create failed on symlink */
|
||||||
if (command == SMB2_CREATE_HE &&
|
if (command == SMB2_CREATE_HE &&
|
||||||
shdr->Status == STATUS_STOPPED_ON_SYMLINK)
|
shdr->Status == STATUS_STOPPED_ON_SYMLINK)
|
||||||
return 0;
|
return 0;
|
||||||
/* Windows 7 server returns 24 bytes more */
|
/* Windows 7 server returns 24 bytes more */
|
||||||
if (clc_len + 24 - srvr->vals->header_preamble_size == len && command == SMB2_OPLOCK_BREAK_HE)
|
if (clc_len + 24 == len && command == SMB2_OPLOCK_BREAK_HE)
|
||||||
return 0;
|
return 0;
|
||||||
/* server can return one byte more due to implied bcc[0] */
|
/* server can return one byte more due to implied bcc[0] */
|
||||||
if (clc_len == srvr->vals->header_preamble_size + len + 1)
|
if (clc_len == len + 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -261,10 +251,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
|
||||||
* Log the server error (once), but allow it and continue
|
* Log the server error (once), but allow it and continue
|
||||||
* since the frame is parseable.
|
* since the frame is parseable.
|
||||||
*/
|
*/
|
||||||
if (clc_len < srvr->vals->header_preamble_size /* RFC1001 header size */ + len) {
|
if (clc_len < len) {
|
||||||
printk_once(KERN_WARNING
|
printk_once(KERN_WARNING
|
||||||
"SMB2 server sent bad RFC1001 len %d not %zu\n",
|
"SMB2 server sent bad RFC1001 len %d not %u\n",
|
||||||
len, clc_len - srvr->vals->header_preamble_size);
|
len, clc_len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue