Commit 8d09328d authored by Zisen Ye's avatar Zisen Ye Committed by Steve French
Browse files

smb/client: fix out-of-bounds read in smb2_compound_op()

If a server sends a truncated response but a large OutputBufferLength, and
terminates the EA list early, check_wsl_eas() returns success without
validating that the entire OutputBufferLength fits within iov_len.

Then smb2_compound_op() does:
    memcpy(idata->wsl.eas, data[0], size[0]);

Where size[0] is OutputBufferLength. If iov_len is smaller than size[0],
memcpy can read beyond the end of the rsp_iov allocation and leak adjacent
kernel heap memory.

Link: https://lore.kernel.org/linux-cifs/d998240c-aca9-420d-9dbd-f5ba24af19e0@chenxiaosong.com/


Fixes: ea41367b ("smb: client: introduce SMB2_OP_QUERY_WSL_EA")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarZisen Ye <zisenye@stu.xidian.edu.cn>
Reviewed-by: default avatarChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent d62b8d23
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
	u32 outlen, next;
	u16 vlen;
	u8 nlen;
	u8 *end;
	u8 *ea_end, *iov_end;

	outlen = le32_to_cpu(rsp->OutputBufferLength);
	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
@@ -120,15 +120,19 @@ static int check_wsl_eas(struct kvec *rsp_iov)

	ea = (void *)((u8 *)rsp_iov->iov_base +
		      le16_to_cpu(rsp->OutputBufferOffset));
	end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
	ea_end = (u8 *)ea + outlen;
	iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
	if (ea_end > iov_end)
		return -EINVAL;

	for (;;) {
		if ((u8 *)ea > end - sizeof(*ea))
		if ((u8 *)ea > ea_end - sizeof(*ea))
			return -EINVAL;

		nlen = ea->ea_name_length;
		vlen = le16_to_cpu(ea->ea_value_length);
		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
		    (u8 *)ea->ea_data + nlen + 1 + vlen > end)
		    (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
			return -EINVAL;

		switch (vlen) {