Commit 205d4b20 authored by David S. Miller's avatar David S. Miller

[TCP]: Do not access inet_sk() of a time-wait bucket.

Bug discovered by Mandred Spraul.
parent 5680d227
...@@ -208,6 +208,8 @@ struct tcp_tw_bucket { ...@@ -208,6 +208,8 @@ struct tcp_tw_bucket {
#endif #endif
}; };
#define tcptw_sk(__sk) ((struct tcp_tw_bucket *)(__sk))
extern kmem_cache_t *tcp_timewait_cachep; extern kmem_cache_t *tcp_timewait_cachep;
static inline void tcp_tw_put(struct tcp_tw_bucket *tw) 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); ...@@ -246,7 +248,11 @@ extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
#endif /* __BIG_ENDIAN */ #endif /* __BIG_ENDIAN */
#define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ #define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
(((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie)) && \ (((*((__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)))) (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
#else /* 32-bit arch */ #else /* 32-bit arch */
#define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) #define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr)
...@@ -255,6 +261,11 @@ extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw); ...@@ -255,6 +261,11 @@ extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
(inet_sk(__sk)->rcv_saddr == (__daddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \
((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \
(!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) (!((__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 */ #endif /* 64-bit arch */
#define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \ #define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \
......
...@@ -509,7 +509,7 @@ static inline struct sock *__tcp_v4_lookup_established(u32 saddr, u16 sport, ...@@ -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. */ /* Must check for a TIME_WAIT'er before going to listener hash. */
for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) 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; goto hit;
out: out:
read_unlock(&head->lock); read_unlock(&head->lock);
...@@ -570,7 +570,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport, ...@@ -570,7 +570,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
skp = &sk2->next) { skp = &sk2->next) {
tw = (struct tcp_tw_bucket *)sk2; 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); struct tcp_opt *tp = tcp_sk(sk);
/* With PAWS, it is safe from the viewpoint /* With PAWS, it is safe from the viewpoint
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment