diff options
| author | Florian Westphal <fwestphal@astaro.com> | 2011-02-17 05:32:38 -0500 |
|---|---|---|
| committer | Patrick McHardy <kaber@trash.net> | 2011-02-17 05:32:38 -0500 |
| commit | d503b30bd648b3cb4e5f50b65d27e389960cc6d9 (patch) | |
| tree | ebb3e2ad85f32cd95c767dda75d25873c384e78d /net | |
| parent | de9963f0f2dfad128b26ae7bf6005f5948416a6d (diff) | |
netfilter: tproxy: do not assign timewait sockets to skb->sk
Assigning a socket in timewait state to skb->sk can trigger
kernel oops, e.g. in nfnetlink_log, which does:
if (skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file) ...
in the timewait case, accessing sk->sk_callback_lock and sk->sk_socket
is invalid.
Either all of these spots will need to add a test for sk->sk_state != TCP_TIME_WAIT,
or xt_TPROXY must not assign a timewait socket to skb->sk.
This does the latter.
If a TW socket is found, assign the tproxy nfmark, but skip the skb->sk assignment,
thus mimicking behaviour of a '-m socket .. -j MARK/ACCEPT' re-routing rule.
The 'SYN to TW socket' case is left unchanged -- we try to redirect to the
listener socket.
Cc: Balazs Scheidler <bazsi@balabit.hu>
Cc: KOVACS Krisztian <hidden@balabit.hu>
Signed-off-by: Florian Westphal <fwestphal@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
| -rw-r--r-- | net/netfilter/nf_tproxy_core.c | 27 | ||||
| -rw-r--r-- | net/netfilter/xt_TPROXY.c | 22 | ||||
| -rw-r--r-- | net/netfilter/xt_socket.c | 13 |
3 files changed, 43 insertions, 19 deletions
diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c index 4d87befb04c0..474d621cbc2e 100644 --- a/net/netfilter/nf_tproxy_core.c +++ b/net/netfilter/nf_tproxy_core.c | |||
| @@ -28,26 +28,23 @@ nf_tproxy_destructor(struct sk_buff *skb) | |||
| 28 | skb->destructor = NULL; | 28 | skb->destructor = NULL; |
| 29 | 29 | ||
| 30 | if (sk) | 30 | if (sk) |
| 31 | nf_tproxy_put_sock(sk); | 31 | sock_put(sk); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | /* consumes sk */ | 34 | /* consumes sk */ |
| 35 | int | 35 | void |
| 36 | nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk) | 36 | nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk) |
| 37 | { | 37 | { |
| 38 | bool transparent = (sk->sk_state == TCP_TIME_WAIT) ? | 38 | /* assigning tw sockets complicates things; most |
| 39 | inet_twsk(sk)->tw_transparent : | 39 | * skb->sk->X checks would have to test sk->sk_state first */ |
| 40 | inet_sk(sk)->transparent; | 40 | if (sk->sk_state == TCP_TIME_WAIT) { |
| 41 | 41 | inet_twsk_put(inet_twsk(sk)); | |
| 42 | if (transparent) { | 42 | return; |
| 43 | skb_orphan(skb); | 43 | } |
| 44 | skb->sk = sk; | 44 | |
| 45 | skb->destructor = nf_tproxy_destructor; | 45 | skb_orphan(skb); |
| 46 | return 1; | 46 | skb->sk = sk; |
| 47 | } else | 47 | skb->destructor = nf_tproxy_destructor; |
| 48 | nf_tproxy_put_sock(sk); | ||
| 49 | |||
| 50 | return 0; | ||
| 51 | } | 48 | } |
| 52 | EXPORT_SYMBOL_GPL(nf_tproxy_assign_sock); | 49 | EXPORT_SYMBOL_GPL(nf_tproxy_assign_sock); |
| 53 | 50 | ||
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index 640678f47a2a..dcfd57eb9d02 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
| @@ -33,6 +33,20 @@ | |||
| 33 | #include <net/netfilter/nf_tproxy_core.h> | 33 | #include <net/netfilter/nf_tproxy_core.h> |
| 34 | #include <linux/netfilter/xt_TPROXY.h> | 34 | #include <linux/netfilter/xt_TPROXY.h> |
| 35 | 35 | ||
| 36 | static bool tproxy_sk_is_transparent(struct sock *sk) | ||
| 37 | { | ||
| 38 | if (sk->sk_state != TCP_TIME_WAIT) { | ||
| 39 | if (inet_sk(sk)->transparent) | ||
| 40 | return true; | ||
| 41 | sock_put(sk); | ||
| 42 | } else { | ||
| 43 | if (inet_twsk(sk)->tw_transparent) | ||
| 44 | return true; | ||
| 45 | inet_twsk_put(inet_twsk(sk)); | ||
| 46 | } | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | |||
| 36 | static inline __be32 | 50 | static inline __be32 |
| 37 | tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) | 51 | tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr) |
| 38 | { | 52 | { |
| @@ -141,7 +155,7 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport, | |||
| 141 | skb->dev, NFT_LOOKUP_LISTENER); | 155 | skb->dev, NFT_LOOKUP_LISTENER); |
| 142 | 156 | ||
| 143 | /* NOTE: assign_sock consumes our sk reference */ | 157 | /* NOTE: assign_sock consumes our sk reference */ |
| 144 | if (sk && nf_tproxy_assign_sock(skb, sk)) { | 158 | if (sk && tproxy_sk_is_transparent(sk)) { |
| 145 | /* This should be in a separate target, but we don't do multiple | 159 | /* This should be in a separate target, but we don't do multiple |
| 146 | targets on the same rule yet */ | 160 | targets on the same rule yet */ |
| 147 | skb->mark = (skb->mark & ~mark_mask) ^ mark_value; | 161 | skb->mark = (skb->mark & ~mark_mask) ^ mark_value; |
| @@ -149,6 +163,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport, | |||
| 149 | pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n", | 163 | pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n", |
| 150 | iph->protocol, &iph->daddr, ntohs(hp->dest), | 164 | iph->protocol, &iph->daddr, ntohs(hp->dest), |
| 151 | &laddr, ntohs(lport), skb->mark); | 165 | &laddr, ntohs(lport), skb->mark); |
| 166 | |||
| 167 | nf_tproxy_assign_sock(skb, sk); | ||
| 152 | return NF_ACCEPT; | 168 | return NF_ACCEPT; |
| 153 | } | 169 | } |
| 154 | 170 | ||
| @@ -306,7 +322,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 306 | par->in, NFT_LOOKUP_LISTENER); | 322 | par->in, NFT_LOOKUP_LISTENER); |
| 307 | 323 | ||
| 308 | /* NOTE: assign_sock consumes our sk reference */ | 324 | /* NOTE: assign_sock consumes our sk reference */ |
| 309 | if (sk && nf_tproxy_assign_sock(skb, sk)) { | 325 | if (sk && tproxy_sk_is_transparent(sk)) { |
| 310 | /* This should be in a separate target, but we don't do multiple | 326 | /* This should be in a separate target, but we don't do multiple |
| 311 | targets on the same rule yet */ | 327 | targets on the same rule yet */ |
| 312 | skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; | 328 | skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; |
| @@ -314,6 +330,8 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 314 | pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", | 330 | pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n", |
| 315 | tproto, &iph->saddr, ntohs(hp->source), | 331 | tproto, &iph->saddr, ntohs(hp->source), |
| 316 | laddr, ntohs(lport), skb->mark); | 332 | laddr, ntohs(lport), skb->mark); |
| 333 | |||
| 334 | nf_tproxy_assign_sock(skb, sk); | ||
| 317 | return NF_ACCEPT; | 335 | return NF_ACCEPT; |
| 318 | } | 336 | } |
| 319 | 337 | ||
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 00d6ae838303..9cc46356b577 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c | |||
| @@ -35,6 +35,15 @@ | |||
| 35 | #include <net/netfilter/nf_conntrack.h> | 35 | #include <net/netfilter/nf_conntrack.h> |
| 36 | #endif | 36 | #endif |
| 37 | 37 | ||
| 38 | static void | ||
| 39 | xt_socket_put_sk(struct sock *sk) | ||
| 40 | { | ||
| 41 | if (sk->sk_state == TCP_TIME_WAIT) | ||
| 42 | inet_twsk_put(inet_twsk(sk)); | ||
| 43 | else | ||
| 44 | sock_put(sk); | ||
| 45 | } | ||
| 46 | |||
| 38 | static int | 47 | static int |
| 39 | extract_icmp4_fields(const struct sk_buff *skb, | 48 | extract_icmp4_fields(const struct sk_buff *skb, |
| 40 | u8 *protocol, | 49 | u8 *protocol, |
| @@ -164,7 +173,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, | |||
| 164 | (sk->sk_state == TCP_TIME_WAIT && | 173 | (sk->sk_state == TCP_TIME_WAIT && |
| 165 | inet_twsk(sk)->tw_transparent)); | 174 | inet_twsk(sk)->tw_transparent)); |
| 166 | 175 | ||
| 167 | nf_tproxy_put_sock(sk); | 176 | xt_socket_put_sk(sk); |
| 168 | 177 | ||
| 169 | if (wildcard || !transparent) | 178 | if (wildcard || !transparent) |
| 170 | sk = NULL; | 179 | sk = NULL; |
| @@ -298,7 +307,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par) | |||
| 298 | (sk->sk_state == TCP_TIME_WAIT && | 307 | (sk->sk_state == TCP_TIME_WAIT && |
| 299 | inet_twsk(sk)->tw_transparent)); | 308 | inet_twsk(sk)->tw_transparent)); |
| 300 | 309 | ||
| 301 | nf_tproxy_put_sock(sk); | 310 | xt_socket_put_sk(sk); |
| 302 | 311 | ||
| 303 | if (wildcard || !transparent) | 312 | if (wildcard || !transparent) |
| 304 | sk = NULL; | 313 | sk = NULL; |
