Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef31bef6 authored by Haiyang Zhang's avatar Haiyang Zhang Committed by David S. Miller
Browse files

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: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent afd46503
Loading
Loading
Loading
Loading
+9 −24
Original line number Original line Diff line number Diff line
@@ -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 */
	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,
		(rndis_hdr->msg_len > sizeof(struct rndis_message)) ?
			sizeof(struct rndis_message) :
			rndis_hdr->msg_len);


	dump_rndis_message(dev, &rndis_msg);
	dump_rndis_message(dev, rndis_msg);


	switch (rndis_msg.ndis_msg_type) {
	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;
	}
	}