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);
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)) {
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)
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) {