Commit 69f030cf authored by Junyi Liu's avatar Junyi Liu Committed by Steve French
Browse files

ksmbd: validate SID in parent security descriptor during ACL inheritance



Introduce smb_validate_ntsd_sid() helper to safely validate Owner SID
and Group SID inside the NT Security Descriptor (smb_ntsd) retrieved
from the parent directory.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarJunyi Liu <moss80199@gmail.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 35155033
Loading
Loading
Loading
Loading
+50 −16
Original line number Diff line number Diff line
@@ -1096,6 +1096,40 @@ static int smb_append_inherited_ace(struct smb_ace **ace, int *nt_size,
	return 0;
}

static int smb_validate_ntsd_sid(struct smb_ntsd *pntsd, size_t pntsd_size,
				  unsigned int sid_offset, struct smb_sid **sid,
				  size_t *sid_size)
{
	size_t sid_end;

	*sid = NULL;
	*sid_size = 0;

	if (!sid_offset)
		return 0;

	if (sid_offset < sizeof(struct smb_ntsd) ||
	    check_add_overflow(sid_offset, (size_t)CIFS_SID_BASE_SIZE,
			       &sid_end) ||
	    sid_end > pntsd_size)
		return -EINVAL;

	*sid = (struct smb_sid *)((char *)pntsd + sid_offset);
	if ((*sid)->num_subauth > SID_MAX_SUB_AUTHORITIES)
		return -EINVAL;

	if (check_add_overflow((size_t)CIFS_SID_BASE_SIZE,
			       sizeof(__le32) * (size_t)(*sid)->num_subauth,
			       &sid_end))
		return -EINVAL;

	if (sid_offset > pntsd_size || sid_end > pntsd_size - sid_offset)
		return -EINVAL;

	*sid_size = sid_end;
	return 0;
}

int smb_inherit_dacl(struct ksmbd_conn *conn,
		     const struct path *path,
		     unsigned int uid, unsigned int gid)
@@ -1108,28 +1142,28 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
	struct dentry *parent = path->dentry->d_parent;
	struct mnt_idmap *idmap = mnt_idmap(path->mnt);
	int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size;
	int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size;
	int rc = 0, pntsd_type, ppntsd_size, acl_len, aces_size;
	unsigned int dacloffset;
	size_t dacl_struct_end;
	u16 num_aces, ace_cnt = 0;
	char *aces_base;
	bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);

	pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
	ppntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap,
					    parent, &parent_pntsd);
	if (pntsd_size <= 0)
	if (ppntsd_size <= 0)
		return -ENOENT;

	dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
	if (!dacloffset ||
	    check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) ||
	    dacl_struct_end > (size_t)pntsd_size) {
	    dacl_struct_end > (size_t)ppntsd_size) {
		rc = -EINVAL;
		goto free_parent_pntsd;
	}

	parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
	acl_len = pntsd_size - dacloffset;
	acl_len = ppntsd_size - dacloffset;
	num_aces = le16_to_cpu(parent_pdacl->num_aces);
	pntsd_type = le16_to_cpu(parent_pntsd->type);
	pdacl_size = le16_to_cpu(parent_pdacl->size);
@@ -1243,19 +1277,19 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
		struct smb_ntsd *pntsd;
		struct smb_acl *pdacl;
		struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL;
		int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
		size_t powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size;
		size_t pntsd_alloc_size;

		if (parent_pntsd->osidoffset) {
			powner_sid = (struct smb_sid *)((char *)parent_pntsd +
					le32_to_cpu(parent_pntsd->osidoffset));
			powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4);
		}
		if (parent_pntsd->gsidoffset) {
			pgroup_sid = (struct smb_sid *)((char *)parent_pntsd +
					le32_to_cpu(parent_pntsd->gsidoffset));
			pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4);
		}
		rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
					   le32_to_cpu(parent_pntsd->osidoffset),
					   &powner_sid, &powner_sid_size);
		if (rc)
			goto free_aces_base;
		rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size,
					   le32_to_cpu(parent_pntsd->gsidoffset),
					   &pgroup_sid, &pgroup_sid_size);
		if (rc)
			goto free_aces_base;

		if (check_add_overflow(sizeof(struct smb_ntsd),
				       (size_t)powner_sid_size,