netdev
[Top] [All Lists]

[PATCH] Fix TCP EFAULT error reporting

To: netdev@xxxxxxxxxxx
Subject: [PATCH] Fix TCP EFAULT error reporting
From: Andi Kleen <ak@xxxxxxx>
Date: Sun, 27 Jan 2002 04:13:35 +0100
Sender: owner-netdev@xxxxxxxxxxx
User-agent: Mutt/1.3.22.1i
davem doesn't seem to like this one, so it'll probably not go in. 
In case someone needs proper EFAULT reporting for 2.4/2.5 TCP anyways
here is the patch for reference. It fixes all network related system
call testcases in LTP (except for one which was a bug in LTP).

Patch against 2.5.3pre, but should apply to 2.4 with at best minor
changes.

Also does some minor cleanups in  the TCP input path. Also very carefull
to not pollute any hot paths; it only adds a single new check to them.

-Andi


--- linux-work/include/net/tcp.h-TCPFAULT       Sat Jan  5 18:18:28 2002
+++ linux-work/include/net/tcp.h        Thu Jan 10 19:57:12 2002
@@ -573,6 +573,8 @@
 
        int                     (*remember_stamp)       (struct sock *sk);
 
+       void                    (*send_reset)           (struct sk_buff *skb);
+
        __u16                   net_header_len;
 
        int                     (*setsockopt)           (struct sock *sk, 
@@ -637,6 +639,8 @@
 extern int                     tcp_v4_remember_stamp(struct sock *sk);
 
 extern int                     tcp_v4_tw_remember_stamp(struct tcp_tw_bucket 
*tw);
+
+extern void                    tcp_v4_send_reset(struct sk_buff *skb);
 
 extern int                     tcp_sendmsg(struct sock *sk, struct msghdr 
*msg, int size);
 extern ssize_t                 tcp_sendpage(struct socket *sock, struct page 
*page, int offset, size_t size, int flags);
--- linux-work/net/ipv4/tcp_input.c-TCPFAULT    Fri Jan  4 10:51:50 2002
+++ linux-work/net/ipv4/tcp_input.c     Thu Jan 10 20:03:17 2002
@@ -3315,7 +3315,7 @@
                                __set_current_state(TASK_RUNNING);
 
                                if (tcp_copy_to_iovec(sk, skb, tcp_header_len))
-                                       goto csum_error;
+                                       goto csum_error_fault;
 
                                __skb_pull(skb,tcp_header_len);
 
@@ -3413,7 +3413,8 @@
                TCP_INC_STATS_BH(TcpInErrs);
                NET_INC_STATS_BH(TCPAbortOnSyn);
                tcp_reset(sk);
-               return 1;
+               tp->af_specific->send_reset(skb); 
+               goto discard; 
        }
 
 step5:
@@ -3436,6 +3437,11 @@
 discard:
        __kfree_skb(skb);
        return 0;
+
+csum_error_fault:
+       TCP_INC_STATS_BH(TcpInErrs);
+       __kfree_skb(skb); 
+       return -EFAULT; 
 }
 
 static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
--- linux-work/net/ipv4/tcp_ipv4.c-TCPFAULT     Fri Jan  4 10:51:50 2002
+++ linux-work/net/ipv4/tcp_ipv4.c      Thu Jan 10 23:35:38 2002
@@ -53,6 +53,7 @@
 #include <linux/random.h>
 #include <linux/cache.h>
 #include <linux/init.h>
+#include <linux/compiler.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -1033,7 +1034,7 @@
  *     Exception: precedence violation. We do not implement it in any case.
  */
 
-static void tcp_v4_send_reset(struct sk_buff *skb)
+void tcp_v4_send_reset(struct sk_buff *skb)
 {
        struct tcphdr *th = skb->h.th;
        struct tcphdr rth;
@@ -1546,12 +1547,12 @@
 
        IP_INC_STATS_BH(IpInDelivers);
 
-       if (sk->state == TCP_ESTABLISHED) { /* Fast path */
+       if (likely(sk->state == TCP_ESTABLISHED)) { /* Fast path */
+               int err;                
                TCP_CHECK_TIMER(sk);
-               if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
-                       goto reset;
+               err = tcp_rcv_established(sk, skb, skb->h.th, skb->len);
                TCP_CHECK_TIMER(sk);
-               return 0; 
+               return err; 
        }
 
        if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
@@ -1875,6 +1876,7 @@
        tcp_v4_syn_recv_sock,
        tcp_v4_hash_connecting,
        tcp_v4_remember_stamp,
+       tcp_v4_send_reset,
        sizeof(struct iphdr),
 
        ip_setsockopt,
--- linux-work/net/ipv4/tcp.c-TCPFAULT  Fri Jan  4 21:36:38 2002
+++ linux-work/net/ipv4/tcp.c   Thu Jan 10 20:01:33 2002
@@ -1359,21 +1359,23 @@
        return timeo;
 }
 
-static void tcp_prequeue_process(struct sock *sk)
+static int tcp_prequeue_process(struct sock *sk)
 {
        struct sk_buff *skb;
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+       int err = 0; 
 
        net_statistics[smp_processor_id()*2+1].TCPPrequeued += 
skb_queue_len(&tp->ucopy.prequeue);
 
        /* RX process wants to run with disabled BHs, though it is not 
necessary */
        local_bh_disable();
        while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
-               sk->backlog_rcv(sk, skb);
+               err |= sk->backlog_rcv(sk, skb);
        local_bh_enable();
 
        /* Clear memory counter. */
        tp->ucopy.memory = 0;
+       return err;
 }
 
 /*
@@ -1573,7 +1575,8 @@
                        if (tp->rcv_nxt == tp->copied_seq &&
                            skb_queue_len(&tp->ucopy.prequeue)) {
 do_prequeue:
-                               tcp_prequeue_process(sk);
+                               if ((err = tcp_prequeue_process(sk)) < 0) 
+                                       goto out; 
 
                                if ((chunk = len - tp->ucopy.len) != 0) {
                                        
net_statistics[smp_processor_id()*2+1].TCPDirectCopyFromPrequeue += chunk;
--- linux-work/net/ipv6/tcp_ipv6.c-TCPFAULT     Tue Nov 27 22:58:12 2001
+++ linux-work/net/ipv6/tcp_ipv6.c      Thu Jan 10 19:57:12 2002
@@ -1413,6 +1413,7 @@
        struct sk_filter *filter;
 #endif
        struct sk_buff *opt_skb = NULL;
+       int err;
 
        /* Imagine: socket is IPv6. IPv4 packet arrives,
           goes to IPv4 receive handler and backlogged.
@@ -1456,12 +1457,11 @@
 
        if (sk->state == TCP_ESTABLISHED) { /* Fast path */
                TCP_CHECK_TIMER(sk);
-               if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
-                       goto reset;
+               err = tcp_rcv_established(sk, skb, skb->h.th, skb->len);
                TCP_CHECK_TIMER(sk);
                if (opt_skb)
                        goto ipv6_pktoptions;
-               return 0;
+               return err;
        }
 
        if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
@@ -1486,6 +1486,7 @@
                }
        }
 
+       err = 0; 
        TCP_CHECK_TIMER(sk);
        if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
                goto reset;
@@ -1531,7 +1532,7 @@
 
        if (opt_skb)
                kfree_skb(opt_skb);
-       return 0;
+       return err;
 }
 
 int tcp_v6_rcv(struct sk_buff *skb)
@@ -1763,6 +1764,7 @@
        tcp_v6_syn_recv_sock,
        tcp_v6_hash_connecting,
        tcp_v6_remember_stamp,
+       tcp_v6_send_reset,
        sizeof(struct ipv6hdr),
 
        ipv6_setsockopt,
@@ -1783,6 +1785,7 @@
        tcp_v6_syn_recv_sock,
        tcp_v4_hash_connecting,
        tcp_v4_remember_stamp,
+       tcp_v4_send_reset,
        sizeof(struct iphdr),
 
        ipv6_setsockopt,
--- linux-work/net/netsyms.c-TCPFAULT   Fri Jan  4 10:51:52 2002
+++ linux-work/net/netsyms.c    Thu Jan 10 19:57:12 2002
@@ -392,6 +392,7 @@
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(tcp_cwnd_application_limited);
 EXPORT_SYMBOL(tcp_sendpage);
+EXPORT_SYMBOL(tcp_v4_send_reset);
 
 EXPORT_SYMBOL(tcp_write_xmit);
 

<Prev in Thread] Current Thread [Next in Thread>