From: Namjae Jeon namjae.jeon@samsung.com
mainline inclusion from mainline-5.15-rc1 commit 50355b0b20103a2be39e269a92909fa69f16f2d0 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I60T7G CVE: NA
Reference: https://git.kernel.org/torvalds/linux/c/50355b0b2010
-------------------------------
Dan reported static checker warning:
fs/cifsd/smbacl.c:1140 smb_check_perm_dacl() error: we previously assumed 'pntsd' could be null (see line 1137)
This patch validate bounds of pntsd buffer.
Reported-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/smbacl.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/fs/cifsd/smbacl.c b/fs/cifsd/smbacl.c index 294c5a8fe9af..77c79cf4afd0 100644 --- a/fs/cifsd/smbacl.c +++ b/fs/cifsd/smbacl.c @@ -800,9 +800,13 @@ int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, le32_to_cpu(pntsd->gsidoffset), le32_to_cpu(pntsd->sacloffset), dacloffset);
- if (dacloffset && dacl_ptr) + if (dacloffset) { + if (end_of_acl <= (char *)dacl_ptr || + end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) + return -EIO; total_ace_size = le16_to_cpu(dacl_ptr->size) - sizeof(struct smb_acl); + }
pntsd_type = le16_to_cpu(pntsd->type);
@@ -1131,13 +1135,28 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, struct smb_ace *others_ace = NULL; struct posix_acl_entry *pa_entry; unsigned int sid_type = SIDOWNER; + char *end_of_acl;
ksmbd_debug(SMB, "check permission using windows acl\n"); acl_size = ksmbd_vfs_get_sd_xattr(conn, dentry, &pntsd); - if (acl_size <= 0 || (pntsd && !pntsd->dacloffset)) + if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) { + kfree(pntsd); return 0; + }
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); + end_of_acl = ((char *)pntsd) + acl_size; + if (end_of_acl <= (char *)pdacl) { + kfree(pntsd); + return 0; + } + + if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size) || + le16_to_cpu(pdacl->size) < sizeof(struct smb_acl)) { + kfree(pntsd); + return 0; + } + if (!pdacl->num_aces) { if (!(le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) && *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) { @@ -1156,6 +1175,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { granted |= le32_to_cpu(ace->access_req); ace = (struct smb_ace *) ((char *)ace + le16_to_cpu(ace->size)); + if (end_of_acl < (char *)ace) + goto err_out; }
if (!pdacl->num_aces) @@ -1177,6 +1198,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, others_ace = ace;
ace = (struct smb_ace *) ((char *)ace + le16_to_cpu(ace->size)); + if (end_of_acl < (char *)ace) + goto err_out; }
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {