Commit 4cbfe450 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v7.1-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - fix for creating tmpfiles

 - fix durable reconnect error path

 - validate SID in security descriptor when inheriting DACL

* tag 'v7.1-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  smb/server: promote S_DEL_ON_CLS to S_DEL_PENDING when close
  ksmbd: validate SID in parent security descriptor during ACL inheritance
  ksmbd: fix durable reconnect error path file lifetime
parents 40054463 4ec9c8e0
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -3804,8 +3804,19 @@ int smb2_open(struct ksmbd_work *work)
		ksmbd_debug(SMB, "Error response: %x\n", rsp->hdr.Status);
	}

	if (dh_info.reconnected)
	if (dh_info.reconnected) {
		/*
		 * If reconnect succeeded, fp was republished in the
		 * session file table.  On a later error, ksmbd_fd_put()
		 * above drops the session reference; drop the durable
		 * lookup reference through the same session-aware path so
		 * final close removes the volatile id before freeing fp.
		 */
		if (rc && fp == dh_info.fp)
			ksmbd_fd_put(work, dh_info.fp);
		else
			ksmbd_put_durable_fd(dh_info.fp);
	}

	kfree(name);
	kfree(lc);
+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,
+12 −4
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ int ksmbd_query_inode_status(struct dentry *dentry)
		return ret;

	down_read(&ci->m_lock);
	if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
	if (ci->m_flags & S_DEL_PENDING)
		ret = KSMBD_INODE_STATUS_PENDING_DELETE;
	else
		ret = KSMBD_INODE_STATUS_OK;
@@ -227,7 +227,7 @@ bool ksmbd_inode_pending_delete(struct ksmbd_file *fp)
	int ret;

	down_read(&ci->m_lock);
	ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS));
	ret = (ci->m_flags & S_DEL_PENDING);
	up_read(&ci->m_lock);

	return ret;
@@ -395,12 +395,20 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
		}
	}

	down_write(&ci->m_lock);
	/* Promote S_DEL_ON_CLS to S_DEL_PENDING when close */
	if (ci->m_flags & S_DEL_ON_CLS) {
		ci->m_flags &= ~S_DEL_ON_CLS;
		ci->m_flags |= S_DEL_PENDING;
	}
	up_write(&ci->m_lock);

	if (atomic_dec_and_test(&ci->m_count)) {
		bool do_unlink = false;

		down_write(&ci->m_lock);
		if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) {
			ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
		if (ci->m_flags & S_DEL_PENDING) {
			ci->m_flags &= ~S_DEL_PENDING;
			do_unlink = true;
		}
		up_write(&ci->m_lock);