aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-22 22:11:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-22 22:11:48 -0400
commit69c902f597c4bec92013a526268620fb6255c24a (patch)
tree4c7311d5befeaaa6a29fb2a9026eb9634be9d91e
parentb03fcfaef3538390cfb5e8d268fcdc5c828af1c7 (diff)
parent1013e760d10e614dc10b5624ce9fc41563ba2e65 (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.c9
-rw-r--r--fs/cifs/cifsfs.c4
-rw-r--r--fs/cifs/connect.c8
-rw-r--r--fs/cifs/file.c19
-rw-r--r--fs/cifs/inode.c15
-rw-r--r--fs/cifs/smb2pdu.c26
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;
1179out: 1189out:
1180 kfree(sess_data); 1190 kfree(sess_data);