diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-02 12:15:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-02 12:15:21 -0500 |
commit | 12f1d7e4932a40100177be5681f1a26f46265217 (patch) | |
tree | e8e1795663ae7d227bf4490d2876968fa7ca0c43 | |
parent | 39680f50ae54cbbb6e72ac38b8329dd3eb9105f4 (diff) | |
parent | 9589995e46d89c70c6fa4723c5f3e5ec04c3c3e3 (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French:
"Various small CIFS/SMB3 fixes for stable:
Fixes address oops that can occur when accessing Macs with SMB3, and
another problem found to Samba when read responses queued (e.g. with
gluster under Samba)"
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
CIFS: Fix duplicate line introduced by clone_file_range patch
Fix cifs_uniqueid_to_ino_t() function for s390x
CIFS: Fix SMB2+ interim response processing for read requests
cifs: fix out-of-bounds access in lease parsing
-rw-r--r-- | fs/cifs/cifsfs.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 21 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 24 |
4 files changed, 36 insertions, 22 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c48ca13673e3..2eea40353e60 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -1013,7 +1013,6 @@ const struct file_operations cifs_file_strict_ops = { | |||
1013 | .llseek = cifs_llseek, | 1013 | .llseek = cifs_llseek, |
1014 | .unlocked_ioctl = cifs_ioctl, | 1014 | .unlocked_ioctl = cifs_ioctl, |
1015 | .clone_file_range = cifs_clone_file_range, | 1015 | .clone_file_range = cifs_clone_file_range, |
1016 | .clone_file_range = cifs_clone_file_range, | ||
1017 | .setlease = cifs_setlease, | 1016 | .setlease = cifs_setlease, |
1018 | .fallocate = cifs_fallocate, | 1017 | .fallocate = cifs_fallocate, |
1019 | }; | 1018 | }; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 68c4547528c4..83aac8ba50b0 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -31,19 +31,15 @@ | |||
31 | * so that it will fit. We use hash_64 to convert the value to 31 bits, and | 31 | * so that it will fit. We use hash_64 to convert the value to 31 bits, and |
32 | * then add 1, to ensure that we don't end up with a 0 as the value. | 32 | * then add 1, to ensure that we don't end up with a 0 as the value. |
33 | */ | 33 | */ |
34 | #if BITS_PER_LONG == 64 | ||
35 | static inline ino_t | 34 | static inline ino_t |
36 | cifs_uniqueid_to_ino_t(u64 fileid) | 35 | cifs_uniqueid_to_ino_t(u64 fileid) |
37 | { | 36 | { |
37 | if ((sizeof(ino_t)) < (sizeof(u64))) | ||
38 | return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; | ||
39 | |||
38 | return (ino_t)fileid; | 40 | return (ino_t)fileid; |
41 | |||
39 | } | 42 | } |
40 | #else | ||
41 | static inline ino_t | ||
42 | cifs_uniqueid_to_ino_t(u64 fileid) | ||
43 | { | ||
44 | return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; | ||
45 | } | ||
46 | #endif | ||
47 | 43 | ||
48 | extern struct file_system_type cifs_fs_type; | 44 | extern struct file_system_type cifs_fs_type; |
49 | extern const struct address_space_operations cifs_addr_ops; | 45 | extern const struct address_space_operations cifs_addr_ops; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 90b4f9f7de66..76fcb50295a3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1396,11 +1396,10 @@ openRetry: | |||
1396 | * current bigbuf. | 1396 | * current bigbuf. |
1397 | */ | 1397 | */ |
1398 | static int | 1398 | static int |
1399 | cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 1399 | discard_remaining_data(struct TCP_Server_Info *server) |
1400 | { | 1400 | { |
1401 | unsigned int rfclen = get_rfc1002_length(server->smallbuf); | 1401 | unsigned int rfclen = get_rfc1002_length(server->smallbuf); |
1402 | int remaining = rfclen + 4 - server->total_read; | 1402 | int remaining = rfclen + 4 - server->total_read; |
1403 | struct cifs_readdata *rdata = mid->callback_data; | ||
1404 | 1403 | ||
1405 | while (remaining > 0) { | 1404 | while (remaining > 0) { |
1406 | int length; | 1405 | int length; |
@@ -1414,10 +1413,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1414 | remaining -= length; | 1413 | remaining -= length; |
1415 | } | 1414 | } |
1416 | 1415 | ||
1417 | dequeue_mid(mid, rdata->result); | ||
1418 | return 0; | 1416 | return 0; |
1419 | } | 1417 | } |
1420 | 1418 | ||
1419 | static int | ||
1420 | cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | ||
1421 | { | ||
1422 | int length; | ||
1423 | struct cifs_readdata *rdata = mid->callback_data; | ||
1424 | |||
1425 | length = discard_remaining_data(server); | ||
1426 | dequeue_mid(mid, rdata->result); | ||
1427 | return length; | ||
1428 | } | ||
1429 | |||
1421 | int | 1430 | int |
1422 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 1431 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) |
1423 | { | 1432 | { |
@@ -1446,6 +1455,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1446 | return length; | 1455 | return length; |
1447 | server->total_read += length; | 1456 | server->total_read += length; |
1448 | 1457 | ||
1458 | if (server->ops->is_status_pending && | ||
1459 | server->ops->is_status_pending(buf, server, 0)) { | ||
1460 | discard_remaining_data(server); | ||
1461 | return -1; | ||
1462 | } | ||
1463 | |||
1449 | /* Was the SMB read successful? */ | 1464 | /* Was the SMB read successful? */ |
1450 | rdata->result = server->ops->map_error(buf, false); | 1465 | rdata->result = server->ops->map_error(buf, false); |
1451 | if (rdata->result != 0) { | 1466 | if (rdata->result != 0) { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 10f8d5cf5681..42e1f440eb1e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1106,21 +1106,25 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, | |||
1106 | { | 1106 | { |
1107 | char *data_offset; | 1107 | char *data_offset; |
1108 | struct create_context *cc; | 1108 | struct create_context *cc; |
1109 | unsigned int next = 0; | 1109 | unsigned int next; |
1110 | unsigned int remaining; | ||
1110 | char *name; | 1111 | char *name; |
1111 | 1112 | ||
1112 | data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); | 1113 | data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); |
1114 | remaining = le32_to_cpu(rsp->CreateContextsLength); | ||
1113 | cc = (struct create_context *)data_offset; | 1115 | cc = (struct create_context *)data_offset; |
1114 | do { | 1116 | while (remaining >= sizeof(struct create_context)) { |
1115 | cc = (struct create_context *)((char *)cc + next); | ||
1116 | name = le16_to_cpu(cc->NameOffset) + (char *)cc; | 1117 | name = le16_to_cpu(cc->NameOffset) + (char *)cc; |
1117 | if (le16_to_cpu(cc->NameLength) != 4 || | 1118 | if (le16_to_cpu(cc->NameLength) == 4 && |
1118 | strncmp(name, "RqLs", 4)) { | 1119 | strncmp(name, "RqLs", 4) == 0) |
1119 | next = le32_to_cpu(cc->Next); | 1120 | return server->ops->parse_lease_buf(cc, epoch); |
1120 | continue; | 1121 | |
1121 | } | 1122 | next = le32_to_cpu(cc->Next); |
1122 | return server->ops->parse_lease_buf(cc, epoch); | 1123 | if (!next) |
1123 | } while (next != 0); | 1124 | break; |
1125 | remaining -= next; | ||
1126 | cc = (struct create_context *)((char *)cc + next); | ||
1127 | } | ||
1124 | 1128 | ||
1125 | return 0; | 1129 | return 0; |
1126 | } | 1130 | } |