summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Green <andy@warmcat.com>2007-10-09 22:46:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-11-16 08:27:36 -0800
commit1e3bfd1413e453b29517e72a9d8f16f22733a847 (patch)
tree93a310b96759fb17d6bfd17aeccddab966b99b3e
parentbe3d7bec26e083b9e42acd5944ad8293b94b06b2 (diff)
mac80211: Improve sanity checks on injected packets
patch 9b8a74e3482f9fc077a88c13fa0ceca8feb0b772 in mainline. 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: Andy Green <andy@warmcat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--net/mac80211/ieee80211.c48
1 files changed, 28 insertions, 20 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 2e699d6ebc7d..0c6c3c3b94af 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -1680,46 +1680,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);
+
+ /* 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 */
}