net/hyperv: Fix data corruption in rndis_filter_receive()

Limiting the memcpy to be the sizeof(struct rndis_message) can truncate
the message if there are Per-Packet-Info or Out-of-Band data.

In my earlier patch (commit 45326342), the unnecessary kmap_atomic and
kunmap_atomic surrounding this memcpy have been removed because the memory
in the receive buffer is always mapped. This memcpy is not necessary
either. To fix the bug, I removed the memcpy.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Haiyang Zhang 2012-03-12 10:20:49 +00:00 committed by David S. Miller
parent afd465030a
commit ef31bef621

View File

@ -352,8 +352,7 @@ int rndis_filter_receive(struct hv_device *dev,
{ {
struct netvsc_device *net_dev = hv_get_drvdata(dev); struct netvsc_device *net_dev = hv_get_drvdata(dev);
struct rndis_device *rndis_dev; struct rndis_device *rndis_dev;
struct rndis_message rndis_msg; struct rndis_message *rndis_msg;
struct rndis_message *rndis_hdr;
struct net_device *ndev; struct net_device *ndev;
if (!net_dev) if (!net_dev)
@ -375,46 +374,32 @@ int rndis_filter_receive(struct hv_device *dev,
return -ENODEV; return -ENODEV;
} }
rndis_hdr = pkt->data; rndis_msg = pkt->data;
/* Make sure we got a valid rndis message */ dump_rndis_message(dev, rndis_msg);
if ((rndis_hdr->ndis_msg_type != REMOTE_NDIS_PACKET_MSG) &&
(rndis_hdr->msg_len > sizeof(struct rndis_message))) {
netdev_err(ndev, "incoming rndis message buffer overflow "
"detected (got %u, max %zu)..marking it an error!\n",
rndis_hdr->msg_len,
sizeof(struct rndis_message));
}
memcpy(&rndis_msg, rndis_hdr, switch (rndis_msg->ndis_msg_type) {
(rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
sizeof(struct rndis_message) :
rndis_hdr->msg_len);
dump_rndis_message(dev, &rndis_msg);
switch (rndis_msg.ndis_msg_type) {
case REMOTE_NDIS_PACKET_MSG: case REMOTE_NDIS_PACKET_MSG:
/* data msg */ /* data msg */
rndis_filter_receive_data(rndis_dev, &rndis_msg, pkt); rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
break; break;
case REMOTE_NDIS_INITIALIZE_CMPLT: case REMOTE_NDIS_INITIALIZE_CMPLT:
case REMOTE_NDIS_QUERY_CMPLT: case REMOTE_NDIS_QUERY_CMPLT:
case REMOTE_NDIS_SET_CMPLT: case REMOTE_NDIS_SET_CMPLT:
/* completion msgs */ /* completion msgs */
rndis_filter_receive_response(rndis_dev, &rndis_msg); rndis_filter_receive_response(rndis_dev, rndis_msg);
break; break;
case REMOTE_NDIS_INDICATE_STATUS_MSG: case REMOTE_NDIS_INDICATE_STATUS_MSG:
/* notification msgs */ /* notification msgs */
rndis_filter_receive_indicate_status(rndis_dev, &rndis_msg); rndis_filter_receive_indicate_status(rndis_dev, rndis_msg);
break; break;
default: default:
netdev_err(ndev, netdev_err(ndev,
"unhandled rndis message (type %u len %u)\n", "unhandled rndis message (type %u len %u)\n",
rndis_msg.ndis_msg_type, rndis_msg->ndis_msg_type,
rndis_msg.msg_len); rndis_msg->msg_len);
break; break;
} }