From 205d4b20061528034755abc166b5ac2b23f79a40 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 28 May 2003 05:11:37 -0700 Subject: [TCP]: Do not access inet_sk() of a time-wait bucket. Bug discovered by Mandred Spraul. --- include/net/tcp.h | 13 ++++++++++++- net/ipv4/tcp_ipv4.c | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 158ee68198b4..afc40c419be0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -208,6 +208,8 @@ struct tcp_tw_bucket { #endif }; +#define tcptw_sk(__sk) ((struct tcp_tw_bucket *)(__sk)) + extern kmem_cache_t *tcp_timewait_cachep; static inline void tcp_tw_put(struct tcp_tw_bucket *tw) @@ -246,7 +248,11 @@ extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw); #endif /* __BIG_ENDIAN */ #define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ (((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie)) && \ - ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ + ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ + (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) +#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ + (((*((__u64 *)&(tcptw_sk(__sk)->daddr)))== (__cookie)) && \ + ((*((__u32 *)&(tcptw_sk(__sk)->dport)))== (__ports)) && \ (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) @@ -255,6 +261,11 @@ extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw); (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) +#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ + ((tcptw_sk(__sk)->daddr == (__saddr)) && \ + (tcptw_sk(__sk)->rcv_saddr == (__daddr)) && \ + ((*((__u32 *)&(tcptw_sk(__sk)->dport)))== (__ports)) && \ + (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) #endif /* 64-bit arch */ #define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 544a181ff550..3f16c2a57aed 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -509,7 +509,7 @@ static inline struct sock *__tcp_v4_lookup_established(u32 saddr, u16 sport, /* Must check for a TIME_WAIT'er before going to listener hash. */ for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) - if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) + if (TCP_IPV4_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) goto hit; out: read_unlock(&head->lock); @@ -570,7 +570,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport, skp = &sk2->next) { tw = (struct tcp_tw_bucket *)sk2; - if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { + if (TCP_IPV4_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { struct tcp_opt *tp = tcp_sk(sk); /* With PAWS, it is safe from the viewpoint -- cgit v1.2.3