[Patch 1/3]: dccp: Oops in DCCPv6

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I think I got the cause for the Oops observed in 
http://www.mail-archive.com/dccp@xxxxxxxxxxxxxxx/msg00578.html

The problem is always with applications listening on PF_INET6
sockets. Apart from the mentioned oops, I observed another one one,
triggered at irregular intervals via timer interrupt:

    run_timer_softirq -> dccp_keepalive_timer 
                      -> inet_csk_reqsk_queue_prune
                      -> reqsk_free
                      -> dccp_v6_reqsk_destructor

The latter function is the problem and is also the last function to be called
in said kernel panic. 

In any case, there is a real problem with allocating the right request_sock
which is what this patch tackles. 

It fixes the following problem:
 - application listens on PF_INET6
 - DCCPv4 packet comes in, is handed over to dccp_v4_do_rcv, from there
   to dccp_v4_conn_request

Now: socket is PF_INET6, packet is IPv4. The following code then furnishes
the connection with IPv6 - request_sock operations:
 
   req = reqsk_alloc(sk->sk_prot->rsk_prot);

The first problem is that all further incoming packets will get a Reset since
the connection can not be looked up. 

The second problem is worse:
 --> reqsk_alloc is called instead of inet6_reqsk_alloc
 --> consequently inet6_rsk_offset is never set (dangling pointer)
 --> the request_sock_ops are nevertheless still dccp6_request_ops
 --> destructor is called via reqsk_free
 --> dccp_v6_reqsk_destructor tries to free random memory location (inet6_rsk_offset not set)
 --> panic

I have tested this for a while, DCCP sockets are now handled correctly in all three scenarios
(v4/v6 only/v4-mapped). 

Signed-off-by: Gerrit Renker <gerrit@xxxxxxxxxxxxxx>
---
 ipv4.c |    2 +-
 ipv6.c |    4 +---
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 7e746c4..d27e208 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -489,7 +489,7 @@ int dccp_v4_conn_request(struct sock *sk
 	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
 		goto drop;
 
-	req = reqsk_alloc(sk->sk_prot->rsk_prot);
+	req = reqsk_alloc(&dccp_request_sock_ops);
 	if (req == NULL)
 		goto drop;
 
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 7171a78..91e7b12 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -672,7 +672,6 @@ static struct sock *dccp_v6_hnd_req(stru
 
 static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 {
-	struct inet_request_sock *ireq;
 	struct dccp_sock dp;
 	struct request_sock *req;
 	struct dccp_request_sock *dreq;
@@ -701,7 +700,7 @@ static int dccp_v6_conn_request(struct s
 	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
 		goto drop;
 
-	req = inet6_reqsk_alloc(sk->sk_prot->rsk_prot);
+	req = inet6_reqsk_alloc(&dccp6_request_sock_ops);
 	if (req == NULL)
 		goto drop;
 
@@ -713,7 +712,6 @@ static int dccp_v6_conn_request(struct s
 		goto drop_and_free;
 
 	ireq6 = inet6_rsk(req);
-	ireq = inet_rsk(req);
 	ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
 	ipv6_addr_copy(&ireq6->loc_addr, &skb->nh.ipv6h->daddr);
 	req->rcv_wnd	= dccp_feat_default_sequence_window;
-
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux