diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-02 14:30:10 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-02 14:30:10 -0400 |
| commit | 5b716ac728bcc01b1f2a7ed6e437196602237c27 (patch) | |
| tree | b2c31c641ca04b72218e00ffebc07d3e8fe303f4 | |
| parent | 0b1a34c992853ecb47daa5be598d7ed2930342dc (diff) | |
| parent | ea7b4887e7266b93fa0c203cc452a926a0fef4f0 (diff) | |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French.
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
CIFS: Fix cifs_do_create error hadnling
cifs: print error code if smb signature verification fails
CIFS: Fix log messages in packet checking for SMB2
CIFS: Protect i_nlink from being negative
| -rw-r--r-- | fs/cifs/cifssmb.c | 11 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 9 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 24 | ||||
| -rw-r--r-- | fs/cifs/link.c | 2 | ||||
| -rw-r--r-- | fs/cifs/smb2misc.c | 16 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.h | 10 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 9 |
7 files changed, 48 insertions, 33 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 074923ce593d..f0cf934ba877 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -1576,9 +1576,14 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
| 1576 | /* result already set, check signature */ | 1576 | /* result already set, check signature */ |
| 1577 | if (server->sec_mode & | 1577 | if (server->sec_mode & |
| 1578 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 1578 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
| 1579 | if (cifs_verify_signature(rdata->iov, rdata->nr_iov, | 1579 | int rc = 0; |
| 1580 | server, mid->sequence_number + 1)) | 1580 | |
| 1581 | cERROR(1, "Unexpected SMB signature"); | 1581 | rc = cifs_verify_signature(rdata->iov, rdata->nr_iov, |
| 1582 | server, | ||
| 1583 | mid->sequence_number + 1); | ||
| 1584 | if (rc) | ||
| 1585 | cERROR(1, "SMB signature verification returned " | ||
| 1586 | "error = %d", rc); | ||
| 1582 | } | 1587 | } |
| 1583 | /* FIXME: should this be counted toward the initiating task? */ | 1588 | /* FIXME: should this be counted toward the initiating task? */ |
| 1584 | task_io_account_read(rdata->bytes); | 1589 | task_io_account_read(rdata->bytes); |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index cbe709ad6663..781025be48bc 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -356,19 +356,12 @@ cifs_create_get_file_info: | |||
| 356 | cifs_create_set_dentry: | 356 | cifs_create_set_dentry: |
| 357 | if (rc != 0) { | 357 | if (rc != 0) { |
| 358 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 358 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
| 359 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
| 359 | goto out; | 360 | goto out; |
| 360 | } | 361 | } |
| 361 | d_drop(direntry); | 362 | d_drop(direntry); |
| 362 | d_add(direntry, newinode); | 363 | d_add(direntry, newinode); |
| 363 | 364 | ||
| 364 | /* ENOENT for create? How weird... */ | ||
| 365 | rc = -ENOENT; | ||
| 366 | if (!newinode) { | ||
| 367 | CIFSSMBClose(xid, tcon, *fileHandle); | ||
| 368 | goto out; | ||
| 369 | } | ||
| 370 | rc = 0; | ||
| 371 | |||
| 372 | out: | 365 | out: |
| 373 | kfree(buf); | 366 | kfree(buf); |
| 374 | kfree(full_path); | 367 | kfree(full_path); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7354877fa3bd..cb79c7edecb0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
| 124 | { | 124 | { |
| 125 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | 125 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
| 126 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 126 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 127 | unsigned long oldtime = cifs_i->time; | ||
| 128 | 127 | ||
| 129 | cifs_revalidate_cache(inode, fattr); | 128 | cifs_revalidate_cache(inode, fattr); |
| 130 | 129 | ||
| 130 | spin_lock(&inode->i_lock); | ||
| 131 | inode->i_atime = fattr->cf_atime; | 131 | inode->i_atime = fattr->cf_atime; |
| 132 | inode->i_mtime = fattr->cf_mtime; | 132 | inode->i_mtime = fattr->cf_mtime; |
| 133 | inode->i_ctime = fattr->cf_ctime; | 133 | inode->i_ctime = fattr->cf_ctime; |
| @@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
| 148 | else | 148 | else |
| 149 | cifs_i->time = jiffies; | 149 | cifs_i->time = jiffies; |
| 150 | 150 | ||
| 151 | cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode, | ||
| 152 | oldtime, cifs_i->time); | ||
| 153 | |||
| 154 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; | 151 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; |
| 155 | 152 | ||
| 156 | cifs_i->server_eof = fattr->cf_eof; | 153 | cifs_i->server_eof = fattr->cf_eof; |
| @@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
| 158 | * Can't safely change the file size here if the client is writing to | 155 | * Can't safely change the file size here if the client is writing to |
| 159 | * it due to potential races. | 156 | * it due to potential races. |
| 160 | */ | 157 | */ |
| 161 | spin_lock(&inode->i_lock); | ||
| 162 | if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { | 158 | if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { |
| 163 | i_size_write(inode, fattr->cf_eof); | 159 | i_size_write(inode, fattr->cf_eof); |
| 164 | 160 | ||
| @@ -859,12 +855,14 @@ struct inode *cifs_root_iget(struct super_block *sb) | |||
| 859 | 855 | ||
| 860 | if (rc && tcon->ipc) { | 856 | if (rc && tcon->ipc) { |
| 861 | cFYI(1, "ipc connection - fake read inode"); | 857 | cFYI(1, "ipc connection - fake read inode"); |
| 858 | spin_lock(&inode->i_lock); | ||
| 862 | inode->i_mode |= S_IFDIR; | 859 | inode->i_mode |= S_IFDIR; |
| 863 | set_nlink(inode, 2); | 860 | set_nlink(inode, 2); |
| 864 | inode->i_op = &cifs_ipc_inode_ops; | 861 | inode->i_op = &cifs_ipc_inode_ops; |
| 865 | inode->i_fop = &simple_dir_operations; | 862 | inode->i_fop = &simple_dir_operations; |
| 866 | inode->i_uid = cifs_sb->mnt_uid; | 863 | inode->i_uid = cifs_sb->mnt_uid; |
| 867 | inode->i_gid = cifs_sb->mnt_gid; | 864 | inode->i_gid = cifs_sb->mnt_gid; |
| 865 | spin_unlock(&inode->i_lock); | ||
| 868 | } else if (rc) { | 866 | } else if (rc) { |
| 869 | iget_failed(inode); | 867 | iget_failed(inode); |
| 870 | inode = ERR_PTR(rc); | 868 | inode = ERR_PTR(rc); |
| @@ -1110,6 +1108,15 @@ undo_setattr: | |||
| 1110 | goto out_close; | 1108 | goto out_close; |
| 1111 | } | 1109 | } |
| 1112 | 1110 | ||
| 1111 | /* copied from fs/nfs/dir.c with small changes */ | ||
| 1112 | static void | ||
| 1113 | cifs_drop_nlink(struct inode *inode) | ||
| 1114 | { | ||
| 1115 | spin_lock(&inode->i_lock); | ||
| 1116 | if (inode->i_nlink > 0) | ||
| 1117 | drop_nlink(inode); | ||
| 1118 | spin_unlock(&inode->i_lock); | ||
| 1119 | } | ||
| 1113 | 1120 | ||
| 1114 | /* | 1121 | /* |
| 1115 | * If dentry->d_inode is null (usually meaning the cached dentry | 1122 | * If dentry->d_inode is null (usually meaning the cached dentry |
| @@ -1166,13 +1173,13 @@ retry_std_delete: | |||
| 1166 | psx_del_no_retry: | 1173 | psx_del_no_retry: |
| 1167 | if (!rc) { | 1174 | if (!rc) { |
| 1168 | if (inode) | 1175 | if (inode) |
| 1169 | drop_nlink(inode); | 1176 | cifs_drop_nlink(inode); |
| 1170 | } else if (rc == -ENOENT) { | 1177 | } else if (rc == -ENOENT) { |
| 1171 | d_drop(dentry); | 1178 | d_drop(dentry); |
| 1172 | } else if (rc == -ETXTBSY) { | 1179 | } else if (rc == -ETXTBSY) { |
| 1173 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1180 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
| 1174 | if (rc == 0) | 1181 | if (rc == 0) |
| 1175 | drop_nlink(inode); | 1182 | cifs_drop_nlink(inode); |
| 1176 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { | 1183 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
| 1177 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1184 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
| 1178 | if (attrs == NULL) { | 1185 | if (attrs == NULL) { |
| @@ -1241,9 +1248,10 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode, | |||
| 1241 | * setting nlink not necessary except in cases where we failed to get it | 1248 | * setting nlink not necessary except in cases where we failed to get it |
| 1242 | * from the server or was set bogus | 1249 | * from the server or was set bogus |
| 1243 | */ | 1250 | */ |
| 1251 | spin_lock(&dentry->d_inode->i_lock); | ||
| 1244 | if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) | 1252 | if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) |
| 1245 | set_nlink(dentry->d_inode, 2); | 1253 | set_nlink(dentry->d_inode, 2); |
| 1246 | 1254 | spin_unlock(&dentry->d_inode->i_lock); | |
| 1247 | mode &= ~current_umask(); | 1255 | mode &= ~current_umask(); |
| 1248 | /* must turn on setgid bit if parent dir has it */ | 1256 | /* must turn on setgid bit if parent dir has it */ |
| 1249 | if (inode->i_mode & S_ISGID) | 1257 | if (inode->i_mode & S_ISGID) |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 09e4b3ae4564..e6ce3b112875 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -433,7 +433,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, | |||
| 433 | if (old_file->d_inode) { | 433 | if (old_file->d_inode) { |
| 434 | cifsInode = CIFS_I(old_file->d_inode); | 434 | cifsInode = CIFS_I(old_file->d_inode); |
| 435 | if (rc == 0) { | 435 | if (rc == 0) { |
| 436 | spin_lock(&old_file->d_inode->i_lock); | ||
| 436 | inc_nlink(old_file->d_inode); | 437 | inc_nlink(old_file->d_inode); |
| 438 | spin_unlock(&old_file->d_inode->i_lock); | ||
| 437 | /* BB should we make this contingent on superblock flag NOATIME? */ | 439 | /* BB should we make this contingent on superblock flag NOATIME? */ |
| 438 | /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ | 440 | /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ |
| 439 | /* parent dir timestamps will update from srv | 441 | /* parent dir timestamps will update from srv |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index a4ff5d547554..e4d3b9964167 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
| @@ -52,7 +52,8 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) | |||
| 52 | cERROR(1, "Bad protocol string signature header %x", | 52 | cERROR(1, "Bad protocol string signature header %x", |
| 53 | *(unsigned int *) hdr->ProtocolId); | 53 | *(unsigned int *) hdr->ProtocolId); |
| 54 | if (mid != hdr->MessageId) | 54 | if (mid != hdr->MessageId) |
| 55 | cERROR(1, "Mids do not match"); | 55 | cERROR(1, "Mids do not match: %llu and %llu", mid, |
| 56 | hdr->MessageId); | ||
| 56 | } | 57 | } |
| 57 | cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId); | 58 | cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId); |
| 58 | return 1; | 59 | return 1; |
| @@ -107,7 +108,7 @@ smb2_check_message(char *buf, unsigned int length) | |||
| 107 | * ie Validate the wct via smb2_struct_sizes table above | 108 | * ie Validate the wct via smb2_struct_sizes table above |
| 108 | */ | 109 | */ |
| 109 | 110 | ||
| 110 | if (length < 2 + sizeof(struct smb2_hdr)) { | 111 | if (length < sizeof(struct smb2_pdu)) { |
| 111 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { | 112 | if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { |
| 112 | pdu->StructureSize2 = 0; | 113 | pdu->StructureSize2 = 0; |
| 113 | /* | 114 | /* |
| @@ -121,15 +122,15 @@ smb2_check_message(char *buf, unsigned int length) | |||
| 121 | return 1; | 122 | return 1; |
| 122 | } | 123 | } |
| 123 | if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) { | 124 | if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) { |
| 124 | cERROR(1, "SMB length greater than maximum, mid=%lld", mid); | 125 | cERROR(1, "SMB length greater than maximum, mid=%llu", mid); |
| 125 | return 1; | 126 | return 1; |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | if (check_smb2_hdr(hdr, mid)) | 129 | if (check_smb2_hdr(hdr, mid)) |
| 129 | return 1; | 130 | return 1; |
| 130 | 131 | ||
| 131 | if (hdr->StructureSize != SMB2_HEADER_SIZE) { | 132 | if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { |
| 132 | cERROR(1, "Illegal structure size %d", | 133 | cERROR(1, "Illegal structure size %u", |
| 133 | le16_to_cpu(hdr->StructureSize)); | 134 | le16_to_cpu(hdr->StructureSize)); |
| 134 | return 1; | 135 | return 1; |
| 135 | } | 136 | } |
| @@ -161,8 +162,9 @@ smb2_check_message(char *buf, unsigned int length) | |||
| 161 | if (4 + len != clc_len) { | 162 | if (4 + len != clc_len) { |
| 162 | cFYI(1, "Calculated size %u length %u mismatch mid %llu", | 163 | cFYI(1, "Calculated size %u length %u mismatch mid %llu", |
| 163 | clc_len, 4 + len, mid); | 164 | clc_len, 4 + len, mid); |
| 164 | if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */ | 165 | /* server can return one byte more */ |
| 165 | return 0; /* BB workaround Samba 3 bug SessSetup rsp */ | 166 | if (clc_len == 4 + len + 1) |
| 167 | return 0; | ||
| 166 | return 1; | 168 | return 1; |
| 167 | } | 169 | } |
| 168 | return 0; | 170 | return 0; |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f37a1b41b402..c5fbfac5d576 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
| @@ -87,10 +87,6 @@ | |||
| 87 | 87 | ||
| 88 | #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe) | 88 | #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe) |
| 89 | 89 | ||
| 90 | #define SMB2_HEADER_SIZE __constant_le16_to_cpu(64) | ||
| 91 | |||
| 92 | #define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9) | ||
| 93 | |||
| 94 | /* | 90 | /* |
| 95 | * SMB2 Header Definition | 91 | * SMB2 Header Definition |
| 96 | * | 92 | * |
| @@ -99,6 +95,9 @@ | |||
| 99 | * "PDU" : "Protocol Data Unit" (ie a network "frame") | 95 | * "PDU" : "Protocol Data Unit" (ie a network "frame") |
| 100 | * | 96 | * |
| 101 | */ | 97 | */ |
| 98 | |||
| 99 | #define SMB2_HEADER_STRUCTURE_SIZE __constant_le16_to_cpu(64) | ||
| 100 | |||
| 102 | struct smb2_hdr { | 101 | struct smb2_hdr { |
| 103 | __be32 smb2_buf_length; /* big endian on wire */ | 102 | __be32 smb2_buf_length; /* big endian on wire */ |
| 104 | /* length is only two or three bytes - with | 103 | /* length is only two or three bytes - with |
| @@ -140,6 +139,9 @@ struct smb2_pdu { | |||
| 140 | * command code name for the struct. Note that structures must be packed. | 139 | * command code name for the struct. Note that structures must be packed. |
| 141 | * | 140 | * |
| 142 | */ | 141 | */ |
| 142 | |||
| 143 | #define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9) | ||
| 144 | |||
| 143 | struct smb2_err_rsp { | 145 | struct smb2_err_rsp { |
| 144 | struct smb2_hdr hdr; | 146 | struct smb2_hdr hdr; |
| 145 | __le16 StructureSize; | 147 | __le16 StructureSize; |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 83867ef348df..d9b639b95fa8 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -503,13 +503,16 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |||
| 503 | /* convert the length into a more usable form */ | 503 | /* convert the length into a more usable form */ |
| 504 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 504 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
| 505 | struct kvec iov; | 505 | struct kvec iov; |
| 506 | int rc = 0; | ||
| 506 | 507 | ||
| 507 | iov.iov_base = mid->resp_buf; | 508 | iov.iov_base = mid->resp_buf; |
| 508 | iov.iov_len = len; | 509 | iov.iov_len = len; |
| 509 | /* FIXME: add code to kill session */ | 510 | /* FIXME: add code to kill session */ |
| 510 | if (cifs_verify_signature(&iov, 1, server, | 511 | rc = cifs_verify_signature(&iov, 1, server, |
| 511 | mid->sequence_number + 1) != 0) | 512 | mid->sequence_number + 1); |
| 512 | cERROR(1, "Unexpected SMB signature"); | 513 | if (rc) |
| 514 | cERROR(1, "SMB signature verification returned error = " | ||
| 515 | "%d", rc); | ||
| 513 | } | 516 | } |
| 514 | 517 | ||
| 515 | /* BB special case reconnect tid and uid here? */ | 518 | /* BB special case reconnect tid and uid here? */ |
