aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2014-09-10 18:05:42 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-12 17:51:25 -0400
commitbf7fa551e0ce507b82935055f4b4aa229be73eeb (patch)
tree88068940307b6369cc1f6a2b346f6a070949f4bd /net/mac80211
parentcab41c47d92851de71c74b1a7bdbf0fadf6ae4ba (diff)
mac80211: Resolve sk_refcnt/sk_wmem_alloc issue in wifi ack path
There is a possible issue with the use, or lack thereof of sk_refcnt and sk_wmem_alloc in the wifi ack status functionality. Specifically if a socket were to request acknowledgements, and the socket were to have sk_refcnt drop to 0 resulting in it waiting on sk_wmem_alloc to reach 0 it would be possible to have sock_queue_err_skb orphan the last buffer, resulting in __sk_free being called on the socket. After this the buffer is enqueued on sk_error_queue, however the queue has already been flushed resulting in at least a memory leak, if not a data corruption. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/tx.c15
1 files changed, 4 insertions, 11 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 925c39f4099e..cf7141452b0f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2072,30 +2072,23 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
2072 2072
2073 if (unlikely(!multicast && skb->sk && 2073 if (unlikely(!multicast && skb->sk &&
2074 skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) { 2074 skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
2075 struct sk_buff *orig_skb = skb; 2075 struct sk_buff *ack_skb = skb_clone_sk(skb);
2076 2076
2077 skb = skb_clone(skb, GFP_ATOMIC); 2077 if (ack_skb) {
2078 if (skb) {
2079 unsigned long flags; 2078 unsigned long flags;
2080 int id; 2079 int id;
2081 2080
2082 spin_lock_irqsave(&local->ack_status_lock, flags); 2081 spin_lock_irqsave(&local->ack_status_lock, flags);
2083 id = idr_alloc(&local->ack_status_frames, orig_skb, 2082 id = idr_alloc(&local->ack_status_frames, ack_skb,
2084 1, 0x10000, GFP_ATOMIC); 2083 1, 0x10000, GFP_ATOMIC);
2085 spin_unlock_irqrestore(&local->ack_status_lock, flags); 2084 spin_unlock_irqrestore(&local->ack_status_lock, flags);
2086 2085
2087 if (id >= 0) { 2086 if (id >= 0) {
2088 info_id = id; 2087 info_id = id;
2089 info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; 2088 info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
2090 } else if (skb_shared(skb)) {
2091 kfree_skb(orig_skb);
2092 } else { 2089 } else {
2093 kfree_skb(skb); 2090 kfree_skb(ack_skb);
2094 skb = orig_skb;
2095 } 2091 }
2096 } else {
2097 /* couldn't clone -- lose tx status ... */
2098 skb = orig_skb;
2099 } 2092 }
2100 } 2093 }
2101 2094