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