提交 740612c7 编写于 作者: W Wang Hai 提交者: Zheng Zengkai

usb: gadget: rndis: Fix info leak of rndis

hulk inclusion
category: bugfix
bugzilla: 172330
CVE: HWPSIRT-2021-84477

--------------------------------

We can construct some special USB packets that cause kernel
info leak by the following steps of rndis.

1. construct the packet to make rndis call gen_ndis_set_resp().

In gen_ndis_set_resp(), BufOffset comes from the USB packet and
it is not checked so that BufOffset can be any value. Therefore,
if OID is RNDIS_OID_GEN_CURRENT_PACKET_FILTER, then *params->filter
can get data at any address.

2. construct the packet to make rndis call rndis_query_response().

In rndis_query_response(), if OID is RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
then the data of *params->filter is fetched and returned, resulting in
info leak.

Therefore, we need to check the BufOffset to prevent info leak. Here,
buf size is USB_COMP_EP0_BUFSIZ, as long as "8 + BufOffset + BufLength"
is less than USB_COMP_EP0_BUFSIZ, it will be considered legal.

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: NWang Hai <wanghai38@huawei.com>
Reviewed-by: NWei Yongjun <weiyongjun1@huawei.com>
Reviewed-by: NXiu Jianfeng <xiujianfeng@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 6b759618
......@@ -2157,7 +2157,7 @@ int composite_dev_prepare(struct usb_composite_driver *composite,
if (!cdev->req)
return -ENOMEM;
cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL);
if (!cdev->req->buf)
goto fail;
......
......@@ -506,6 +506,10 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
switch (OID) {
case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
if (buf_len < 2) {
pr_err("%s:Not support for buf_len < 2\n", __func__);
break;
}
/* these NDIS_PACKET_TYPE_* bitflags are shared with
* cdc_filter; it's not RNDIS-specific
......@@ -592,6 +596,7 @@ static int rndis_query_response(struct rndis_params *params,
rndis_query_msg_type *buf)
{
rndis_query_cmplt_type *resp;
u32 BufOffset, BufLength;
rndis_resp_t *r;
/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
......@@ -612,12 +617,25 @@ static int rndis_query_response(struct rndis_params *params,
resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
BufLength = le32_to_cpu(buf->InformationBufferLength);
/*
* If the address of the buf to be accessed exceeds the valid
* range of the buf, then return RNDIS_STATUS_NOT_SUPPORTED.
*/
if (8 + BufOffset + BufLength >= USB_COMP_EP0_BUFSIZ) {
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = cpu_to_le32(sizeof(*resp));
resp->InformationBufferLength = cpu_to_le32(0);
resp->InformationBufferOffset = cpu_to_le32(0);
params->resp_avail(params->v);
return 0;
}
if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
le32_to_cpu(buf->InformationBufferOffset)
+ 8 + (u8 *)buf,
le32_to_cpu(buf->InformationBufferLength),
r)) {
BufOffset + 8 + (u8 *)buf, BufLength,
r)) {
/* OID not supported */
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = cpu_to_le32(sizeof *resp);
......@@ -660,6 +678,17 @@ static int rndis_set_response(struct rndis_params *params,
resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
resp->MessageLength = cpu_to_le32(16);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
/*
* If the address of the buf to be accessed exceeds the valid
* range of the buf, then return RNDIS_STATUS_NOT_SUPPORTED.
*/
if (8 + BufOffset + BufLength >= USB_COMP_EP0_BUFSIZ) {
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
params->resp_avail(params->v);
return 0;
}
if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID),
((u8 *)buf) + 8 + BufOffset, BufLength, r))
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册