Commit 69c902f5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '4.14-smb3-fixes-from-recent-test-events-for-stable' of...

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
parents b03fcfae 1013e760
...@@ -160,8 +160,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -160,8 +160,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
if ((ses->serverDomain == NULL) || if ((ses->serverDomain == NULL) ||
(ses->serverOS == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) { (ses->serverNOS == NULL)) {
seq_printf(m, "\n%d) entry for %s not fully " seq_printf(m, "\n%d) Name: %s Uses: %d Capability: 0x%x\tSession Status: %d\t",
"displayed\n\t", i, ses->serverName); i, ses->serverName, ses->ses_count,
ses->capabilities, ses->status);
if (ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
seq_printf(m, "Guest\t");
else if (ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
seq_printf(m, "Anonymous\t");
} else { } else {
seq_printf(m, seq_printf(m,
"\n%d) Name: %s Domain: %s Uses: %d OS:" "\n%d) Name: %s Domain: %s Uses: %d OS:"
......
...@@ -461,6 +461,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -461,6 +461,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",nocase"); seq_puts(s, ",nocase");
if (tcon->retry) if (tcon->retry)
seq_puts(s, ",hard"); seq_puts(s, ",hard");
else
seq_puts(s, ",soft");
if (tcon->use_persistent) if (tcon->use_persistent)
seq_puts(s, ",persistenthandles"); seq_puts(s, ",persistenthandles");
else if (tcon->use_resilient) else if (tcon->use_resilient)
...@@ -1447,7 +1449,7 @@ exit_cifs(void) ...@@ -1447,7 +1449,7 @@ exit_cifs(void)
exit_cifs_idmap(); exit_cifs_idmap();
#endif #endif
#ifdef CONFIG_CIFS_UPCALL #ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type); exit_cifs_spnego();
#endif #endif
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
cifs_destroy_mids(); cifs_destroy_mids();
......
...@@ -4154,6 +4154,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, ...@@ -4154,6 +4154,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
server->sec_mode, server->capabilities, server->timeAdj); server->sec_mode, server->capabilities, server->timeAdj);
if (ses->auth_key.response) {
cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
ses->auth_key.response);
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
ses->auth_key.len = 0;
}
if (server->ops->sess_setup) if (server->ops->sess_setup)
rc = server->ops->sess_setup(xid, ses, nls_info); rc = server->ops->sess_setup(xid, ses, nls_info);
......
...@@ -224,6 +224,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, ...@@ -224,6 +224,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
if (f_flags & O_SYNC)
create_options |= CREATE_WRITE_THROUGH;
if (f_flags & O_DIRECT)
create_options |= CREATE_NO_BUFFER;
oparms.tcon = tcon; oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb; oparms.cifs_sb = cifs_sb;
oparms.desired_access = desired_access; oparms.desired_access = desired_access;
...@@ -1102,8 +1109,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) ...@@ -1102,8 +1109,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
unsigned int num, max_num, max_buf; unsigned int num, max_num, max_buf;
LOCKING_ANDX_RANGE *buf, *cur; LOCKING_ANDX_RANGE *buf, *cur;
int types[] = {LOCKING_ANDX_LARGE_FILES, static const int types[] = {
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; LOCKING_ANDX_LARGE_FILES,
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES
};
int i; int i;
xid = get_xid(); xid = get_xid();
...@@ -1434,8 +1443,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, ...@@ -1434,8 +1443,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
unsigned int xid) unsigned int xid)
{ {
int rc = 0, stored_rc; int rc = 0, stored_rc;
int types[] = {LOCKING_ANDX_LARGE_FILES, static const int types[] = {
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; LOCKING_ANDX_LARGE_FILES,
LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES
};
unsigned int i; unsigned int i;
unsigned int max_num, num, max_buf; unsigned int max_num, num, max_buf;
LOCKING_ANDX_RANGE *buf, *cur; LOCKING_ANDX_RANGE *buf, *cur;
......
...@@ -234,6 +234,8 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, ...@@ -234,6 +234,8 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
/* old POSIX extensions don't get create time */
fattr->cf_mode = le64_to_cpu(info->Permissions); fattr->cf_mode = le64_to_cpu(info->Permissions);
/* /*
...@@ -2024,6 +2026,19 @@ int cifs_getattr(const struct path *path, struct kstat *stat, ...@@ -2024,6 +2026,19 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
stat->blksize = CIFS_MAX_MSGSIZE; stat->blksize = CIFS_MAX_MSGSIZE;
stat->ino = CIFS_I(inode)->uniqueid; stat->ino = CIFS_I(inode)->uniqueid;
/* old CIFS Unix Extensions doesn't return create time */
if (CIFS_I(inode)->createtime) {
stat->result_mask |= STATX_BTIME;
stat->btime =
cifs_NTtimeToUnix(cpu_to_le64(CIFS_I(inode)->createtime));
}
stat->attributes_mask |= (STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED);
if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED)
stat->attributes |= STATX_ATTR_COMPRESSED;
if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_ENCRYPTED)
stat->attributes |= STATX_ATTR_ENCRYPTED;
/* /*
* If on a multiuser mount without unix extensions or cifsacl being * If on a multiuser mount without unix extensions or cifsacl being
* enabled, and the admin hasn't overridden them, set the ownership * enabled, and the admin hasn't overridden them, set the ownership
......
...@@ -439,7 +439,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req) ...@@ -439,7 +439,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req)
build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt);
req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT); req->NegotiateContextOffset = cpu_to_le32(OFFSET_OF_NEG_CONTEXT);
req->NegotiateContextCount = cpu_to_le16(2); req->NegotiateContextCount = cpu_to_le16(2);
inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context) + 2 inc_rfc1001_len(req, 4 + sizeof(struct smb2_preauth_neg_context)
+ sizeof(struct smb2_encryption_neg_context)); /* calculate hash */ + sizeof(struct smb2_encryption_neg_context)); /* calculate hash */
} }
#else #else
...@@ -570,10 +570,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) ...@@ -570,10 +570,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
/* ops set to 3.0 by default for default so update */ /* ops set to 3.0 by default for default so update */
ses->server->ops = &smb21_operations; ses->server->ops = &smb21_operations;
} }
} else if (rsp->DialectRevision != ses->server->vals->protocol_id) { } else if (le16_to_cpu(rsp->DialectRevision) !=
ses->server->vals->protocol_id) {
/* if requested single dialect ensure returned dialect matched */ /* if requested single dialect ensure returned dialect matched */
cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n", cifs_dbg(VFS, "Illegal 0x%x dialect returned: not requested\n",
cpu_to_le16(rsp->DialectRevision)); le16_to_cpu(rsp->DialectRevision));
return -EIO; return -EIO;
} }
...@@ -655,14 +656,21 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -655,14 +656,21 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
/* /*
* validation ioctl must be signed, so no point sending this if we * validation ioctl must be signed, so no point sending this if we
* can not sign it. We could eventually change this to selectively * can not sign it (ie are not known user). Even if signing is not
* required (enabled but not negotiated), in those cases we selectively
* sign just this, the first and only signed request on a connection. * sign just this, the first and only signed request on a connection.
* This is good enough for now since a user who wants better security * Having validation of negotiate info helps reduce attack vectors.
* would also enable signing on the mount. Having validation of
* negotiate info for signed connections helps reduce attack vectors
*/ */
if (tcon->ses->server->sign == false) if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
return 0; /* validation requires signing */
if (tcon->ses->user_name == NULL) {
cifs_dbg(FYI, "Can't validate negotiate: null user mount\n");
return 0; /* validation requires signing */ return 0; /* validation requires signing */
}
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
vneg_inbuf.Capabilities = vneg_inbuf.Capabilities =
cpu_to_le32(tcon->ses->server->vals->req_capabilities); cpu_to_le32(tcon->ses->server->vals->req_capabilities);
...@@ -1175,6 +1183,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -1175,6 +1183,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
while (sess_data->func) while (sess_data->func)
sess_data->func(sess_data); sess_data->func(sess_data);
if ((ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST) && (ses->sign))
cifs_dbg(VFS, "signing requested but authenticated as guest\n");
rc = sess_data->result; rc = sess_data->result;
out: out:
kfree(sess_data); kfree(sess_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment