[PATCH 2/8] cxl/features: Bound the Get Feature output by the user output buffer

Guixin Liu <[email protected]>
Newsgroups org.kernel.vger.linux-cxl
Message-ID <[email protected]>
cxlctl_get_feature() allocates the output buffer from the size userspace
asked for (fwctl_rpc.out_len, arriving as *out_len), but then asks the
device for a completely independent, also userspace supplied, amount of
data:

	out_size = *out_len;
	count = le16_to_cpu(feat_in->count);
	rpc_out = kvzalloc(out_size, GFP_KERNEL);
	out_size = cxl_get_feature(..., rpc_out->payload, count, ...);

cxl_get_feature() loops until it has read @count bytes into
@rpc_out->payload, so any 'count' larger than the output allocation
overflows it, with up to 64KB of device supplied data landing past the end
of the object. An out_len of 0 additionally turns the allocation into
ZERO_SIZE_PTR.

Reject the request unless the allocation can hold the Feature data at the
offset the mailbox writes it to, i.e. sizeof(struct fwctl_rpc_cxl_out_hdr)
plus @count.

Note that struct_size_t(struct fwctl_rpc_cxl_out, payload, count) is not
the right bound here: @payload lives in a union whose largest member,
'struct cxl_mbox_get_sup_feats_out', is 8 bytes, so
sizeof(struct fwctl_rpc_cxl_out) already covers the first 8 payload bytes
and the resulting bound would reject valid requests that allocate exactly
the header plus the Feature data.

Fixes: 5908f3ed6dc2 ("cxl: Add support to handle user feature commands for get feature")
Signed-off-by: Guixin Liu <[email protected]>
---
 drivers/cxl/core/features.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c
index 0ab1a8547b7e..b631643ecc7a 100644
--- a/drivers/cxl/core/features.c
+++ b/drivers/cxl/core/features.c
@@ -471,6 +471,10 @@ static void *cxlctl_get_feature(struct cxl_features_state *cxlfs,
 	if (!count)
 		return ERR_PTR(-EINVAL);
 
+	/* cxl_get_feature() writes @count bytes at @rpc_out->payload */
+	if (out_size < sizeof(struct fwctl_rpc_cxl_out_hdr) + count)
+		return ERR_PTR(-EINVAL);
+
 	struct fwctl_rpc_cxl_out *rpc_out __free(kvfree) =
 		kvzalloc(out_size, GFP_KERNEL);
 	if (!rpc_out)
-- 
2.43.7
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.