From: Namjae Jeon namjae.jeon@samsung.com
mainline inclusion from mainline-5.15-rc1 commit a2d0b5034a5fff029ec1be08d3264f8407d47602 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I60T7G CVE: NA
Reference: https://git.kernel.org/torvalds/linux/c/a2d0b5034a5f
-------------------------------
Add the check to prevent potential overflow with smb_strtoUTF16() and UNICODE_LEN().
Reviewed-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Namjae Jeon namjae.jeon@samsung.com Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zhong Jinghua zhongjinghua@huawei.com --- fs/cifsd/auth.c | 50 ++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-)
diff --git a/fs/cifsd/auth.c b/fs/cifsd/auth.c index 8c80f918c8d7..f742870a930b 100644 --- a/fs/cifsd/auth.c +++ b/fs/cifsd/auth.c @@ -246,7 +246,7 @@ static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, char *dname) { - int ret, len; + int ret, len, conv_len; wchar_t *domain = NULL; __le16 *uniname = NULL; struct ksmbd_crypto_ctx *ctx; @@ -279,15 +279,17 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, goto out; }
- if (len) { - len = smb_strtoUTF16(uniname, user_name(sess->user), len, + conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len, sess->conn->local_nls); - UniStrupr(uniname); + if (conv_len < 0 || conv_len > len) { + ret = -EINVAL; + goto out; } + UniStrupr(uniname);
ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), (char *)uniname, - UNICODE_LEN(len)); + UNICODE_LEN(conv_len)); if (ret) { ksmbd_debug(AUTH, "Could not update with user\n"); goto out; @@ -301,12 +303,16 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, goto out; }
- len = smb_strtoUTF16((__le16 *)domain, dname, len, + conv_len = smb_strtoUTF16((__le16 *)domain, dname, len, sess->conn->local_nls); + if (conv_len < 0 || conv_len > len) { + ret = -EINVAL; + goto out; + }
ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), (char *)domain, - UNICODE_LEN(len)); + UNICODE_LEN(conv_len)); if (ret) { ksmbd_debug(AUTH, "Could not update with domain\n"); goto out; @@ -584,6 +590,7 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob, wchar_t *name; __u8 *target_name; unsigned int len, flags, blob_off, blob_len, type, target_info_len = 0; + unsigned int uni_len, conv_len; int cflags = sess->ntlmssp.client_flags;
memcpy(chgblob->Signature, NTLMSSP_SIGNATURE, 8); @@ -611,19 +618,24 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
chgblob->NegotiateFlags = cpu_to_le32(flags); len = strlen(ksmbd_netbios_name()); - name = kmalloc(2 + (len * 2), GFP_KERNEL); + name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL); if (!name) return -ENOMEM;
- len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len, + conv_len = smb_strtoUTF16((__le16 *)name, ksmbd_netbios_name(), len, sess->conn->local_nls); - len = UNICODE_LEN(len); + if (conv_len < 0 || conv_len > len) { + kfree(name); + return -EINVAL; + } + + uni_len = UNICODE_LEN(conv_len);
blob_off = sizeof(struct challenge_message); - blob_len = blob_off + len; + blob_len = blob_off + uni_len;
- chgblob->TargetName.Length = cpu_to_le16(len); - chgblob->TargetName.MaximumLength = cpu_to_le16(len); + chgblob->TargetName.Length = cpu_to_le16(uni_len); + chgblob->TargetName.MaximumLength = cpu_to_le16(uni_len); chgblob->TargetName.BufferOffset = cpu_to_le32(blob_off);
/* Initialize random conn challenge */ @@ -635,18 +647,18 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob, chgblob->TargetInfoArray.BufferOffset = cpu_to_le32(blob_len);
target_name = (__u8 *)chgblob + blob_off; - memcpy(target_name, name, len); - tinfo = (struct target_info *)(target_name + len); + memcpy(target_name, name, uni_len); + tinfo = (struct target_info *)(target_name + uni_len);
chgblob->TargetInfoArray.Length = 0; /* Add target info list for NetBIOS/DNS settings */ for (type = NTLMSSP_AV_NB_COMPUTER_NAME; type <= NTLMSSP_AV_DNS_DOMAIN_NAME; type++) { tinfo->Type = cpu_to_le16(type); - tinfo->Length = cpu_to_le16(len); - memcpy(tinfo->Content, name, len); - tinfo = (struct target_info *)((char *)tinfo + 4 + len); - target_info_len += 4 + len; + tinfo->Length = cpu_to_le16(uni_len); + memcpy(tinfo->Content, name, uni_len); + tinfo = (struct target_info *)((char *)tinfo + 4 + uni_len); + target_info_len += 4 + uni_len; }
/* Add terminator subblock */