tcp: avoid oops in tcp_metrics and reset tcpm_stamp
Julian Anastasov [Mon, 23 Jul 2012 07:46:38 +0000 (10:46 +0300)]
In tcp_tw_remember_stamp we incorrectly checked tw
instead of tm, it can lead to oops if the cached entry is
not found.

tcpm_stamp was not updated in tcpm_check_stamp when
tcpm_suck_dst was called, move the update into tcpm_suck_dst,
so that we do not call it infinitely on every next cache hit
after TCP_METRICS_TIMEOUT.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/ipv4/tcp_metrics.c

index 992f1bf..2288a63 100644 (file)
@@ -107,6 +107,8 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst)
 {
        u32 val;
 
+       tm->tcpm_stamp = jiffies;
+
        val = 0;
        if (dst_metric_locked(dst, RTAX_RTT))
                val |= 1 << TCP_METRIC_RTT;
@@ -158,7 +160,6 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
                        goto out_unlock;
        }
        tm->tcpm_addr = *addr;
-       tm->tcpm_stamp = jiffies;
 
        tcpm_suck_dst(tm, dst);
 
@@ -621,7 +622,7 @@ bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw)
 
        rcu_read_lock();
        tm = __tcp_get_metrics_tw(tw);
-       if (tw) {
+       if (tm) {
                const struct tcp_timewait_sock *tcptw;
                struct sock *sk = (struct sock *) tw;