diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 22:11:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-22 22:11:48 -0400 |
commit | 69c902f597c4bec92013a526268620fb6255c24a (patch) | |
tree | 4c7311d5befeaaa6a29fb2a9026eb9634be9d91e | |
parent | b03fcfaef3538390cfb5e8d268fcdc5c828af1c7 (diff) | |
parent | 1013e760d10e614dc10b5624ce9fc41563ba2e65 (diff) |
Merge tag '4.14-smb3-fixes-from-recent-test-events-for-stable' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French:
"Various SMB3 fixes for stable and security improvements from the
recently completed SMB3/Samba test events
* tag '4.14-smb3-fixes-from-recent-test-events-for-stable' of git://git.samba.org/sfrench/cifs-2.6:
SMB3: Don't ignore O_SYNC/O_DSYNC and O_DIRECT flags
SMB3: handle new statx fields
SMB: Validate negotiate (to protect against downgrade) even if signing off
cifs: release auth_key.response for reconnect.
cifs: release cifs root_cred after exit_cifs
CIFS: make arrays static const, reduces object code size
[SMB3] Update session and share information displayed for debugging SMB2/SMB3
cifs: show 'soft' in the mount options for hard mounts
SMB3: Warn user if trying to sign connection that authenticated as guest
SMB3: Fix endian warning
Fix SMB3.1.1 guest authentication to Samba
-rw-r--r-- | fs/cifs/cifs_debug.c | 9 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 8 | ||||
-rw-r--r-- | fs/cifs/file.c | 19 | ||||
-rw-r--r-- | fs/cifs/inode.c | 15 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 26 |
6 files changed, 66 insertions, 15 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 9727e1dcacd5..cbb9534b89b4 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -160,8 +160,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
160 | if ((ses->serverDomain == NULL) || | 160 | if ((ses->serverDomain == NULL) || |
161 | (ses->serverOS == NULL) || | 161 | (ses->serverOS == NULL) || |
162 | (ses->serverNOS == NULL)) { | 162 | (ses->serverNOS == NULL)) { |
163 | seq_printf(m, "\n%d) entry for %s not fully " | 163 | seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d\t", |
164 | "displayed\n\t", i, ses->serverName); | 164 | i, ses->serverName, ses->ses_count, |
165 | ses->capabilities, ses->status); | ||
166 | if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) | ||
167 | seq_printf(m, "Guest\t"); | ||
168 | else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) | ||
169 | seq_printf(m, "Anonymous\t"); | ||
165 | } else { | 170 | } else { |
166 | seq_printf(m, | 171 | seq_printf(m, |
167 | "\n%d) Name: %s Domain: %s Uses: %d OS:" | 172 | "\n%d) Name: %s Domain: %s Uses: %d OS:" |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 180b3356ff86..8c8b75d33f31 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -461,6 +461,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
461 | seq_puts(s, ",nocase"); | 461 | seq_puts(s, ",nocase"); |
462 | if (tcon->retry) | 462 | if (tcon->retry) |
463 | seq_puts(s, ",hard"); | 463 | seq_puts(s, ",hard"); |
464 | else | ||
465 | seq_puts(s, ",soft"); | ||
464 | if (tcon->use_persistent) | 466 | if (tcon->use_persistent) |
465 | seq_puts(s, ",persistenthandles"); | 467 | seq_puts(s, ",persistenthandles"); |
466 | else if (tcon->use_resilient) | 468 | else if (tcon->use_resilient) |
@@ -1447,7 +1449,7 @@ exit_cifs(void) | |||
1447 | exit_cifs_idmap(); | 1449 | exit_cifs_idmap(); |
1448 | #endif | 1450 | #endif |
1449 | #ifdef CONFIG_CIFS_UPCALL | 1451 | #ifdef CONFIG_CIFS_UPCALL |
1450 | unregister_key_type(&cifs_spnego_key_type); | 1452 | exit_cifs_spnego(); |
1451 | #endif | 1453 | #endif |
1452 | cifs_destroy_request_bufs(); | 1454 | cifs_destroy_request_bufs(); |
1453 | cifs_destroy_mids(); | 1455 | cifs_destroy_mids(); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8d38b22afb2b..0bfc2280436d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -4154,6 +4154,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, | |||
4154 | cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", | 4154 | cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", |
4155 | server->sec_mode, server->capabilities, server->timeAdj); | 4155 | server->sec_mode, server->capabilities, server->timeAdj); |
4156 | 4156 | ||
4157 | if (ses->auth_key.response) { | ||
4158 | cifs_dbg(VFS, "Free previous auth_key.response = %p\n", | ||
4159 | ses->auth_key.response); | ||
4160 | kfree(ses->auth_key.response); | ||
4161 | ses->auth_key.response = NULL; | ||
4162 | ses->auth_key.len = 0; | ||
4163 | } | ||
4164 | |||
4157 | if (server->ops->sess_setup) | 4165 | if (server->ops->sess_setup) |
4158 | rc = server->ops->sess_setup(xid, ses, nls_info); | 4166 | rc = server->ops->sess_setup(xid, ses, nls_info); |
4159 | 4167 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0786f19d288f..92fdf9c35de2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -224,6 +224,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | |||
224 | if (backup_cred(cifs_sb)) | 224 | if (backup_cred(cifs_sb)) |
225 | create_options |= CREATE_OPEN_BACKUP_INTENT; | 225 | create_options |= CREATE_OPEN_BACKUP_INTENT; |
226 | 226 | ||
227 | /* O_SYNC also has bit for O_DSYNC so following check picks up either */ | ||
228 | if (f_flags & O_SYNC) | ||
229 | create_options |= CREATE_WRITE_THROUGH; | ||
230 | |||
231 | if (f_flags & O_DIRECT) | ||
232 | create_options |= CREATE_NO_BUFFER; | ||
233 | |||
227 | oparms.tcon = tcon; | 234 | oparms.tcon = tcon; |
228 | oparms.cifs_sb = cifs_sb; | 235 | oparms.cifs_sb = cifs_sb; |
229 | oparms.desired_access = desired_access; | 236 | oparms.desired_access = desired_access; |
@@ -1102,8 +1109,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
1102 | struct cifs_tcon *tcon; | 1109 | struct cifs_tcon *tcon; |
1103 | unsigned int num, max_num, max_buf; | 1110 | unsigned int num, max_num, max_buf; |
1104 | LOCKING_ANDX_RANGE *buf, *cur; | 1111 | LOCKING_ANDX_RANGE *buf, *cur; |
1105 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 1112 | static const int types[] = { |
1106 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; | 1113 | LOCKING_ANDX_LARGE_FILES, |
1114 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES | ||
1115 | }; | ||
1107 | int i; | 1116 | int i; |
1108 | 1117 | ||
1109 | xid = get_xid(); | 1118 | xid = get_xid(); |
@@ -1434,8 +1443,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, | |||
1434 | unsigned int xid) | 1443 | unsigned int xid) |
1435 | { | 1444 | { |
1436 | int rc = 0, stored_rc; | 1445 | int rc = 0, stored_rc; |
1437 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 1446 | static const int types[] = { |
1438 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; | 1447 | LOCKING_ANDX_LARGE_FILES, |
1448 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES | ||
1449 | }; | ||
1439 | unsigned int i; | 1450 | unsigned int i; |
1440 | unsigned int max_num, num, max_buf; | 1451 | unsigned int max_num, num, max_buf; |
1441 | LOCKING_ANDX_RANGE *buf, *cur; | 1452 | LOCKING_ANDX_RANGE *buf, *cur; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a8693632235f..7c732cb44164 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -234,6 +234,8 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, | |||
234 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 234 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
235 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); | 235 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); |
236 | fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); | 236 | fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); |
237 | /* old POSIX extensions don't get create time */ | ||
238 | |||
237 | fattr->cf_mode = le64_to_cpu(info->Permissions); | 239 | fattr->cf_mode = le64_to_cpu(info->Permissions); |
238 | 240 | ||
239 | /* | 241 | /* |
@@ -2024,6 +2026,19 @@ int cifs_getattr(const struct path *path, struct kstat *stat, | |||
2024 | stat->blksize = CIFS_MAX_MSGSIZE; | 2026 | stat->blksize = CIFS_MAX_MSGSIZE; |
2025 | stat->ino = CIFS_I(inode)->uniqueid; | 2027 | stat->ino = CIFS_I(inode)->uniqueid; |
2026 | 2028 | ||
2029 | /* old CIFS Unix Extensions doesn't return create time */ | ||
2030 | if (CIFS_I(inode)->createtime) { | ||
2031 | stat->result_mask |= STATX_BTIME; | ||
2032 | stat->btime = | ||
2033 | cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime)); | ||
2034 | } | ||
2035 | |||
2036 | stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED); | ||
2037 | if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED) | ||
2038 | stat->attributes |= STATX_ATTR_COMPRESSED; | ||
2039 | if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED) | ||
2040 | stat->attributes |= STATX_ATTR_ENCRYPTED; | ||
2041 | |||
2027 | /* | 2042 | /* |
2028 | * If on a multiuser mount without unix extensions or cifsacl being | 2043 | * If on a multiuser mount without unix extensions or cifsacl being |
2029 | * enabled, and the admin hasn't overridden them, set the ownership | 2044 | * enabled, and the admin hasn't overridden them, set the ownership |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 5c16591a128e..6f0e6343c15e 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -439,7 +439,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req) | |||
439 | build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); | 439 | build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); |
440 | req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); | 440 | req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); |
441 | req->NegotiateContextCount = cpu_to_le16(2); | 441 | req->NegotiateContextCount = cpu_to_le16(2); |
442 | inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) + 2 | 442 | inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) |
443 | + sizeof(struct smb2_encryption_neg_context)); /* calculate hash */ | 443 | + sizeof(struct smb2_encryption_neg_context)); /* calculate hash */ |
444 | } | 444 | } |
445 | #else | 445 | #else |
@@ -570,10 +570,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) | |||
570 | /* ops set to 3.0 by default for default so update */ | 570 | /* ops set to 3.0 by default for default so update */ |
571 | ses->server->ops = &smb21_operations; | 571 | ses->server->ops = &smb21_operations; |
572 | } | 572 | } |
573 | } else if (rsp->DialectRevision != ses->server->vals->protocol_id) { | 573 | } else if (le16_to_cpu(rsp->DialectRevision) != |
574 | ses->server->vals->protocol_id) { | ||
574 | /* if requested single dialect ensure returned dialect matched */ | 575 | /* if requested single dialect ensure returned dialect matched */ |
575 | cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n", | 576 | cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n", |
576 | cpu_to_le16(rsp->DialectRevision)); | 577 | le16_to_cpu(rsp->DialectRevision)); |
577 | return -EIO; | 578 | return -EIO; |
578 | } | 579 | } |
579 | 580 | ||
@@ -655,15 +656,22 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | |||
655 | 656 | ||
656 | /* | 657 | /* |
657 | * validation ioctl must be signed, so no point sending this if we | 658 | * validation ioctl must be signed, so no point sending this if we |
658 | * can not sign it. We could eventually change this to selectively | 659 | * can not sign it (ie are not known user). Even if signing is not |
660 | * required (enabled but not negotiated), in those cases we selectively | ||
659 | * sign just this, the first and only signed request on a connection. | 661 | * sign just this, the first and only signed request on a connection. |
660 | * This is good enough for now since a user who wants better security | 662 | * Having validation of negotiate info helps reduce attack vectors. |
661 | * would also enable signing on the mount. Having validation of | ||
662 | * negotiate info for signed connections helps reduce attack vectors | ||
663 | */ | 663 | */ |
664 | if (tcon->ses->server->sign == false) | 664 | if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) |
665 | return 0; /* validation requires signing */ | 665 | return 0; /* validation requires signing */ |
666 | 666 | ||
667 | if (tcon->ses->user_name == NULL) { | ||
668 | cifs_dbg(FYI, "Can't validate negotiate: null user mount\n"); | ||
669 | return 0; /* validation requires signing */ | ||
670 | } | ||
671 | |||
672 | if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) | ||
673 | cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n"); | ||
674 | |||
667 | vneg_inbuf.Capabilities = | 675 | vneg_inbuf.Capabilities = |
668 | cpu_to_le32(tcon->ses->server->vals->req_capabilities); | 676 | cpu_to_le32(tcon->ses->server->vals->req_capabilities); |
669 | memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid, | 677 | memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid, |
@@ -1175,6 +1183,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | |||
1175 | while (sess_data->func) | 1183 | while (sess_data->func) |
1176 | sess_data->func(sess_data); | 1184 | sess_data->func(sess_data); |
1177 | 1185 | ||
1186 | if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign)) | ||
1187 | cifs_dbg(VFS, "signing requested but authenticated as guest\n"); | ||
1178 | rc = sess_data->result; | 1188 | rc = sess_data->result; |
1179 | out: | 1189 | out: |
1180 | kfree(sess_data); | 1190 | kfree(sess_data); |