cifs: use get/put_unaligned functions to access ByteCount

It's possible that when we access the ByteCount that the alignment
will be off. Most CPUs deal with that transparently, but there's
usually some performance impact. Some CPUs raise an exception on
unaligned accesses.

Fix this by accessing the byte count using the get_unaligned and
put_unaligned inlined functions. While we're at it, fix the types
of some of the variables that end up getting returns from these
functions.

Acked-by: Pavel Shilovsky <piastryyy@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French 690c522f aae62fdb

+65 -32
+43 -4
fs/cifs/cifspdu.h
··· 23 #define _CIFSPDU_H 24 25 #include <net/sock.h> 26 #include "smbfsctl.h" 27 28 #ifdef CONFIG_CIFS_WEAK_PW_HASH ··· 427 __u16 Mid; 428 __u8 WordCount; 429 } __attribute__((packed)); 430 - /* given a pointer to an smb_hdr retrieve the value of byte count */ 431 - #define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) 432 - #define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) 433 /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ 434 - #define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2) 435 436 /* 437 * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
··· 23 #define _CIFSPDU_H 24 25 #include <net/sock.h> 26 + #include <asm/unaligned.h> 27 #include "smbfsctl.h" 28 29 #ifdef CONFIG_CIFS_WEAK_PW_HASH ··· 426 __u16 Mid; 427 __u8 WordCount; 428 } __attribute__((packed)); 429 + 430 + /* given a pointer to an smb_hdr retrieve a char pointer to the byte count */ 431 + #define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \ 432 + (2 * (smb_var)->WordCount)) 433 + 434 /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ 435 + #define pByteArea(smb_var) (BCC(smb_var) + 2) 436 + 437 + /* get the converted ByteCount for a SMB packet and return it */ 438 + static inline __u16 439 + get_bcc(struct smb_hdr *hdr) 440 + { 441 + __u16 *bc_ptr = (__u16 *)BCC(hdr); 442 + 443 + return get_unaligned(bc_ptr); 444 + } 445 + 446 + /* get the unconverted ByteCount for a SMB packet and return it */ 447 + static inline __u16 448 + get_bcc_le(struct smb_hdr *hdr) 449 + { 450 + __le16 *bc_ptr = (__le16 *)BCC(hdr); 451 + 452 + return get_unaligned_le16(bc_ptr); 453 + } 454 + 455 + /* set the ByteCount for a SMB packet in host-byte order */ 456 + static inline void 457 + put_bcc(__u16 count, struct smb_hdr *hdr) 458 + { 459 + __u16 *bc_ptr = (__u16 *)BCC(hdr); 460 + 461 + put_unaligned(count, bc_ptr); 462 + } 463 + 464 + /* set the ByteCount for a SMB packet in little-endian */ 465 + static inline void 466 + put_bcc_le(__u16 count, struct smb_hdr *hdr) 467 + { 468 + __le16 *bc_ptr = (__le16 *)BCC(hdr); 469 + 470 + put_unaligned_le16(count, bc_ptr); 471 + } 472 473 /* 474 * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
+5 -9
fs/cifs/cifssmb.c
··· 333 { 334 int rc = -EINVAL; 335 int total_size; 336 - char *pBCC; 337 338 /* check for plausible wct, bcc and t2 data and parm sizes */ 339 /* check for parm and data offset going beyond end of smb */ ··· 345 if (total_size < 512) { 346 total_size += 347 le16_to_cpu(pSMB->t2_rsp.DataCount); 348 - /* BCC le converted in SendReceive */ 349 - pBCC = (pSMB->hdr.WordCount * 2) + 350 - sizeof(struct smb_hdr) + 351 - (char *)pSMB; 352 - if ((total_size <= (*(u16 *)pBCC)) && 353 - (total_size < 354 - CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { 355 return 0; 356 } 357 } ··· 357 sizeof(struct smb_t2_rsp) + 16); 358 return rc; 359 } 360 int 361 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) 362 { ··· 5605 } 5606 5607 /* make sure list_len doesn't go past end of SMB */ 5608 - end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); 5609 if ((char *)ea_response_data + list_len > end_of_smb) { 5610 cFYI(1, "EA list appears to go beyond SMB"); 5611 rc = -EIO;
··· 333 { 334 int rc = -EINVAL; 335 int total_size; 336 337 /* check for plausible wct, bcc and t2 data and parm sizes */ 338 /* check for parm and data offset going beyond end of smb */ ··· 346 if (total_size < 512) { 347 total_size += 348 le16_to_cpu(pSMB->t2_rsp.DataCount); 349 + if (total_size <= get_bcc(&pSMB->hdr) && 350 + total_size < 351 + CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { 352 return 0; 353 } 354 } ··· 362 sizeof(struct smb_t2_rsp) + 16); 363 return rc; 364 } 365 + 366 int 367 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) 368 { ··· 5609 } 5610 5611 /* make sure list_len doesn't go past end of SMB */ 5612 + end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); 5613 if ((char *)ea_response_data + list_len > end_of_smb) { 5614 cFYI(1, "EA list appears to go beyond SMB"); 5615 rc = -EIO;
+5 -5
fs/cifs/connect.c
··· 318 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); 319 total_in_buf += total_in_buf2; 320 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); 321 - byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); 322 byte_count += total_in_buf2; 323 - BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); 324 325 byte_count = pTargetSMB->smb_buf_length; 326 byte_count += total_in_buf2; ··· 2937 TCONX_RSP *pSMBr; 2938 unsigned char *bcc_ptr; 2939 int rc = 0; 2940 - int length, bytes_left; 2941 - __u16 count; 2942 2943 if (ses == NULL) 2944 return -EIO; ··· 3032 tcon->need_reconnect = false; 3033 tcon->tid = smb_buffer_response->Tid; 3034 bcc_ptr = pByteArea(smb_buffer_response); 3035 - bytes_left = BCC(smb_buffer_response); 3036 length = strnlen(bcc_ptr, bytes_left - 2); 3037 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) 3038 is_unicode = true;
··· 318 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); 319 total_in_buf += total_in_buf2; 320 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); 321 + byte_count = get_bcc_le(pTargetSMB); 322 byte_count += total_in_buf2; 323 + put_bcc_le(byte_count, pTargetSMB); 324 325 byte_count = pTargetSMB->smb_buf_length; 326 byte_count += total_in_buf2; ··· 2937 TCONX_RSP *pSMBr; 2938 unsigned char *bcc_ptr; 2939 int rc = 0; 2940 + int length; 2941 + __u16 bytes_left, count; 2942 2943 if (ses == NULL) 2944 return -EIO; ··· 3032 tcon->need_reconnect = false; 3033 tcon->tid = smb_buffer_response->Tid; 3034 bcc_ptr = pByteArea(smb_buffer_response); 3035 + bytes_left = get_bcc(smb_buffer_response); 3036 length = strnlen(bcc_ptr, bytes_left - 2); 3037 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) 3038 is_unicode = true;
+2 -2
fs/cifs/netmisc.c
··· 916 smbCalcSize(struct smb_hdr *ptr) 917 { 918 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 919 - 2 /* size of the bcc field */ + BCC(ptr)); 920 } 921 922 unsigned int 923 smbCalcSize_LE(struct smb_hdr *ptr) 924 { 925 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 926 - 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); 927 } 928 929 /* The following are taken from fs/ntfs/util.c */
··· 916 smbCalcSize(struct smb_hdr *ptr) 917 { 918 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 919 + 2 /* size of the bcc field */ + get_bcc(ptr)); 920 } 921 922 unsigned int 923 smbCalcSize_LE(struct smb_hdr *ptr) 924 { 925 return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + 926 + 2 /* size of the bcc field */ + get_bcc_le(ptr)); 927 } 928 929 /* The following are taken from fs/ntfs/util.c */
+6 -7
fs/cifs/sess.c
··· 277 } 278 279 static void 280 - decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, 281 const struct nls_table *nls_cp) 282 { 283 int len; ··· 323 return; 324 } 325 326 - static int decode_ascii_ssetup(char **pbcc_area, int bleft, 327 struct cifsSesInfo *ses, 328 const struct nls_table *nls_cp) 329 { ··· 575 char *str_area; 576 SESSION_SETUP_ANDX *pSMB; 577 __u32 capabilities; 578 - int count; 579 int resp_buf_type; 580 struct kvec iov[3]; 581 enum securityEnum type; 582 - __u16 action; 583 - int bytes_remaining; 584 struct key *spnego_key = NULL; 585 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 586 u16 blob_len; ··· 875 count = iov[1].iov_len + iov[2].iov_len; 876 smb_buf->smb_buf_length += count; 877 878 - BCC_LE(smb_buf) = cpu_to_le16(count); 879 880 rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, 881 CIFS_LOG_ERROR); ··· 909 cFYI(1, "UID = %d ", ses->Suid); 910 /* response can have either 3 or 4 word count - Samba sends 3 */ 911 /* and lanman response is 3 */ 912 - bytes_remaining = BCC(smb_buf); 913 bcc_ptr = pByteArea(smb_buf); 914 915 if (smb_buf->WordCount == 4) {
··· 277 } 278 279 static void 280 + decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, 281 const struct nls_table *nls_cp) 282 { 283 int len; ··· 323 return; 324 } 325 326 + static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft, 327 struct cifsSesInfo *ses, 328 const struct nls_table *nls_cp) 329 { ··· 575 char *str_area; 576 SESSION_SETUP_ANDX *pSMB; 577 __u32 capabilities; 578 + __u16 count; 579 int resp_buf_type; 580 struct kvec iov[3]; 581 enum securityEnum type; 582 + __u16 action, bytes_remaining; 583 struct key *spnego_key = NULL; 584 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 585 u16 blob_len; ··· 876 count = iov[1].iov_len + iov[2].iov_len; 877 smb_buf->smb_buf_length += count; 878 879 + put_bcc_le(count, smb_buf); 880 881 rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, 882 CIFS_LOG_ERROR); ··· 910 cFYI(1, "UID = %d ", ses->Suid); 911 /* response can have either 3 or 4 word count - Samba sends 3 */ 912 /* and lanman response is 3 */ 913 + bytes_remaining = get_bcc(smb_buf); 914 bcc_ptr = pByteArea(smb_buf); 915 916 if (smb_buf->WordCount == 4) {
+4 -5
fs/cifs/transport.c
··· 484 in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; 485 in_buf->Command = SMB_COM_NT_CANCEL; 486 in_buf->WordCount = 0; 487 - BCC_LE(in_buf) = 0; 488 489 mutex_lock(&server->srv_mutex); 490 rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); ··· 632 if (receive_len >= sizeof(struct smb_hdr) - 4 633 /* do not count RFC1001 header */ + 634 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) 635 - BCC(midQ->resp_buf) = 636 - le16_to_cpu(BCC_LE(midQ->resp_buf)); 637 if ((flags & CIFS_NO_RESP) == 0) 638 midQ->resp_buf = NULL; /* mark it so buf will 639 not be freed by ··· 775 if (receive_len >= sizeof(struct smb_hdr) - 4 776 /* do not count RFC1001 header */ + 777 (2 * out_buf->WordCount) + 2 /* bcc */ ) 778 - BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); 779 } else { 780 rc = -EIO; 781 cERROR(1, "Bad MID state?"); ··· 976 if (receive_len >= sizeof(struct smb_hdr) - 4 977 /* do not count RFC1001 header */ + 978 (2 * out_buf->WordCount) + 2 /* bcc */ ) 979 - BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); 980 981 out: 982 delete_mid(midQ);
··· 484 in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; 485 in_buf->Command = SMB_COM_NT_CANCEL; 486 in_buf->WordCount = 0; 487 + put_bcc_le(0, in_buf); 488 489 mutex_lock(&server->srv_mutex); 490 rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); ··· 632 if (receive_len >= sizeof(struct smb_hdr) - 4 633 /* do not count RFC1001 header */ + 634 (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) 635 + put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); 636 if ((flags & CIFS_NO_RESP) == 0) 637 midQ->resp_buf = NULL; /* mark it so buf will 638 not be freed by ··· 776 if (receive_len >= sizeof(struct smb_hdr) - 4 777 /* do not count RFC1001 header */ + 778 (2 * out_buf->WordCount) + 2 /* bcc */ ) 779 + put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); 780 } else { 781 rc = -EIO; 782 cERROR(1, "Bad MID state?"); ··· 977 if (receive_len >= sizeof(struct smb_hdr) - 4 978 /* do not count RFC1001 header */ + 979 (2 * out_buf->WordCount) + 2 /* bcc */ ) 980 + put_bcc(get_bcc_le(out_buf), out_buf); 981 982 out: 983 delete_mid(midQ);