: Dst entry leak in icmp_send host re-lookup code (v2).
Subsystems (3)
PATCH 1/1 : Dst entry leak in icmp_send host re-lookup code (v2).
Commit 8b7817f3a959ed99d7443afc12f78a7e1fcc2063 ([IPSEC]: Add ICMP host relookup support) introduced some dst leaks on error paths: the rt pointer can be forgotten to be put. Fix it bu going to a proper label.
Found after net namespace's lo refused to unregister :) Many thanks to Den for valuable help during debugging.
Herbert pointed out, that xfrm_lookup() will put the rtable in case of error itself, so the first goto fix is redundant.
---
net/ipv4/icmp.c +3 -3
@@ -591,7 +591,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) }if (xfrm_decode_session_reverse (skb_in, &fl,AF_INET )) - goto out_unlock; + goto ende;if (inet_addr_type (net, fl.fl4_src) ==RTN_LOCAL ) err =__ip_route_output_key (net, &rt2, &fl);
@@ -601,7 +601,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) fl2.fl4_dst = fl.fl4_src;if (ip_route_output_key (net, &rt2, &fl2)) - goto out_unlock; + goto ende;/* Ugh! */ odst = skb_in->dst;
@@ -614,7 +614,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) }if (err) - goto out_unlock; + goto ende; err =xfrm_lookup ((struct dst_entry **)&rt2, &fl,NULL ,XFRM_LOOKUP_ICMP );
David Miller
maintainerFrom: Pavel Emelyanov <[email protected]>
Date: Wed, 26 Mar 2008 12:25:40 +0300
Quoted 4 lines
Commit
8b7817f3a959ed99d7443afc12f78a7e1fcc2063([IPSEC]: Add ICMP host relookup support) introduced some dst leaks on error paths: the rt pointer can be forgotten to be put. Fix it bu going to a proper label.
Quoted 8 lines
Found after net namespace's lo refused to unregister :) Many thanks to Den for valuable help during debugging.
Herbert pointed out, that
xfrm_lookup()will put the rtable in case of error itself, so the first goto fix is redundant.Signed-off-by Pavel Emelyanov <[email protected]>Signed-off-by Denis V. Lunev <[email protected]>
Looks good, applied, thanks!
Quoted 3 lines · Pavel Emelyanov
Commit
8b7817f3a959ed99d7443afc12f78a7e1fcc2063([IPSEC]: Add ICMP host relookup support) introduced some dst leaks on error paths: the rt pointer can be forgotten to be put. Fix it bu going to a proper label.
I just remembered that we have exactly the same code path in IPv6 and sure enough it also has the same bug.
[IPV6]: Fix ICMP relookup error path dst leak
When we encounter an error while looking up the dst the second time we need to drop the first dst. This patch is pretty much the same as the one for IPv4.
Thakns,
Signature · 5 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--net/ipv6/icmp.c +2 -2
@@ -436,10 +436,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, }if (xfrm_decode_session_reverse (skb, &fl2,AF_INET6 )) - goto out; + goto out_dst_release;if (ip6_dst_lookup (sk, &dst2, &fl)) - goto out; + goto out_dst_release; err =xfrm_lookup (&dst2, &fl, sk,XFRM_LOOKUP_ICMP );if (err == -ENOENT ) {
From: Herbert Xu <[email protected]>
Date: Tue, 1 Apr 2008 20:15:32 +0800
Quoted 8 lines · Pavel Emelyanov
Quoted 3 lines
Commit
8b7817f3a959ed99d7443afc12f78a7e1fcc2063([IPSEC]: Add ICMP host relookup support) introduced some dst leaks on error paths: the rt pointer can be forgotten to be put. Fix it bu going to a proper label.I just remembered that we have exactly the same code path in IPv6 and sure enough it also has the same bug.
Quoted 7 lines
[IPV6]: Fix ICMP relookup error path dst leak
When we encounter an error while looking up the dst the second time we need to drop the first dst. This patch is pretty much the same as the one for IPv4.
Signed-off-by Herbert Xu <[email protected]>
Applied, thanks for catching this.
Hello,
Quoted 7 lines · Herbert Xu
Quoted 3 lines · Pavel Emelyanov
Commit
8b7817f3a959ed99d7443afc12f78a7e1fcc2063([IPSEC]: Add ICMP host relookup support) introduced some dst leaks on error paths: the rt pointer can be forgotten to be put. Fix it bu going to a proper label.I just remembered that we have exactly the same code path in IPv6 and sure enough it also has the same bug.
OK, we found there was a leak, but why it happens? Initially,
I thought it was caused by saddr=0 provided to ip_route_input. Some debugging shows that in the case with forwarded skb (with attached input route) saddr is set to 0 but later xfrm_decode_session_reverse rebuilds fl with addresses from packet. So, it was not that we play with saddr=0. In my test setup with 2 interfaces ip_route_input failed because I don't have route to the original destination which is now provided as saddr to ip_route_input. No ICMP was sent to sender while previous kernels send ICMP.
As result, this new code adds some new checks that are not
valid for all cases. When kernel wants to say that destination is unreachable it can not do it. We should talk with sender without considering destination address.
May be this code should be reverted for 2.6.25 or some extra
checks should be added considering the different variants where icmp_send can be called:
- original packet is incoming, destined to localhost (rt->fl.iif!=0
and rt->rt_flags & RTCF_LOCAL) - original packet is incoming, destined to remote host (rt->fl.iif!=0 and !(rt->rt_flags & RTCF_LOCAL))
- original packet is outgoing, destined to localhost
- original packet is outgoing, destined to remote host
In my case even SNAT happened before icmp_send, soip_route_input failed for saddr=ORIGINAL_TARGET and daddr=MASQ_ADDR_WHICH_IS_LOCAL indev=MADDR_DEVICE
Regards
--
Julian Anastasov <[email protected]>
Quoted 10 lines · Julian Anastasov
OK, we found there was a leak, but why it happens? Initially,
I thought it was caused by saddr=0 provided toip_route_input. Some debugging shows that in the case with forwarded skb (with attached input route) saddr is set to 0 but laterxfrm_decode_session_reverserebuilds fl with addresses from packet. So, it was not that we play with saddr=0. In my test setup with 2 interfacesip_route_inputfailed because I don't have route to the original destination which is now provided as saddr toip_route_input. No ICMP was sent to sender while previous kernels send ICMP.
Yes this was an oversight.
[ICMP]: Ensure that ICMP relookup maintains status quo
The ICMP relookup path is only meant to modify behaviour when appropriate IPsec policies are in place and marked as requiring relookups. It is certainly not meant to modify behaviour when IPsec policies don't exist at all.
However, due to an oversight on the error paths existing behaviour may in fact change should one of the relookup steps fail.
This patch corrects this by redirecting all errors on relookup failures to the previous code path. That is, if the initial xfrm_lookup let the packet pass, we will stand by that decision should the relookup fail due to an error.
This should be safe from a security point-of-view because compliant systems must install a default deny policy so the packet would'nt have passed in that case.
Many thanks to Julian Anastasov for pointing out this error.
Cheers,
Signature · 5 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--net/ipv4/icmp.c +13 -11
@@ -591,7 +591,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) }if (xfrm_decode_session_reverse (skb_in, &fl,AF_INET )) - goto ende; + goto relookup_failed;if (inet_addr_type (net, fl.fl4_src) ==RTN_LOCAL ) err =__ip_route_output_key (net, &rt2, &fl);
@@ -601,7 +601,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) fl2.fl4_dst = fl.fl4_src;if (ip_route_output_key (net, &rt2, &fl2)) - goto ende; + goto relookup_failed;/* Ugh! */ odst = skb_in->dst;
@@ -614,21 +614,23 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) }if (err) - goto ende; + goto relookup_failed; err =xfrm_lookup ((struct dst_entry **)&rt2, &fl,NULL ,XFRM_LOOKUP_ICMP ); -if (err == -ENOENT ) { +switch (err) { +case 0 : +dst_release (&rt->u.dst); + rt = rt2; +break ; +case -EPERM : + goto ende; +default : +relookup_failed:if (!rt) goto out_unlock; - goto route_done; +break ; } - -dst_release (&rt->u.dst); - rt = rt2; - -if (err) - goto out_unlock; } route_done:
net/ipv6/icmp.c +12 -10
@@ -436,24 +436,26 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, }if (xfrm_decode_session_reverse (skb, &fl2,AF_INET6 )) - goto out_dst_release; + goto relookup_failed;if (ip6_dst_lookup (sk, &dst2, &fl)) - goto out_dst_release; + goto relookup_failed; err =xfrm_lookup (&dst2, &fl, sk,XFRM_LOOKUP_ICMP ); -if (err == -ENOENT ) { +switch (err) { +case 0 : +dst_release (dst); + dst = dst2; +break ; +case -EPERM : + goto out_dst_release; +default : +relookup_failed:if (!dst) goto out; - goto route_done; +break ; } -dst_release (dst); - dst = dst2; - -if (err) - goto out; - route_done:if (ipv6_addr_is_multicast (&fl.fl6_dst)) hlimit = np->mcast_hops;
Hello,
Quoted 16 lines · Herbert Xu
Quoted 5 lines · Julian Anastasov
play with saddr=0. In my test setup with 2 interfaces
ip_route_inputfailed because I don't have route to the original destination which is now provided as saddr toip_route_input. No ICMP was sent to sender while previous kernels send ICMP.Yes this was an oversight.
[ICMP]: Ensure that ICMP relookup maintains status quo
The ICMP relookup path is only meant to modify behaviour when appropriate IPsec policies are in place and marked as requiring relookups. It is certainly not meant to modify behaviour when IPsec policies don't exist at all.
Quoted 7 lines
However, due to an oversight on the error paths existing behaviour may in fact change should one of the relookup steps fail.
This patch corrects this by redirecting all errors on relookup failures to the previous code path. That is, if the initial
xfrm_lookuplet the packet pass, we will stand by that decision should the relookup fail due to an error.
I tested this fix and now ICMP error is sent correctly.
There is mistake in my previous email, I said there is no route but I have route to my destination, only that ARP resolution fails (after SNAT which makes the things more funny) and ICMP host unreachable error should be sent. But it does not matter much, only that NAT can confuse these xfrm calls but this is out of my knowledge.
Regards
--
Julian Anastasov <[email protected]>
From: Herbert Xu <[email protected]>
Date: Wed, 2 Apr 2008 20:40:24 +0800
Quoted 15 lines
[ICMP]: Ensure that ICMP relookup maintains status quo
The ICMP relookup path is only meant to modify behaviour when appropriate IPsec policies are in place and marked as requiring relookups. It is certainly not meant to modify behaviour when IPsec policies don't exist at all.
However, due to an oversight on the error paths existing behaviour may in fact change should one of the relookup steps fail.
This patch corrects this by redirecting all errors on relookup failures to the previous code path. That is, if the initial
xfrm_lookuplet the packet pass, we will stand by that decision should the relookup fail due to an error.
Quoted 7 lines
This should be safe from a security point-of-view because compliant systems must install a default deny policy so the packet would'nt have passed in that case.
Many thanks to Julian Anastasov for pointing out this error.
Signed-off-by Herbert Xu <[email protected]>
Applied, thanks Herbert.