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 | |
| 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>
| -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); |
