diff options
author | Jarek Poplawski <jarkao2@gmail.com> | 2010-01-10 17:04:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-11 18:39:42 -0500 |
commit | eb70df13ee52dbc0f2c0ffd8ed34a8cd27440baf (patch) | |
tree | 9026781435cdaf46b8414f4596903dd7d5f2e5ae /net/packet | |
parent | fa15e99b6bb44aa86b241a43ca8c509e91f80153 (diff) |
af_packet: Don't use skb after dev_queue_xmit()
tpacket_snd() can change and kfree an skb after dev_queue_xmit(),
which is illegal.
With debugging by: Stephen Hemminger <shemminger@vyatta.com>
Reported-by: Michael Breuer <mbreuer@majjas.com>
With help from: David S. Miller <davem@davemloft.net>
Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
Tested-by: Michael Breuer<mbreuer@majjas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e0516a22be2e..f126d18dbdc4 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1021,8 +1021,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
1021 | 1021 | ||
1022 | status = TP_STATUS_SEND_REQUEST; | 1022 | status = TP_STATUS_SEND_REQUEST; |
1023 | err = dev_queue_xmit(skb); | 1023 | err = dev_queue_xmit(skb); |
1024 | if (unlikely(err > 0 && (err = net_xmit_errno(err)) != 0)) | 1024 | if (unlikely(err > 0)) { |
1025 | goto out_xmit; | 1025 | err = net_xmit_errno(err); |
1026 | if (err && __packet_get_status(po, ph) == | ||
1027 | TP_STATUS_AVAILABLE) { | ||
1028 | /* skb was destructed already */ | ||
1029 | skb = NULL; | ||
1030 | goto out_status; | ||
1031 | } | ||
1032 | /* | ||
1033 | * skb was dropped but not destructed yet; | ||
1034 | * let's treat it like congestion or err < 0 | ||
1035 | */ | ||
1036 | err = 0; | ||
1037 | } | ||
1026 | packet_increment_head(&po->tx_ring); | 1038 | packet_increment_head(&po->tx_ring); |
1027 | len_sum += tp_len; | 1039 | len_sum += tp_len; |
1028 | } while (likely((ph != NULL) || | 1040 | } while (likely((ph != NULL) || |
@@ -1033,9 +1045,6 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
1033 | err = len_sum; | 1045 | err = len_sum; |
1034 | goto out_put; | 1046 | goto out_put; |
1035 | 1047 | ||
1036 | out_xmit: | ||
1037 | skb->destructor = sock_wfree; | ||
1038 | atomic_dec(&po->tx_ring.pending); | ||
1039 | out_status: | 1048 | out_status: |
1040 | __packet_set_status(po, ph, status); | 1049 | __packet_set_status(po, ph, status); |
1041 | kfree_skb(skb); | 1050 | kfree_skb(skb); |