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

Commit 9b8a74e3 authored by Andy Green's avatar Andy Green Committed by David S. Miller
Browse files

[MAC80211]: Improve sanity checks on injected packets



Michael Wu noticed that the skb length checking is not taken care of enough when
a packet is presented on the Monitor interface for injection.

This patch improves the sanity checking and removes fake offsets placed
into the skb network and transport header.

Signed-off-by: default avatarAndy Green <andy@warmcat.com>
Signed-off-by: default avatarJiri Benc <jbenc@suse.cz>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent dfe6e81d
Loading
Loading
Loading
Loading
+28 −20
Original line number Diff line number Diff line
@@ -1270,46 +1270,54 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
	struct ieee80211_tx_packet_data *pkt_data;
	struct ieee80211_radiotap_header *prthdr =
		(struct ieee80211_radiotap_header *)skb->data;
	u16 len;
	u16 len_rthdr;

	/*
	 * there must be a radiotap header at the
	 * start in this case
	 */
	if (unlikely(prthdr->it_version)) {
		/* only version 0 is supported */
		dev_kfree_skb(skb);
		return NETDEV_TX_OK;
	}
	/* check for not even having the fixed radiotap header part */
	if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
		goto fail; /* too short to be possibly valid */

	/* is it a header version we can trust to find length from? */
	if (unlikely(prthdr->it_version))
		goto fail; /* only version 0 is supported */

	/* then there must be a radiotap header with a length we can use */
	len_rthdr = ieee80211_get_radiotap_len(skb->data);

	/* does the skb contain enough to deliver on the alleged length? */
	if (unlikely(skb->len < len_rthdr))
		goto fail; /* skb too short for claimed rt header extent */

	skb->dev = local->mdev;

	pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
	memset(pkt_data, 0, sizeof(*pkt_data));
	/* needed because we set skb device to master */
	pkt_data->ifindex = dev->ifindex;

	pkt_data->mgmt_iface = 0;
	pkt_data->do_not_encrypt = 1;

	/* above needed because we set skb device to master */

	/*
	 * fix up the pointers accounting for the radiotap
	 * header still being in there.  We are being given
	 * a precooked IEEE80211 header so no need for
	 * normal processing
	 */
	len = le16_to_cpu(get_unaligned(&prthdr->it_len));
	skb_set_mac_header(skb, len);
	skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr));
	skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr));

	skb_set_mac_header(skb, len_rthdr);
	/*
	 * pass the radiotap header up to
	 * the next stage intact
	 * these are just fixed to the end of the rt area since we
	 * don't have any better information and at this point, nobody cares
	 */
	dev_queue_xmit(skb);
	skb_set_network_header(skb, len_rthdr);
	skb_set_transport_header(skb, len_rthdr);

	/* pass the radiotap header up to the next stage intact */
	dev_queue_xmit(skb);
	return NETDEV_TX_OK;

fail:
	dev_kfree_skb(skb);
	return NETDEV_TX_OK; /* meaning, we dealt with the skb */
}

/**