From fda0fd6c5b722cc48e904e0daafedca275d332af Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 14 Oct 2005 16:38:49 +1000 Subject: [DCCP]: Use skb_set_owner_w in dccp_transmit_skb when skb->sk is NULL David S. Miller wrote: > One thing you can probably do for this bug is to mark data packets > explicitly somehow, perhaps in the SKB control block DCCP already > uses for other data. Put some boolean in there, set it true for > data packets. Then change the test in dccp_transmit_skb() as > appropriate to test the boolean flag instead of "skb_cloned(skb)". I agree. In fact we already have that flag, it's called skb->sk. So here is patch to test that instead of skb_cloned(). Signed-off-by: Herbert Xu Acked-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/output.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index 4786bdcddcc92..946ec2db75de7 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -62,10 +62,8 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) skb->h.raw = skb_push(skb, dccp_header_size); dh = dccp_hdr(skb); - /* - * Data packets are not cloned as they are never retransmitted - */ - if (skb_cloned(skb)) + + if (!skb->sk) skb_set_owner_w(skb, sk); /* Build DCCP header and checksum it. */ -- cgit 1.2.3-korg From ffa29347dfbc158d1f47f5925324a6f5713659c1 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 16 Oct 2005 21:08:46 +1000 Subject: [DCCP]: Make dccp_write_xmit always free the packet icmp_send doesn't use skb->sk at all so even if skb->sk has already been freed it can't cause crash there (it would've crashed somewhere else first, e.g., ip_queue_xmit). I found a double-free on an skb that could explain this though. dccp_sendmsg and dccp_write_xmit are a little confused as to what should free the packet when something goes wrong. Sometimes they both go for the ball and end up in each other's way. This patch makes dccp_write_xmit always free the packet no matter what. This makes sense since dccp_transmit_skb which in turn comes from the fact that ip_queue_xmit always frees the packet. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/output.c | 3 ++- net/dccp/proto.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/net/dccp/output.c b/net/dccp/output.c index 946ec2db75de7..7006549f70504 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -241,7 +241,8 @@ int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) err = dccp_transmit_skb(sk, skb); ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len); - } + } else + kfree_skb(skb); return err; } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index a1cfd0e9e3bc9..a021c3422f677 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -402,8 +402,6 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, * This bug was _quickly_ found & fixed by just looking at an OSTRA * generated callgraph 8) -acme */ - if (rc != 0) - goto out_discard; out_release: release_sock(sk); return rc ? : len; -- cgit 1.2.3-korg From 49c5bfaffe8ae6e6440dc4bf78b03800960d93f5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 18 Oct 2005 12:03:28 +1000 Subject: [DCCP]: Clear the IPCB area Turns out the problem has nothing to do with use-after-free or double-free. It's just that we're not clearing the CB area and DCCP unlike TCP uses a CB format that's incompatible with IP. Signed-off-by: Herbert Xu Signed-off-by: Ian McDonald Signed-off-by: Arnaldo Carvalho de Melo --- net/dccp/ipv4.c | 2 ++ net/dccp/output.c | 1 + 2 files changed, 3 insertions(+) diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index ae088d1347af0..6298cf58ff9e8 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -463,6 +463,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, if (skb != NULL) { const struct inet_request_sock *ireq = inet_rsk(req); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, ireq->rmt_addr, ireq->opt); @@ -647,6 +648,7 @@ int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) if (skb != NULL) { const struct inet_sock *inet = inet_sk(sk); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_build_and_send_pkt(skb, sk, inet->saddr, inet->daddr, NULL); if (err == NET_XMIT_CN) diff --git a/net/dccp/output.c b/net/dccp/output.c index 7006549f70504..29250749f16f8 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -100,6 +100,7 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) DCCP_INC_STATS(DCCP_MIB_OUTSEGS); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); err = ip_queue_xmit(skb, 0); if (err <= 0) return err; -- cgit 1.2.3-korg From b2cc99f04c5a732c793519aca61a20f719b50db4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 20 Oct 2005 17:13:13 -0200 Subject: [TCP] Allow len == skb->len in tcp_fragment It is legitimate to call tcp_fragment with len == skb->len since that is done for FIN packets and the FIN flag counts as one byte. So we should only check for the len > skb->len case. Signed-off-by: Herbert Xu Signed-off-by: Arnaldo Carvalho de Melo --- net/ipv4/tcp_output.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7114031fdc70e..b907456a79f46 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -435,17 +435,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss int nsize, old_factor; u16 flags; - if (unlikely(len >= skb->len)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "TCP: seg_size=%u, mss=%u, seq=%u, " - "end_seq=%u, skb->len=%u.\n", len, mss_now, - TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - skb->len); - WARN_ON(1); - } - return 0; - } - + BUG_ON(len > skb->len); nsize = skb_headlen(skb) - len; if (nsize < 0) nsize = 0; -- cgit 1.2.3-korg