From f980d055a0f858d73d9467bb0b570721bbfcdfb8 Mon Sep 17 00:00:00 2001 From: Len Baker Date: Tue, 17 Aug 2021 12:27:09 +0200 Subject: [PATCH 01/11] CIFS: Fix a potencially linear read overflow strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated. Also, the strnlen() call does not avoid the read overflow in the strlcpy function when a not NUL-terminated string is passed. So, replace this block by a call to kstrndup() that avoids this type of overflow and does the same. Fixes: 066ce6899484d ("cifs: rename cifs_strlcpy_to_host and make it use new functions") Signed-off-by: Len Baker Reviewed-by: Paulo Alcantara (SUSE) Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_unicode.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 9bd03a231032..171ad8b42107 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -358,14 +358,9 @@ cifs_strndup_from_utf16(const char *src, const int maxlen, if (!dst) return NULL; cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage, - NO_MAP_UNI_RSVD); + NO_MAP_UNI_RSVD); } else { - len = strnlen(src, maxlen); - len++; - dst = kmalloc(len, GFP_KERNEL); - if (!dst) - return NULL; - strlcpy(dst, src, len); + dst = kstrndup(src, maxlen, GFP_KERNEL); } return dst; From d72c74197b70bc3c95152f351a568007bffa3e11 Mon Sep 17 00:00:00 2001 From: Ding Hui Date: Tue, 17 Aug 2021 22:55:10 +0800 Subject: [PATCH 02/11] cifs: fix wrong release in sess_alloc_buffer() failed path smb_buf is allocated by small_smb_init_no_tc(), and buf type is CIFS_SMALL_BUFFER, so we should use cifs_small_buf_release() to release it in failed path. Signed-off-by: Ding Hui Reviewed-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- fs/cifs/sess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c5785fd3f52e..606fd7d6cb71 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -877,7 +877,7 @@ sess_alloc_buffer(struct sess_data *sess_data, int wct) return 0; out_free_smb_buf: - kfree(smb_buf); + cifs_small_buf_release(smb_buf); sess_data->iov[0].iov_base = NULL; sess_data->iov[0].iov_len = 0; sess_data->buf0_type = CIFS_NO_BUFFER; From 7321be2663da5922343cc121f1ff04924cee2e76 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 23 Aug 2021 13:52:12 -0500 Subject: [PATCH 03/11] smb3: fix posix extensions mount option We were incorrectly initializing the posix extensions in the conversion to the new mount API. CC: # 5.11+ Reported-by: Christian Brauner Acked-by: Christian Brauner Suggested-by: Namjae Jeon Signed-off-by: Steve French --- fs/cifs/fs_context.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index eed59bc1d913..727c8835b222 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -1266,10 +1266,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ctx->posix_paths = 1; break; case Opt_unix: - if (result.negated) + if (result.negated) { + if (ctx->linux_ext == 1) + pr_warn_once("conflicting posix mount options specified\n"); ctx->linux_ext = 0; - else ctx->no_linux_ext = 1; + } else { + if (ctx->no_linux_ext == 1) + pr_warn_once("conflicting posix mount options specified\n"); + ctx->linux_ext = 1; + ctx->no_linux_ext = 0; + } break; case Opt_nocase: ctx->nocase = 1; From 3d2b50e0e7682b2453ccfac775ad7c2c1d5ceb45 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 Aug 2021 18:10:36 -0500 Subject: [PATCH 04/11] oid_registry: Add OIDs for missing Spnego auth mechanisms to Macs In testing mounts to Macs, noticed that the OIDS for some GSSAPI/SPNEGO auth mechanisms sent by the server were not recognized and were missing from the header. Reviewed-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- include/linux/oid_registry.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 3d8db1f6a5db..0f4a8903922a 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -70,6 +70,9 @@ enum OID { OID_spnego, /* 1.3.6.1.5.5.2 */ + OID_IAKerb, /* 1.3.6.1.5.2.5 */ + OID_PKU2U, /* 1.3.5.1.5.2.7 */ + OID_Scram, /* 1.3.6.1.5.5.14 */ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ OID_id_ansip384r1, /* 1.3.132.0.34 */ @@ -104,6 +107,10 @@ enum OID { OID_authorityKeyIdentifier, /* 2.5.29.35 */ OID_extKeyUsage, /* 2.5.29.37 */ + /* Heimdal mechanisms */ + OID_NetlogonMechanism, /* 1.2.752.43.14.2 */ + OID_appleLocalKdcSupported, /* 1.2.752.43.14.3 */ + /* EC-RDSA */ OID_gostCPSignA, /* 1.2.643.2.2.35.1 */ OID_gostCPSignB, /* 1.2.643.2.2.35.2 */ From 18d04062f83b3eedb64e9f64ede26ee83ae7f152 Mon Sep 17 00:00:00 2001 From: Shyam Prasad N Date: Tue, 10 Aug 2021 10:22:28 +0000 Subject: [PATCH 05/11] cifs: enable fscache usage even for files opened as rw So far, the fscache implementation we had supports only a small set of use cases. Particularly for files opened with O_RDONLY. This commit enables it even for rw based file opens. It also enables the reuse of cached data in case of mount option (cache=singleclient) where it is guaranteed that this is the only client (and server) which operates on the files. There's also a single line change in fscache.c to get around a bug seen in fscache. Signed-off-by: Shyam Prasad N Acked-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 1 - fs/cifs/cifssmb.c | 1 + fs/cifs/file.c | 15 +++++++++++++-- fs/cifs/fscache.c | 41 +++++++++++++++++++++++++++++++++-------- fs/cifs/fscache.h | 23 +++++++++++++++++++++++ fs/cifs/inode.c | 6 ++++++ 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 64b71c4e2a9d..6e4fc4221418 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -399,7 +399,6 @@ cifs_evict_inode(struct inode *inode) { truncate_inode_pages_final(&inode->i_data); clear_inode(inode); - cifs_fscache_release_inode_cookie(inode); } static void diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 65d1a65bfc37..f207de803629 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2101,6 +2101,7 @@ cifs_writev_complete(struct work_struct *work) else if (wdata->result < 0) SetPageError(page); end_page_writeback(page); + cifs_readpage_to_fscache(inode, page); put_page(page); } if (wdata->result != -EAGAIN) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index bb98fbdd22a9..d0216472f1c6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -377,6 +377,8 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) struct cifsLockInfo *li, *tmp; struct super_block *sb = inode->i_sb; + cifs_fscache_release_inode_cookie(inode); + /* * Delete any outstanding lock records. We'll lose them when the file * is closed anyway. @@ -882,8 +884,10 @@ int cifs_close(struct inode *inode, struct file *file) if ((cinode->oplock == CIFS_CACHE_RHW_FLG) && cinode->lease_granted && dclose) { - if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) + if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) { inode->i_ctime = inode->i_mtime = current_time(inode); + cifs_fscache_update_inode_cookie(inode); + } spin_lock(&cinode->deferred_lock); cifs_add_deferred_close(cfile, dclose); if (cfile->deferred_close_scheduled && @@ -4170,6 +4174,10 @@ static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) { struct page *page = vmf->page; + struct file *file = vmf->vma->vm_file; + struct inode *inode = file_inode(file); + + cifs_fscache_wait_on_page_write(inode, page); lock_page(page); return VM_FAULT_LOCKED; @@ -4235,13 +4243,16 @@ cifs_readv_complete(struct work_struct *work) (rdata->result == -EAGAIN && got_bytes)) { flush_dcache_page(page); SetPageUptodate(page); - } + } else + SetPageError(page); unlock_page(page); if (rdata->result == 0 || (rdata->result == -EAGAIN && got_bytes)) cifs_readpage_to_fscache(rdata->mapping->host, page); + else + cifs_fscache_uncache_page(rdata->mapping->host, page); got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes); diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index dd625033cd6b..fab47fa7df74 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -176,29 +176,34 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); + /* fscache_relinquish_cookie does not seem to update auxdata */ + fscache_update_cookie(cifsi->fscache, &auxdata); fscache_relinquish_cookie(cifsi->fscache, &auxdata, false); cifsi->fscache = NULL; } } -static void cifs_fscache_disable_inode_cookie(struct inode *inode) +void cifs_fscache_update_inode_cookie(struct inode *inode) { + struct cifs_fscache_inode_auxdata auxdata; struct cifsInodeInfo *cifsi = CIFS_I(inode); if (cifsi->fscache) { + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.eof = cifsi->server_eof; + auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec; + auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec; + auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec; + auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; + cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); - fscache_uncache_all_inode_pages(cifsi->fscache, inode); - fscache_relinquish_cookie(cifsi->fscache, NULL, true); - cifsi->fscache = NULL; + fscache_update_cookie(cifsi->fscache, &auxdata); } } void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) { - if ((filp->f_flags & O_ACCMODE) != O_RDONLY) - cifs_fscache_disable_inode_cookie(inode); - else - cifs_fscache_enable_inode_cookie(inode); + cifs_fscache_enable_inode_cookie(inode); } void cifs_fscache_reset_inode_cookie(struct inode *inode) @@ -310,6 +315,8 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) struct cifsInodeInfo *cifsi = CIFS_I(inode); int ret; + WARN_ON(!cifsi->fscache); + cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n", __func__, cifsi->fscache, page, inode); ret = fscache_write_page(cifsi->fscache, page, @@ -334,3 +341,21 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) fscache_wait_on_page_write(cookie, page); fscache_uncache_page(cookie, page); } + +void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page) +{ + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct fscache_cookie *cookie = cifsi->fscache; + + cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie); + fscache_wait_on_page_write(cookie, page); +} + +void __cifs_fscache_uncache_page(struct inode *inode, struct page *page) +{ + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct fscache_cookie *cookie = cifsi->fscache; + + cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie); + fscache_uncache_page(cookie, page); +} diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 3d55cb2ef055..82e856b9cf89 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -55,10 +55,13 @@ extern void cifs_fscache_get_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_inode_cookie(struct inode *); +extern void cifs_fscache_update_inode_cookie(struct inode *inode); extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); extern void cifs_fscache_reset_inode_cookie(struct inode *); extern void __cifs_fscache_invalidate_page(struct page *, struct inode *); +extern void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page); +extern void __cifs_fscache_uncache_page(struct inode *inode, struct page *page); extern int cifs_fscache_release_page(struct page *page, gfp_t gfp); extern int __cifs_readpage_from_fscache(struct inode *, struct page *); extern int __cifs_readpages_from_fscache(struct inode *, @@ -76,6 +79,20 @@ static inline void cifs_fscache_invalidate_page(struct page *page, __cifs_fscache_invalidate_page(page, inode); } +static inline void cifs_fscache_wait_on_page_write(struct inode *inode, + struct page *page) +{ + if (PageFsCache(page)) + __cifs_fscache_wait_on_page_write(inode, page); +} + +static inline void cifs_fscache_uncache_page(struct inode *inode, + struct page *page) +{ + if (PageFsCache(page)) + __cifs_fscache_uncache_page(inode, page); +} + static inline int cifs_readpage_from_fscache(struct inode *inode, struct page *page) { @@ -123,6 +140,7 @@ static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} +static inline void cifs_fscache_update_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) {} static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {} @@ -133,6 +151,11 @@ static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) static inline void cifs_fscache_invalidate_page(struct page *page, struct inode *inode) {} +static inline void cifs_fscache_wait_on_page_write(struct inode *inode, + struct page *page) {} +static inline void cifs_fscache_uncache_page(struct inode *inode, + struct page *page) {} + static inline int cifs_readpage_from_fscache(struct inode *inode, struct page *page) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 65f8a70cece3..50c01cff4c84 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2297,6 +2297,7 @@ cifs_revalidate_mapping(struct inode *inode) { int rc; unsigned long *flags = &CIFS_I(inode)->flags; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); /* swapfiles are not supposed to be shared */ if (IS_SWAPFILE(inode)) @@ -2308,11 +2309,16 @@ cifs_revalidate_mapping(struct inode *inode) return rc; if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) { + /* for cache=singleclient, do not invalidate */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) + goto skip_invalidate; + rc = cifs_invalidate_mapping(inode); if (rc) set_bit(CIFS_INO_INVALID_MAPPING, flags); } +skip_invalidate: clear_bit_unlock(CIFS_INO_LOCK, flags); smp_mb__after_atomic(); wake_up_bit(flags, CIFS_INO_LOCK); From 76a3c92ec9e0668e4cd0e9ff1782eb68f61a179c Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 19 Aug 2021 20:34:58 +1000 Subject: [PATCH 06/11] cifs: remove support for NTLM and weaker authentication algorithms for SMB1. This removes the dependency to DES. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/Kconfig | 28 ----- fs/cifs/cifs_debug.c | 11 -- fs/cifs/cifs_swn.c | 2 - fs/cifs/cifsencrypt.c | 81 -------------- fs/cifs/cifsfs.c | 6 - fs/cifs/cifsglob.h | 32 +----- fs/cifs/cifspdu.h | 28 ----- fs/cifs/cifsproto.h | 10 -- fs/cifs/cifssmb.c | 106 +----------------- fs/cifs/connect.c | 32 ------ fs/cifs/fs_context.c | 14 --- fs/cifs/fs_context.h | 3 - fs/cifs/sess.c | 255 +----------------------------------------- fs/cifs/smbencrypt.c | 117 +------------------ 14 files changed, 5 insertions(+), 720 deletions(-) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7364950a9ef4..2e8b132efdbc 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -16,7 +16,6 @@ config CIFS select CRYPTO_GCM select CRYPTO_ECB select CRYPTO_AES - select CRYPTO_LIB_DES select KEYS select DNS_RESOLVER select ASN1 @@ -85,33 +84,6 @@ config CIFS_ALLOW_INSECURE_LEGACY If unsure, say Y. -config CIFS_WEAK_PW_HASH - bool "Support legacy servers which use weaker LANMAN security" - depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY - help - Modern CIFS servers including Samba and most Windows versions - (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) - security mechanisms. These hash the password more securely - than the mechanisms used in the older LANMAN version of the - SMB protocol but LANMAN based authentication is needed to - establish sessions with some old SMB servers. - - Enabling this option allows the cifs module to mount to older - LANMAN based servers such as OS/2 and Windows 95, but such - mounts may be less secure than mounts using NTLM or more recent - security mechanisms if you are on a public network. Unless you - have a need to access old SMB servers (and are on a private - network) you probably want to say N. Even if this support - is enabled in the kernel build, LANMAN authentication will not be - used automatically. At runtime LANMAN mounts are disabled but - can be set to required (or optional) either in - /proc/fs/cifs (see Documentation/admin-guide/cifs/usage.rst for - more detail) or via an option on the mount command. This support - is disabled by default in order to reduce the possibility of a - downgrade attack. - - If unsure, say N. - config CIFS_UPCALL bool "Kerberos/SPNEGO advanced session setup" depends on CIFS diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 8857ac7e7a14..51a824fc926a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -250,9 +250,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY seq_printf(m, ",ALLOW_INSECURE_LEGACY"); #endif -#ifdef CONFIG_CIFS_WEAK_PW_HASH - seq_printf(m, ",WEAK_PW_HASH"); -#endif #ifdef CONFIG_CIFS_POSIX seq_printf(m, ",CIFS_POSIX"); #endif @@ -929,14 +926,6 @@ cifs_security_flags_handle_must_flags(unsigned int *flags) *flags = CIFSSEC_MUST_NTLMSSP; else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) *flags = CIFSSEC_MUST_NTLMV2; - else if ((*flags & CIFSSEC_MUST_NTLM) == CIFSSEC_MUST_NTLM) - *flags = CIFSSEC_MUST_NTLM; - else if (CIFSSEC_MUST_LANMAN && - (*flags & CIFSSEC_MUST_LANMAN) == CIFSSEC_MUST_LANMAN) - *flags = CIFSSEC_MUST_LANMAN; - else if (CIFSSEC_MUST_PLNTXT && - (*flags & CIFSSEC_MUST_PLNTXT) == CIFSSEC_MUST_PLNTXT) - *flags = CIFSSEC_MUST_PLNTXT; *flags |= signflags; } diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 93b47818c6c2..12bde7bfda86 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -147,8 +147,6 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) goto nlmsg_fail; } break; - case LANMAN: - case NTLM: case NTLMv2: case RawNTLMSSP: ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index ecf15d845dbd..7680e0a9bea3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -250,87 +250,6 @@ int cifs_verify_signature(struct smb_rqst *rqst, } -/* first calculate 24 bytes ntlm response and then 16 byte session key */ -int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp) -{ - int rc = 0; - unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; - char temp_key[CIFS_SESS_KEY_SIZE]; - - if (!ses) - return -EINVAL; - - ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); - if (!ses->auth_key.response) - return -ENOMEM; - - ses->auth_key.len = temp_len; - - rc = SMBNTencrypt(ses->password, ses->server->cryptkey, - ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", - __func__, rc); - return rc; - } - - rc = E_md4hash(ses->password, temp_key, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - - rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); - if (rc) - cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", - __func__, rc); - - return rc; -} - -#ifdef CONFIG_CIFS_WEAK_PW_HASH -int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, - char *lnm_session_key) -{ - int i, len; - int rc; - char password_with_pad[CIFS_ENCPWD_SIZE] = {0}; - - if (password) { - for (len = 0; len < CIFS_ENCPWD_SIZE; len++) - if (!password[len]) - break; - - memcpy(password_with_pad, password, len); - } - - if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) { - memcpy(lnm_session_key, password_with_pad, - CIFS_ENCPWD_SIZE); - return 0; - } - - /* calculate old style session key */ - /* calling toupper is less broken than repeatedly - calling nls_toupper would be since that will never - work for UTF8, but neither handles multibyte code pages - but the only alternative would be converting to UCS-16 (Unicode) - (using a routine something like UniStrupr) then - uppercasing and then converting back from Unicode - which - would only worth doing it if we knew it were utf8. Basically - utf8 and other multibyte codepages each need their own strupper - function since a byte at a time will ont work. */ - - for (i = 0; i < CIFS_ENCPWD_SIZE; i++) - password_with_pad[i] = toupper(password_with_pad[i]); - - rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); - - return rc; -} -#endif /* CIFS_WEAK_PW_HASH */ - /* Build a proper attribute value/target info pairs blob. * Fill in netbios and dns domain name and workstation name * and client time (total five av pairs and + one end of fields indicator. diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 6e4fc4221418..b1b175f229ee 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -437,15 +437,9 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses) seq_puts(s, ",sec="); switch (ses->sectype) { - case LANMAN: - seq_puts(s, "lanman"); - break; case NTLMv2: seq_puts(s, "ntlmv2"); break; - case NTLM: - seq_puts(s, "ntlm"); - break; case Kerberos: seq_puts(s, "krb5"); break; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c6a9542ca281..c068f7d8d879 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -114,8 +114,6 @@ enum statusEnum { enum securityEnum { Unspecified = 0, /* not specified */ - LANMAN, /* Legacy LANMAN auth */ - NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ Kerberos, /* Kerberos via SPNEGO */ @@ -634,7 +632,6 @@ struct TCP_Server_Info { struct session_key session_key; unsigned long lstrp; /* when we got last response from this server */ struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ -#define CIFS_NEGFLAVOR_LANMAN 0 /* wct == 13, LANMAN */ #define CIFS_NEGFLAVOR_UNENCAP 1 /* wct == 17, but no ext_sec */ #define CIFS_NEGFLAVOR_EXTENDED 2 /* wct == 17, ext_sec bit set */ char negflavor; /* NEGOTIATE response flavor */ @@ -1734,16 +1731,8 @@ static inline bool is_retryable_error(int error) /* Security Flags: indicate type of session setup needed */ #define CIFSSEC_MAY_SIGN 0x00001 -#define CIFSSEC_MAY_NTLM 0x00002 #define CIFSSEC_MAY_NTLMV2 0x00004 #define CIFSSEC_MAY_KRB5 0x00008 -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFSSEC_MAY_LANMAN 0x00010 -#define CIFSSEC_MAY_PLNTXT 0x00020 -#else -#define CIFSSEC_MAY_LANMAN 0 -#define CIFSSEC_MAY_PLNTXT 0 -#endif /* weak passwords */ #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ #define CIFSSEC_MAY_NTLMSSP 0x00080 /* raw ntlmssp with ntlmv2 */ @@ -1751,32 +1740,19 @@ static inline bool is_retryable_error(int error) /* note that only one of the following can be set so the result of setting MUST flags more than once will be to require use of the stronger protocol */ -#define CIFSSEC_MUST_NTLM 0x02002 #define CIFSSEC_MUST_NTLMV2 0x04004 #define CIFSSEC_MUST_KRB5 0x08008 -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFSSEC_MUST_LANMAN 0x10010 -#define CIFSSEC_MUST_PLNTXT 0x20020 -#ifdef CONFIG_CIFS_UPCALL -#define CIFSSEC_MASK 0xBF0BF /* allows weak security but also krb5 */ -#else -#define CIFSSEC_MASK 0xB70B7 /* current flags supported if weak */ -#endif /* UPCALL */ -#else /* do not allow weak pw hash */ -#define CIFSSEC_MUST_LANMAN 0 -#define CIFSSEC_MUST_PLNTXT 0 #ifdef CONFIG_CIFS_UPCALL #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ #else #define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */ #endif /* UPCALL */ -#endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP) -#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) -#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) +#define CIFSSEC_MAX (CIFSSEC_MUST_NTLMV2) +#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) /* ***************************************************************** * All constants go here @@ -1940,10 +1916,6 @@ static inline char *get_security_type_str(enum securityEnum sectype) return "Kerberos"; case NTLMv2: return "NTLMv2"; - case NTLM: - return "NTLM"; - case LANMAN: - return "LANMAN"; default: return "Unknown"; } diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index f6e235001358..dc920e206336 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -14,13 +14,7 @@ #include #include "smbfsctl.h" -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define LANMAN_PROT 0 -#define LANMAN2_PROT 1 -#define CIFS_PROT 2 -#else #define CIFS_PROT 0 -#endif #define POSIX_PROT (CIFS_PROT+1) #define BAD_PROT 0xFFFF @@ -505,30 +499,8 @@ typedef struct negotiate_req { unsigned char DialectsArray[1]; } __attribute__((packed)) NEGOTIATE_REQ; -/* Dialect index is 13 for LANMAN */ - #define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ -typedef struct lanman_neg_rsp { - struct smb_hdr hdr; /* wct = 13 */ - __le16 DialectIndex; - __le16 SecurityMode; - __le16 MaxBufSize; - __le16 MaxMpxCount; - __le16 MaxNumberVcs; - __le16 RawMode; - __le32 SessionKey; - struct { - __le16 Time; - __le16 Date; - } __attribute__((packed)) SrvTime; - __le16 ServerTimeZone; - __le16 EncryptionKeyLength; - __le16 Reserved; - __u16 ByteCount; - unsigned char EncryptionKey[1]; -} __attribute__((packed)) LANMAN_NEG_RSP; - #define READ_RAW_ENABLE 1 #define WRITE_RAW_ENABLE 2 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e0def0f0714b..f9740c21ca3d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -498,19 +498,12 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, __u32 expected_sequence_number); -extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, - const struct nls_table *); -extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern int calc_seckey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb311signingkey(struct cifs_ses *); -#ifdef CONFIG_CIFS_WEAK_PW_HASH -extern int calc_lanman_hash(const char *password, const char *cryptkey, - bool encrypt, char *lnm_session_key); -#endif /* CIFS_WEAK_PW_HASH */ extern int CIFSSMBCopy(unsigned int xid, struct cifs_tcon *source_tcon, const char *fromName, @@ -547,11 +540,8 @@ extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, const unsigned char *path); -extern int mdfour(unsigned char *, unsigned char *, int); extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, const struct nls_table *codepage); -extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, - unsigned char *p24); extern int cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f207de803629..a8e41c1e80ca 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -42,10 +42,6 @@ static struct { int index; char *name; } protocols[] = { -#ifdef CONFIG_CIFS_WEAK_PW_HASH - {LANMAN_PROT, "\2LM1.2X002"}, - {LANMAN2_PROT, "\2LANMAN2.1"}, -#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {POSIX_PROT, "\2POSIX 2"}, {BAD_PROT, "\2"} @@ -55,10 +51,6 @@ static struct { int index; char *name; } protocols[] = { -#ifdef CONFIG_CIFS_WEAK_PW_HASH - {LANMAN_PROT, "\2LM1.2X002"}, - {LANMAN2_PROT, "\2LANMAN2.1"}, -#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} }; @@ -66,17 +58,9 @@ static struct { /* define the number of elements in the cifs dialect array */ #ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 4 -#else #define CIFS_NUM_PROT 2 -#endif /* CIFS_WEAK_PW_HASH */ #else /* not posix */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 3 -#else #define CIFS_NUM_PROT 1 -#endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CIFS_POSIX */ /* @@ -475,89 +459,6 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) return 0; } -#ifdef CONFIG_CIFS_WEAK_PW_HASH -static int -decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) -{ - __s16 tmp; - struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; - - if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) - return -EOPNOTSUPP; - - server->sec_mode = le16_to_cpu(rsp->SecurityMode); - server->maxReq = min_t(unsigned int, - le16_to_cpu(rsp->MaxMpxCount), - cifs_max_pending); - set_credits(server, server->maxReq); - server->maxBuf = le16_to_cpu(rsp->MaxBufSize); - /* set up max_read for readpages check */ - server->max_read = server->maxBuf; - /* even though we do not use raw we might as well set this - accurately, in case we ever find a need for it */ - if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { - server->max_rw = 0xFF00; - server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; - } else { - server->max_rw = 0;/* do not need to use raw anyway */ - server->capabilities = CAP_MPX_MODE; - } - tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); - if (tmp == -1) { - /* OS/2 often does not set timezone therefore - * we must use server time to calc time zone. - * Could deviate slightly from the right zone. - * Smallest defined timezone difference is 15 minutes - * (i.e. Nepal). Rounding up/down is done to match - * this requirement. - */ - int val, seconds, remain, result; - struct timespec64 ts; - time64_t utc = ktime_get_real_seconds(); - ts = cnvrtDosUnixTm(rsp->SrvTime.Date, - rsp->SrvTime.Time, 0); - cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n", - ts.tv_sec, utc, - utc - ts.tv_sec); - val = (int)(utc - ts.tv_sec); - seconds = abs(val); - result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; - remain = seconds % MIN_TZ_ADJ; - if (remain >= (MIN_TZ_ADJ / 2)) - result += MIN_TZ_ADJ; - if (val < 0) - result = -result; - server->timeAdj = result; - } else { - server->timeAdj = (int)tmp; - server->timeAdj *= 60; /* also in seconds */ - } - cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); - - - /* BB get server time for time conversions and add - code to use it and timezone since this is not UTC */ - - if (rsp->EncryptionKeyLength == - cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { - memcpy(server->cryptkey, rsp->EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { - return -EIO; /* need cryptkey unless plain text */ - } - - cifs_dbg(FYI, "LANMAN negotiated\n"); - return 0; -} -#else -static inline int -decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) -{ - cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); - return -EOPNOTSUPP; -} -#endif - static bool should_set_ext_sec_flag(enum securityEnum sectype) { @@ -626,16 +527,12 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) server->dialect = le16_to_cpu(pSMBr->DialectIndex); cifs_dbg(FYI, "Dialect: %d\n", server->dialect); /* Check wct = 1 error case */ - if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) { + if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) { /* core returns wct = 1, but we do not ask for core - otherwise small wct just comes when dialect index is -1 indicating we could not negotiate a common dialect */ rc = -EOPNOTSUPP; goto neg_err_exit; - } else if (pSMBr->hdr.WordCount == 13) { - server->negflavor = CIFS_NEGFLAVOR_LANMAN; - rc = decode_lanman_negprot_rsp(server, pSMBr); - goto signing_check; } else if (pSMBr->hdr.WordCount != 17) { /* unknown wct */ rc = -EOPNOTSUPP; @@ -677,7 +574,6 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) server->capabilities &= ~CAP_EXTENDED_SECURITY; } -signing_check: if (!rc) rc = cifs_enable_signing(server, ses->sign); neg_err_exit: diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3781eee9360a..0db344807ef1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3684,38 +3684,6 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, *bcc_ptr = 0; /* password is null byte */ bcc_ptr++; /* skip password */ /* already aligned so no need to do it below */ - } else { - pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); - /* BB FIXME add code to fail this if NTLMv2 or Kerberos - specified as required (when that support is added to - the vfs in the future) as only NTLM or the much - weaker LANMAN (which we do not send by default) is accepted - by Samba (not sure whether other servers allow - NTLMv2 password here) */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((global_secflags & CIFSSEC_MAY_LANMAN) && - (ses->sectype == LANMAN)) - calc_lanman_hash(tcon->password, ses->server->cryptkey, - ses->server->sec_mode & - SECMODE_PW_ENCRYPT ? true : false, - bcc_ptr); - else -#endif /* CIFS_WEAK_PW_HASH */ - rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, - bcc_ptr, nls_codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", - __func__, rc); - cifs_buf_release(smb_buffer); - return rc; - } - - bcc_ptr += CIFS_AUTH_RESP_SIZE; - if (ses->capabilities & CAP_UNICODE) { - /* must align unicode strings */ - *bcc_ptr = 0; /* null byte password */ - bcc_ptr++; - } } if (ses->server->sign) diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 727c8835b222..3109def8e199 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -57,12 +57,9 @@ static const match_table_t cifs_secflavor_tokens = { { Opt_sec_krb5p, "krb5p" }, { Opt_sec_ntlmsspi, "ntlmsspi" }, { Opt_sec_ntlmssp, "ntlmssp" }, - { Opt_ntlm, "ntlm" }, - { Opt_sec_ntlmi, "ntlmi" }, { Opt_sec_ntlmv2, "nontlm" }, { Opt_sec_ntlmv2, "ntlmv2" }, { Opt_sec_ntlmv2i, "ntlmv2i" }, - { Opt_sec_lanman, "lanman" }, { Opt_sec_none, "none" }, { Opt_sec_err, NULL } @@ -221,23 +218,12 @@ cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_c case Opt_sec_ntlmssp: ctx->sectype = RawNTLMSSP; break; - case Opt_sec_ntlmi: - ctx->sign = true; - fallthrough; - case Opt_ntlm: - ctx->sectype = NTLM; - break; case Opt_sec_ntlmv2i: ctx->sign = true; fallthrough; case Opt_sec_ntlmv2: ctx->sectype = NTLMv2; break; -#ifdef CONFIG_CIFS_WEAK_PW_HASH - case Opt_sec_lanman: - ctx->sectype = LANMAN; - break; -#endif case Opt_sec_none: ctx->nullauth = 1; break; diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index b6243972edf3..a42ba71d7a81 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -47,11 +47,8 @@ enum cifs_sec_param { Opt_sec_krb5p, Opt_sec_ntlmsspi, Opt_sec_ntlmssp, - Opt_ntlm, - Opt_sec_ntlmi, Opt_sec_ntlmv2, Opt_sec_ntlmv2i, - Opt_sec_lanman, Opt_sec_none, Opt_sec_err diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 606fd7d6cb71..118403fbeda2 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -799,30 +799,16 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) } case CIFS_NEGFLAVOR_UNENCAP: switch (requested) { - case NTLM: case NTLMv2: return requested; case Unspecified: if (global_secflags & CIFSSEC_MAY_NTLMV2) return NTLMv2; - if (global_secflags & CIFSSEC_MAY_NTLM) - return NTLM; break; default: break; } - fallthrough; /* to attempt LANMAN authentication next */ - case CIFS_NEGFLAVOR_LANMAN: - switch (requested) { - case LANMAN: - return requested; - case Unspecified: - if (global_secflags & CIFSSEC_MAY_LANMAN) - return LANMAN; - fallthrough; - default: - return Unspecified; - } + fallthrough; default: return Unspecified; } @@ -947,230 +933,6 @@ sess_sendreceive(struct sess_data *sess_data) return rc; } -/* - * LANMAN and plaintext are less secure and off by default. - * So we make this explicitly be turned on in kconfig (in the - * build) and turned on at runtime (changed from the default) - * in proc/fs/cifs or via mount parm. Unfortunately this is - * needed for old Win (e.g. Win95), some obscure NAS and OS/2 - */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH -static void -sess_auth_lanman(struct sess_data *sess_data) -{ - int rc = 0; - struct smb_hdr *smb_buf; - SESSION_SETUP_ANDX *pSMB; - char *bcc_ptr; - struct cifs_ses *ses = sess_data->ses; - char lnm_session_key[CIFS_AUTH_RESP_SIZE]; - __u16 bytes_remaining; - - /* lanman 2 style sessionsetup */ - /* wct = 10 */ - rc = sess_alloc_buffer(sess_data, 10); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - bcc_ptr = sess_data->iov[2].iov_base; - (void)cifs_ssetup_hdr(ses, pSMB); - - pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; - - if (ses->user_name != NULL) { - /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); - - /* Calculate hash with password and copy into bcc_ptr. - * Encryption Key (stored as in cryptkey) gets used if the - * security mode bit in Negotiate Protocol response states - * to use challenge/response method (i.e. Password bit is 1). - */ - rc = calc_lanman_hash(ses->password, ses->server->cryptkey, - ses->server->sec_mode & SECMODE_PW_ENCRYPT ? - true : false, lnm_session_key); - if (rc) - goto out; - - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - } else { - pSMB->old_req.PasswordLength = 0; - } - - /* - * can not sign if LANMAN negotiated so no need - * to calculate signing key? but what if server - * changed to do higher than lanman dialect and - * we reconnected would we ever calc signing_key? - */ - - cifs_dbg(FYI, "Negotiating LANMAN setting up strings\n"); - /* Unicode not allowed for LANMAN dialects */ - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - - sess_data->iov[2].iov_len = (long) bcc_ptr - - (long) sess_data->iov[2].iov_base; - - rc = sess_sendreceive(sess_data); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; - - /* lanman response has a word count of 3 */ - if (smb_buf->WordCount != 3) { - rc = -EIO; - cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); - goto out; - } - - if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) - cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ - - ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ - cifs_dbg(FYI, "UID = %llu\n", ses->Suid); - - bytes_remaining = get_bcc(smb_buf); - bcc_ptr = pByteArea(smb_buf); - - /* BB check if Unicode and decode strings */ - if (bytes_remaining == 0) { - /* no string area to decode, do nothing */ - } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { - /* unicode string area must be word-aligned */ - if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { - ++bcc_ptr; - --bytes_remaining; - } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } - - rc = sess_establish_session(sess_data); -out: - sess_data->result = rc; - sess_data->func = NULL; - sess_free_buffer(sess_data); -} - -#endif - -static void -sess_auth_ntlm(struct sess_data *sess_data) -{ - int rc = 0; - struct smb_hdr *smb_buf; - SESSION_SETUP_ANDX *pSMB; - char *bcc_ptr; - struct cifs_ses *ses = sess_data->ses; - __u32 capabilities; - __u16 bytes_remaining; - - /* old style NTLM sessionsetup */ - /* wct = 13 */ - rc = sess_alloc_buffer(sess_data, 13); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - bcc_ptr = sess_data->iov[2].iov_base; - capabilities = cifs_ssetup_hdr(ses, pSMB); - - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); - if (ses->user_name != NULL) { - pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_AUTH_RESP_SIZE); - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_AUTH_RESP_SIZE); - - /* calculate ntlm response and session key */ - rc = setup_ntlm_response(ses, sess_data->nls_cp); - if (rc) { - cifs_dbg(VFS, "Error %d during NTLM authentication\n", - rc); - goto out; - } - - /* copy ntlm response */ - memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - } else { - pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; - pSMB->req_no_secext.CaseSensitivePasswordLength = 0; - } - - if (ses->capabilities & CAP_UNICODE) { - /* unicode strings must be word aligned */ - if (sess_data->iov[0].iov_len % 2) { - *bcc_ptr = 0; - bcc_ptr++; - } - unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - } else { - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - } - - - sess_data->iov[2].iov_len = (long) bcc_ptr - - (long) sess_data->iov[2].iov_base; - - rc = sess_sendreceive(sess_data); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; - - if (smb_buf->WordCount != 3) { - rc = -EIO; - cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); - goto out; - } - - if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) - cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ - - ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ - cifs_dbg(FYI, "UID = %llu\n", ses->Suid); - - bytes_remaining = get_bcc(smb_buf); - bcc_ptr = pByteArea(smb_buf); - - /* BB check if Unicode and decode strings */ - if (bytes_remaining == 0) { - /* no string area to decode, do nothing */ - } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { - /* unicode string area must be word-aligned */ - if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { - ++bcc_ptr; - --bytes_remaining; - } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } - - rc = sess_establish_session(sess_data); -out: - sess_data->result = rc; - sess_data->func = NULL; - sess_free_buffer(sess_data); - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; -} - static void sess_auth_ntlmv2(struct sess_data *sess_data) { @@ -1675,21 +1437,6 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) } switch (type) { - case LANMAN: - /* LANMAN and plaintext are less secure and off by default. - * So we make this explicitly be turned on in kconfig (in the - * build) and turned on at runtime (changed from the default) - * in proc/fs/cifs or via mount parm. Unfortunately this is - * needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH - sess_data->func = sess_auth_lanman; - break; -#else - return -EOPNOTSUPP; -#endif - case NTLM: - sess_data->func = sess_auth_ntlm; - break; case NTLMv2: sess_data->func = sess_auth_ntlmv2; break; diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 39a938443e3e..5da7eea3323f 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "cifspdu.h" @@ -38,74 +37,8 @@ #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) -static void -str_to_key(unsigned char *str, unsigned char *key) -{ - int i; - - key[0] = str[0] >> 1; - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); - key[7] = str[6] & 0x7F; - for (i = 0; i < 8; i++) - key[i] = (key[i] << 1); -} - -static int -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) -{ - unsigned char key2[8]; - struct des_ctx ctx; - - str_to_key(key, key2); - - if (fips_enabled) { - cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); - return -ENOENT; - } - - des_expand_key(&ctx, key2, DES_KEY_SIZE); - des_encrypt(&ctx, out, in); - memzero_explicit(&ctx, sizeof(ctx)); - - return 0; -} - -static int -E_P16(unsigned char *p14, unsigned char *p16) -{ - int rc; - unsigned char sp8[8] = - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; - - rc = smbhash(p16, sp8, p14); - if (rc) - return rc; - rc = smbhash(p16 + 8, sp8, p14 + 7); - return rc; -} - -static int -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) -{ - int rc; - - rc = smbhash(p24, c8, p21); - if (rc) - return rc; - rc = smbhash(p24 + 8, c8, p21 + 7); - if (rc) - return rc; - rc = smbhash(p24 + 16, c8, p21 + 14); - return rc; -} - /* produce a md4 message digest from data of length n bytes */ -int +static int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) { int rc; @@ -135,32 +68,6 @@ mdfour_err: return rc; } -/* - This implements the X/Open SMB password encryption - It takes a password, a 8 byte "crypt key" and puts 24 bytes of - encrypted password into p24 */ -/* Note that password must be uppercased and null terminated */ -int -SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) -{ - int rc; - unsigned char p14[14], p16[16], p21[21]; - - memset(p14, '\0', 14); - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - memcpy(p14, passwd, 14); - rc = E_P16(p14, p16); - if (rc) - return rc; - - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); - - return rc; -} - /* * Creates the MD4 Hash of the users password in NT UNICODE. */ @@ -186,25 +93,3 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16, return rc; } - -/* Does the NT MD4 hash then des encryption. */ -int -SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, - const struct nls_table *codepage) -{ - int rc; - unsigned char p16[16], p21[21]; - - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - rc = E_md4hash(passwd, p16, codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); - return rc; -} From 71c02863246167b3d1639b8278681ca8ebedcb4e Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 19 Aug 2021 20:34:59 +1000 Subject: [PATCH 07/11] cifs: fork arc4 and create a separate module for it for cifs and other users We can not drop ARC4 and basically destroy CIFS connectivity for almost all CIFS users so create a new forked ARC4 module that CIFS and other subsystems that have a hard dependency on ARC4 can use. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/Kconfig | 7 +++ fs/Makefile | 1 + fs/cifs/Kconfig | 1 - fs/cifs/cifsencrypt.c | 8 ++-- fs/cifs_common/Makefile | 6 +++ fs/cifs_common/arc4.h | 23 ++++++++++ fs/cifs_common/cifs_arc4.c | 87 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 fs/cifs_common/Makefile create mode 100644 fs/cifs_common/arc4.h create mode 100644 fs/cifs_common/cifs_arc4.c diff --git a/fs/Kconfig b/fs/Kconfig index a7749c126b8e..6d719f2c5828 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -358,7 +358,14 @@ config NFS_V4_2_SSC_HELPER source "net/sunrpc/Kconfig" source "fs/ceph/Kconfig" + source "fs/cifs/Kconfig" + +config CIFS_COMMON + tristate + default y if CIFS=y + default m if CIFS=m + source "fs/coda/Kconfig" source "fs/afs/Kconfig" source "fs/9p/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index f98f3e691c37..77b0e79c8b4f 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_LOCKD) += lockd/ obj-$(CONFIG_NLS) += nls/ obj-$(CONFIG_UNICODE) += unicode/ obj-$(CONFIG_SYSV_FS) += sysv/ +obj-$(CONFIG_CIFS_COMMON) += cifs_common/ obj-$(CONFIG_CIFS) += cifs/ obj-$(CONFIG_HPFS_FS) += hpfs/ obj-$(CONFIG_NTFS_FS) += ntfs/ diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 2e8b132efdbc..aa4457d72392 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -10,7 +10,6 @@ config CIFS select CRYPTO_SHA512 select CRYPTO_CMAC select CRYPTO_HMAC - select CRYPTO_LIB_ARC4 select CRYPTO_AEAD2 select CRYPTO_CCM select CRYPTO_GCM diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7680e0a9bea3..6679e07e533e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include "../cifs_common/arc4.h" #include int __cifs_calc_signature(struct smb_rqst *rqst, @@ -699,9 +699,9 @@ calc_seckey(struct cifs_ses *ses) return -ENOMEM; } - arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE); - arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key, - CIFS_CPHTXT_SIZE); + cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE); + cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key, + CIFS_CPHTXT_SIZE); /* make secondary_key/nonce as session key */ memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); diff --git a/fs/cifs_common/Makefile b/fs/cifs_common/Makefile new file mode 100644 index 000000000000..2fc9b40345c4 --- /dev/null +++ b/fs/cifs_common/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for Linux filesystem routines that are shared by client and server. +# + +obj-$(CONFIG_CIFS_COMMON) += cifs_arc4.o diff --git a/fs/cifs_common/arc4.h b/fs/cifs_common/arc4.h new file mode 100644 index 000000000000..12e71ec033a1 --- /dev/null +++ b/fs/cifs_common/arc4.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Common values for ARC4 Cipher Algorithm + */ + +#ifndef _CRYPTO_ARC4_H +#define _CRYPTO_ARC4_H + +#include + +#define ARC4_MIN_KEY_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_BLOCK_SIZE 1 + +struct arc4_ctx { + u32 S[256]; + u32 x, y; +}; + +int cifs_arc4_setkey(struct arc4_ctx *ctx, const u8 *in_key, unsigned int key_len); +void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int len); + +#endif /* _CRYPTO_ARC4_H */ diff --git a/fs/cifs_common/cifs_arc4.c b/fs/cifs_common/cifs_arc4.c new file mode 100644 index 000000000000..b964cc682944 --- /dev/null +++ b/fs/cifs_common/cifs_arc4.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cryptographic API + * + * ARC4 Cipher Algorithm + * + * Jon Oberheide + */ + +#include +#include "arc4.h" + +MODULE_LICENSE("GPL"); + +int cifs_arc4_setkey(struct arc4_ctx *ctx, const u8 *in_key, unsigned int key_len) +{ + int i, j = 0, k = 0; + + ctx->x = 1; + ctx->y = 0; + + for (i = 0; i < 256; i++) + ctx->S[i] = i; + + for (i = 0; i < 256; i++) { + u32 a = ctx->S[i]; + + j = (j + in_key[k] + a) & 0xff; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = a; + if (++k >= key_len) + k = 0; + } + + return 0; +} +EXPORT_SYMBOL_GPL(cifs_arc4_setkey); + +void cifs_arc4_crypt(struct arc4_ctx *ctx, u8 *out, const u8 *in, unsigned int len) +{ + u32 *const S = ctx->S; + u32 x, y, a, b; + u32 ty, ta, tb; + + if (len == 0) + return; + + x = ctx->x; + y = ctx->y; + + a = S[x]; + y = (y + a) & 0xff; + b = S[y]; + + do { + S[y] = a; + a = (a + b) & 0xff; + S[x] = b; + x = (x + 1) & 0xff; + ta = S[x]; + ty = (y + ta) & 0xff; + tb = S[ty]; + *out++ = *in++ ^ S[a]; + if (--len == 0) + break; + y = ty; + a = ta; + b = tb; + } while (true); + + ctx->x = x; + ctx->y = y; +} +EXPORT_SYMBOL_GPL(cifs_arc4_crypt); + +static int __init +init_cifs_common(void) +{ + return 0; +} +static void __init +exit_cifs_common(void) +{ +} + +module_init(init_cifs_common) +module_exit(exit_cifs_common) From 42c21973fa3c0f4898330fa30d327fbab67b5460 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 20 Aug 2021 09:32:56 +1000 Subject: [PATCH 08/11] cifs: create a MD4 module and switch cifs.ko to use it MD4 support will likely be removed from the crypto directory, but is needed for compression of NTLMSSP in SMB3 mounts. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/Kconfig | 1 - fs/cifs/cifsfs.c | 1 - fs/cifs/smbencrypt.c | 22 ++--- fs/cifs_common/Makefile | 1 + fs/cifs_common/cifs_md4.c | 201 ++++++++++++++++++++++++++++++++++++++ fs/cifs_common/md4.h | 27 +++++ 6 files changed, 238 insertions(+), 15 deletions(-) create mode 100644 fs/cifs_common/cifs_md4.c create mode 100644 fs/cifs_common/md4.h diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index aa4457d72392..3b7e3b9e4fd2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -4,7 +4,6 @@ config CIFS depends on INET select NLS select CRYPTO - select CRYPTO_MD4 select CRYPTO_MD5 select CRYPTO_SHA256 select CRYPTO_SHA512 diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b1b175f229ee..8c20bfa187ac 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1748,7 +1748,6 @@ MODULE_DESCRIPTION MODULE_VERSION(CIFS_VERSION); MODULE_SOFTDEP("ecb"); MODULE_SOFTDEP("hmac"); -MODULE_SOFTDEP("md4"); MODULE_SOFTDEP("md5"); MODULE_SOFTDEP("nls"); MODULE_SOFTDEP("aes"); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 5da7eea3323f..10047cc55286 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -24,6 +24,7 @@ #include "cifsglob.h" #include "cifs_debug.h" #include "cifsproto.h" +#include "../cifs_common/md4.h" #ifndef false #define false 0 @@ -42,29 +43,24 @@ static int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) { int rc; - struct crypto_shash *md4 = NULL; - struct sdesc *sdescmd4 = NULL; + struct md4_ctx mctx; - rc = cifs_alloc_hash("md4", &md4, &sdescmd4); - if (rc) - goto mdfour_err; - - rc = crypto_shash_init(&sdescmd4->shash); + rc = cifs_md4_init(&mctx); if (rc) { - cifs_dbg(VFS, "%s: Could not init md4 shash\n", __func__); + cifs_dbg(VFS, "%s: Could not init MD4\n", __func__); goto mdfour_err; } - rc = crypto_shash_update(&sdescmd4->shash, link_str, link_len); + rc = cifs_md4_update(&mctx, link_str, link_len); if (rc) { - cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__); + cifs_dbg(VFS, "%s: Could not update MD4\n", __func__); goto mdfour_err; } - rc = crypto_shash_final(&sdescmd4->shash, md4_hash); + rc = cifs_md4_final(&mctx, md4_hash); if (rc) - cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__); + cifs_dbg(VFS, "%s: Could not finalize MD4\n", __func__); + mdfour_err: - cifs_free_hash(&md4, &sdescmd4); return rc; } diff --git a/fs/cifs_common/Makefile b/fs/cifs_common/Makefile index 2fc9b40345c4..6fedd2f88a25 100644 --- a/fs/cifs_common/Makefile +++ b/fs/cifs_common/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_CIFS_COMMON) += cifs_arc4.o +obj-$(CONFIG_CIFS_COMMON) += cifs_md4.o diff --git a/fs/cifs_common/cifs_md4.c b/fs/cifs_common/cifs_md4.c new file mode 100644 index 000000000000..dbf9113b8600 --- /dev/null +++ b/fs/cifs_common/cifs_md4.c @@ -0,0 +1,201 @@ +/* + * Cryptographic API. + * + * MD4 Message Digest Algorithm (RFC1320). + * + * Implementation derived from Andrew Tridgell and Steve French's + * CIFS MD4 implementation, and the cryptoapi implementation + * originally based on the public domain implementation written + * by Colin Plumb in 1993. + * + * Copyright (c) Andrew Tridgell 1997-1998. + * Modified by Steve French (sfrench@us.ibm.com) 2002 + * Copyright (c) Cryptoapi developers. + * Copyright (c) 2002 David S. Miller (davem@redhat.com) + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include "md4.h" + +MODULE_LICENSE("GPL"); + +static inline u32 lshift(u32 x, unsigned int s) +{ + x &= 0xFFFFFFFF; + return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); +} + +static inline u32 F(u32 x, u32 y, u32 z) +{ + return (x & y) | ((~x) & z); +} + +static inline u32 G(u32 x, u32 y, u32 z) +{ + return (x & y) | (x & z) | (y & z); +} + +static inline u32 H(u32 x, u32 y, u32 z) +{ + return x ^ y ^ z; +} + +#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) +#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (u32)0x5A827999,s)) +#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (u32)0x6ED9EBA1,s)) + +static void md4_transform(u32 *hash, u32 const *in) +{ + u32 a, b, c, d; + + a = hash[0]; + b = hash[1]; + c = hash[2]; + d = hash[3]; + + ROUND1(a, b, c, d, in[0], 3); + ROUND1(d, a, b, c, in[1], 7); + ROUND1(c, d, a, b, in[2], 11); + ROUND1(b, c, d, a, in[3], 19); + ROUND1(a, b, c, d, in[4], 3); + ROUND1(d, a, b, c, in[5], 7); + ROUND1(c, d, a, b, in[6], 11); + ROUND1(b, c, d, a, in[7], 19); + ROUND1(a, b, c, d, in[8], 3); + ROUND1(d, a, b, c, in[9], 7); + ROUND1(c, d, a, b, in[10], 11); + ROUND1(b, c, d, a, in[11], 19); + ROUND1(a, b, c, d, in[12], 3); + ROUND1(d, a, b, c, in[13], 7); + ROUND1(c, d, a, b, in[14], 11); + ROUND1(b, c, d, a, in[15], 19); + + ROUND2(a, b, c, d, in[0], 3); + ROUND2(d, a, b, c, in[4], 5); + ROUND2(c, d, a, b, in[8], 9); + ROUND2(b, c, d, a, in[12], 13); + ROUND2(a, b, c, d, in[1], 3); + ROUND2(d, a, b, c, in[5], 5); + ROUND2(c, d, a, b, in[9], 9); + ROUND2(b, c, d, a, in[13], 13); + ROUND2(a, b, c, d, in[2], 3); + ROUND2(d, a, b, c, in[6], 5); + ROUND2(c, d, a, b, in[10], 9); + ROUND2(b, c, d, a, in[14], 13); + ROUND2(a, b, c, d, in[3], 3); + ROUND2(d, a, b, c, in[7], 5); + ROUND2(c, d, a, b, in[11], 9); + ROUND2(b, c, d, a, in[15], 13); + + ROUND3(a, b, c, d, in[0], 3); + ROUND3(d, a, b, c, in[8], 9); + ROUND3(c, d, a, b, in[4], 11); + ROUND3(b, c, d, a, in[12], 15); + ROUND3(a, b, c, d, in[2], 3); + ROUND3(d, a, b, c, in[10], 9); + ROUND3(c, d, a, b, in[6], 11); + ROUND3(b, c, d, a, in[14], 15); + ROUND3(a, b, c, d, in[1], 3); + ROUND3(d, a, b, c, in[9], 9); + ROUND3(c, d, a, b, in[5], 11); + ROUND3(b, c, d, a, in[13], 15); + ROUND3(a, b, c, d, in[3], 3); + ROUND3(d, a, b, c, in[11], 9); + ROUND3(c, d, a, b, in[7], 11); + ROUND3(b, c, d, a, in[15], 15); + + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; +} + +static inline void md4_transform_helper(struct md4_ctx *ctx) +{ + le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block)); + md4_transform(ctx->hash, ctx->block); +} + +int cifs_md4_init(struct md4_ctx *mctx) +{ + memset(mctx, 0, sizeof(struct md4_ctx)); + mctx->hash[0] = 0x67452301; + mctx->hash[1] = 0xefcdab89; + mctx->hash[2] = 0x98badcfe; + mctx->hash[3] = 0x10325476; + mctx->byte_count = 0; + + return 0; +} +EXPORT_SYMBOL_GPL(cifs_md4_init); + +int cifs_md4_update(struct md4_ctx *mctx, const u8 *data, unsigned int len) +{ + const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return 0; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, avail); + + md4_transform_helper(mctx); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + memcpy(mctx->block, data, sizeof(mctx->block)); + md4_transform_helper(mctx); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + memcpy(mctx->block, data, len); + + return 0; +} +EXPORT_SYMBOL_GPL(cifs_md4_update); + +int cifs_md4_final(struct md4_ctx *mctx, u8 *out) +{ + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + + *p++ = 0x80; + if (padding < 0) { + memset(p, 0x00, padding + sizeof(u64)); + md4_transform_helper(mctx); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + mctx->block[14] = mctx->byte_count << 3; + mctx->block[15] = mctx->byte_count >> 29; + le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - + sizeof(u64)) / sizeof(u32)); + md4_transform(mctx->hash, mctx->block); + cpu_to_le32_array(mctx->hash, ARRAY_SIZE(mctx->hash)); + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(*mctx)); + + return 0; +} +EXPORT_SYMBOL_GPL(cifs_md4_final); diff --git a/fs/cifs_common/md4.h b/fs/cifs_common/md4.h new file mode 100644 index 000000000000..5337becc699a --- /dev/null +++ b/fs/cifs_common/md4.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Common values for ARC4 Cipher Algorithm + */ + +#ifndef _CIFS_MD4_H +#define _CIFS_MD4_H + +#include + +#define MD4_DIGEST_SIZE 16 +#define MD4_HMAC_BLOCK_SIZE 64 +#define MD4_BLOCK_WORDS 16 +#define MD4_HASH_WORDS 4 + +struct md4_ctx { + u32 hash[MD4_HASH_WORDS]; + u32 block[MD4_BLOCK_WORDS]; + u64 byte_count; +}; + + +int cifs_md4_init(struct md4_ctx *mctx); +int cifs_md4_update(struct md4_ctx *mctx, const u8 *data, unsigned int len); +int cifs_md4_final(struct md4_ctx *mctx, u8 *out); + +#endif /* _CIFS_MD4_H */ From 38f4910b8b26d3a940167f207bddfcc589310c8a Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 24 Aug 2021 12:07:46 -0500 Subject: [PATCH 09/11] cifs: cifs_md4 convert to SPDX identifier Add SPDX license identifier and replace license boilerplate for cifs_md4.c Signed-off-by: Steve French --- fs/cifs/smb2maperror.c | 1 - fs/cifs_common/cifs_md4.c | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index cea39bcecbab..181514b8770d 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/smb2/smb2maperror.c * * Functions which do error mapping of SMB2 status codes to POSIX errors * diff --git a/fs/cifs_common/cifs_md4.c b/fs/cifs_common/cifs_md4.c index dbf9113b8600..50f78cfc6ce9 100644 --- a/fs/cifs_common/cifs_md4.c +++ b/fs/cifs_common/cifs_md4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Cryptographic API. * @@ -14,11 +15,6 @@ * Copyright (c) 2002 David S. Miller (davem@redhat.com) * Copyright (c) 2002 James Morris * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include #include From 332c404a55ef3b39837e958284275622a2a4849d Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 24 Aug 2021 16:14:53 -0500 Subject: [PATCH 10/11] cifs: add cifs_common directory to MAINTAINERS file With some files moving into the cifs_common directory, we need to add it to the CIFS entry in the MAINTAINERS file. Suggested-by: Paulo Alcantara (SUSE) Signed-off-by: Steve French --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index c6b8a720c0bc..c1d80232f949 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4629,6 +4629,7 @@ W: http://linux-cifs.samba.org/ T: git git://git.samba.org/sfrench/cifs-2.6.git F: Documentation/admin-guide/cifs/ F: fs/cifs/ +F: fs/cifs_common/ COMPACTPCI HOTPLUG CORE M: Scott Murray From 3998f0b8bc49ec784990971dc1f16bf367b19078 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 25 Aug 2021 21:16:56 +1000 Subject: [PATCH 11/11] cifs: Do not leak EDEADLK to dgetents64 for STATUS_USER_SESSION_DELETED RHBZ: 1994393 If we hit a STATUS_USER_SESSION_DELETED for the Create part in the Create/QueryDirectory compound that starts a directory scan we will leak EDEADLK back to userspace and surprise glibc and the application. Pick this up initiate_cifs_search() and retry a small number of tries before we return an error to userspace. Cc: stable@vger.kernel.org Reported-by: Xiaoli Feng Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/readdir.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index bfee176b901d..54d77c99e21c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -369,7 +369,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, */ static int -initiate_cifs_search(const unsigned int xid, struct file *file, +_initiate_cifs_search(const unsigned int xid, struct file *file, const char *full_path) { __u16 search_flags; @@ -451,6 +451,27 @@ error_exit: return rc; } +static int +initiate_cifs_search(const unsigned int xid, struct file *file, + const char *full_path) +{ + int rc, retry_count = 0; + + do { + rc = _initiate_cifs_search(xid, file, full_path); + /* + * If we don't have enough credits to start reading the + * directory just try again after short wait. + */ + if (rc != -EDEADLK) + break; + + usleep_range(512, 2048); + } while (retry_count++ < 5); + + return rc; +} + /* return length of unicode string in bytes */ static int cifs_unicode_bytelen(const char *str) {