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