pull request (net): ipsec 2018-10-01
Subsystems (3)
Steffen Klassert
maintainer1) Validate address prefix lengths in the xfrm selector, otherwise we may hit undefined behaviour in the address matching functions if the prefix is too big for the given address family.
2) Fix skb leak on local message size errors.
From Thadeu Lima de Souza Cascardo.
3) We currently reset the transport header back to the network header after a transport mode transformation is applied. This leads to an incorrect transport header when multiple transport mode transformations are applied. Reset the transport header only after all transformations are already applied to fix this. From Sowmini Varadhan.
4) We only support one offloaded xfrm, so reset crypto_done after the first transformation in xfrm_input(). Otherwise we may call the wrong input method for subsequent transformations. From Sowmini Varadhan.
5) Fix NULL pointer dereference when skb_dst_force clears the dst_entry. skb_dst_force does not really force a dst refcount anymore, it might clear it instead. xfrm code did not expect this, add a check to not dereference skb_dst() if it was cleared by skb_dst_force.
6) Validate xfrm template mode, otherwise we can get a stack-out-of-bounds read in xfrm_state_find. From Sean Tranchetti.
Please pull or let me know if there are problems.
Thanks!
The following changes since commit 25432eba9cd8f2ef5afef55be811b010a004b5fa:
openvswitch: meter: Fix setting meter id for new entries (2018-07-29 13:20:54 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git master
for you to fetch changes up to 32bf94fb5c2ec4ec842152d0e5937cd4bb6738fa:
xfrm: validate template mode (2018-09-20 08:30:42 +0200)
----------------------------------------------------------------
Sean Tranchetti (1):
xfrm: validate template mode
Sowmini Varadhan (2):
xfrm: reset transport header back to network header after all input transforms ahave been applied
xfrm: reset crypto_done when iterating over multiple input xfrms
Steffen Klassert (2):
xfrm: Validate address prefix lengths in the xfrm selector.
xfrm: Fix NULL pointer dereference when skb_dst_force clears the dst_entry.
Thadeu Lima de Souza Cascardo (1):
xfrm6: call kfree_skb when skb is toobig
net/ipv4/xfrm4_input.c | 1 + net/ipv4/xfrm4_mode_transport.c | 4 +--- net/ipv6/xfrm6_input.c | 1 + net/ipv6/xfrm6_mode_transport.c | 4 +--- net/ipv6/xfrm6_output.c | 2 ++ net/xfrm/xfrm_input.c | 1 + net/xfrm/xfrm_output.c | 4 ++++ net/xfrm/xfrm_policy.c | 4 ++++ net/xfrm/xfrm_user.c | 15 +++++++++++++++ 9 files changed, 30 insertions(+), 6 deletions(-)
Steffen Klassert
maintainerPATCH 1/6 xfrm: Validate address prefix lengths in the xfrm selector.
We don't validate the address prefix lengths in the xfrm selector we got from userspace. This can lead to undefined behaviour in the address matching functions if the prefix is too big for the given address family. Fix this by checking the prefixes and refuse SA/policy insertation when a prefix is invalid.
--- net/xfrm/xfrm_user.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
net/xfrm/xfrm_user.c +12 -0
@@ -151,10 +151,16 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, err = -EINVAL ;switch (p->family) {case AF_INET : +if (p->sel.prefixlen_d >32 || p->sel.prefixlen_s >32 ) + goto out; +break ;case AF_INET6 :#if IS_ENABLED (CONFIG_IPV6 ) +if (p->sel.prefixlen_d >128 || p->sel.prefixlen_s >128 ) + goto out; +break ;#else err = -EAFNOSUPPORT ;
@@ -1359,10 +1365,16 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)switch (p->sel.family) {case AF_INET : +if (p->sel.prefixlen_d >32 || p->sel.prefixlen_s >32 ) +return -EINVAL ; +break ;case AF_INET6 :#if IS_ENABLED (CONFIG_IPV6 ) +if (p->sel.prefixlen_d >128 || p->sel.prefixlen_s >128 ) +return -EINVAL ; +break ;#else return -EAFNOSUPPORT ;
Signature · 1 line
2.17.1
Steffen Klassert
maintainerPATCH 2/6 xfrm6: call kfree_skb when skb is toobig
In reply to Steffen KlassertFrom: Thadeu Lima de Souza Cascardo <[email protected]>
After commit d6990976af7c5d8f55903bfb4289b6fb030bf754 ("vti6: fix PMTU caching and reporting on xmit"), some too big skbs might be potentially passed down to __xfrm6_output, causing it to fail to transmit but not free the skb, causing a leak of skb, and consequentially a leak of dst references.
After running pmtu.sh, that shows as failure to unregister devices in a namespace:
[ 311.397671] unregister_netdevice: waiting for veth_b to become free. Usage count = 1
The fix is to call kfree_skb in case of transmit failures.
--- net/ipv6/xfrm6_output.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/xfrm6_output.c +2 -0
@@ -170,9 +170,11 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)if (toobig &&xfrm6_local_dontfrag (skb)) {xfrm6_local_rxpmtu (skb, mtu); +kfree_skb (skb);return -EMSGSIZE ; }else if (!skb->ignore_df && toobig && skb->sk) {xfrm_local_error (skb, mtu); +kfree_skb (skb);return -EMSGSIZE ; }
Signature · 1 line
2.17.1
Steffen Klassert
maintainerPATCH 3/6 xfrm: reset transport header back to network header after all input transforms ahave been applied
In reply to Steffen KlassertFrom: Sowmini Varadhan <[email protected]>
A policy may have been set up with multiple transforms (e.g., ESP and ipcomp). In this situation, the ingress IPsec processing iterates in xfrm_input() and applies each transform in turn, processing the nexthdr to find any additional xfrm that may apply.
This patch resets the transport header back to network header only after the last transformation so that subsequent xfrms can find the correct transport header.
--- net/ipv4/xfrm4_input.c | 1 + net/ipv4/xfrm4_mode_transport.c | 4 +--- net/ipv6/xfrm6_input.c | 1 + net/ipv6/xfrm6_mode_transport.c | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-)
net/ipv4/xfrm4_input.c +1 -0
@@ -67,6 +67,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)if (xo && (xo->flags &XFRM_GRO )) {skb_mac_header_rebuild (skb); +skb_reset_transport_header (skb);return 0 ; }
net/ipv4/xfrm4_mode_transport.c +1 -3
@@ -46,7 +46,6 @@ static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)static int xfrm4_transport_input (struct xfrm_state *x,struct sk_buff *skb) {int ihl = skb->data -skb_transport_header (skb); -struct xfrm_offload *xo =xfrm_offload (skb);if (skb->transport_header != skb->network_header) { memmove(skb_transport_header(skb),
@@ -54,8 +53,7 @@ static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) skb->network_header = skb->transport_header; }ip_hdr (skb)->tot_len =htons (skb->len + ihl); -if (!xo || !(xo->flags &XFRM_GRO )) -skb_reset_transport_header (skb); +skb_reset_transport_header (skb);return 0 ; }
net/ipv6/xfrm6_input.c +1 -0
@@ -59,6 +59,7 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)if (xo && (xo->flags &XFRM_GRO )) {skb_mac_header_rebuild (skb); +skb_reset_transport_header (skb);return -1 ; }
net/ipv6/xfrm6_mode_transport.c +1 -3
@@ -51,7 +51,6 @@ static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)static int xfrm6_transport_input (struct xfrm_state *x,struct sk_buff *skb) {int ihl = skb->data -skb_transport_header (skb); -struct xfrm_offload *xo =xfrm_offload (skb);if (skb->transport_header != skb->network_header) { memmove(skb_transport_header(skb),
@@ -60,8 +59,7 @@ static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) }ipv6_hdr (skb)->payload_len =htons (skb->len + ihl -sizeof (struct ipv6hdr )); -if (!xo || !(xo->flags &XFRM_GRO )) -skb_reset_transport_header (skb); +skb_reset_transport_header (skb);return 0 ; }
Signature · 1 line
2.17.1
Steffen Klassert
maintainerPATCH 4/6 xfrm: reset crypto_done when iterating over multiple input xfrms
In reply to Steffen KlassertFrom: Sowmini Varadhan <[email protected]>
We only support one offloaded xfrm (we do not have devices that can handle more than one offload), so reset crypto_done in xfrm_input() when iterating over multiple transforms in xfrm_input, so that we can invoke the appropriate x->type->input for the non-offloaded transforms
--- net/xfrm/xfrm_input.c | 1 + 1 file changed, 1 insertion(+)
net/xfrm/xfrm_input.c +1 -0
@@ -453,6 +453,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)XFRM_INC_STATS (net,LINUX_MIB_XFRMINHDRERROR ); goto drop; } + crypto_done = false; }while (!err); err =xfrm_rcv_cb (skb, family, x->type->proto,0 );
Signature · 1 line
2.17.1
Steffen Klassert
maintainerPATCH 5/6 xfrm: Fix NULL pointer dereference when skb_dst_force clears the dst_entry.
In reply to Steffen KlassertSince commit 222d7dbd258d ("net: prevent dst uses after free") skb_dst_force() might clear the dst_entry attached to the skb. The xfrm code don't expect this to happen, so we crash with a NULL pointer dereference in this case. Fix it by checking skb_dst(skb) for NULL after skb_dst_force() and drop the packet in cast the dst_entry was cleared.
--- net/xfrm/xfrm_output.c | 4 ++++ net/xfrm/xfrm_policy.c | 4 ++++ 2 files changed, 8 insertions(+)
net/xfrm/xfrm_output.c +4 -0
@@ -101,6 +101,10 @@ static int xfrm_output_one(struct sk_buff *skb, int err)spin_unlock_bh (&x->lock);skb_dst_force (skb); +if (!skb_dst (skb)) { +XFRM_INC_STATS (net,LINUX_MIB_XFRMOUTERROR ); + goto error_nolock; + }if (xfrm_offload (skb)) { x->type_offload->encap (x, skb);
net/xfrm/xfrm_policy.c +4 -0
@@ -2548,6 +2548,10 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) }skb_dst_force (skb); +if (!skb_dst (skb)) { +XFRM_INC_STATS (net,LINUX_MIB_XFRMFWDHDRERROR ); +return 0 ; + } dst =xfrm_lookup (net,skb_dst (skb), &fl,NULL ,XFRM_LOOKUP_QUEUE );if (IS_ERR (dst)) {
Signature · 1 line
2.17.1
Re: [PATCH 5/6] xfrm: Fix NULL pointer dereference when skb_dst_force clears the dst_entry.
Quoted 3 lines · Steffen Klassert
Since commit
222d7dbd258d("net: prevent dst uses after free")skb_dst_force()might clear thedst_entryattached to the skb. The xfrm code don't expect this to happen, so we crash with
Doesn't.
Quoted 3 lines
a NULL pointer dereference in this case. Fix it by checking
skb_dst(skb)for NULL afterskb_dst_force()and drop the packet in cast thedst_entrywas cleared.
In case?
Quoted 5 lines
Fixes 222d7dbd258d ("net: prevent dst uses after free")Reported-by Tobias Hommel <[email protected]>Reported-by Kristian Evensen <[email protected]>Reported-by Wolfgang Walter <[email protected]>Signed-off-by Steffen Klassert <[email protected]>
[...]
MBR, Sergei
Steffen Klassert
maintainerPATCH 6/6 xfrm: validate template mode
In reply to Steffen KlassertFrom: Sean Tranchetti <[email protected]>
XFRM mode parameters passed as part of the user templates in the IP_XFRM_POLICY are never properly validated. Passing values other than valid XFRM modes can cause stack-out-of-bounds reads to occur later in the XFRM processing:
[ 140.535608] ================================================================ [ 140.543058] BUG: KASAN: stack-out-of-bounds in xfrm_state_find+0x17e4/0x1cc4 [ 140.550306] Read of size 4 at addr ffffffc0238a7a58 by task repro/5148 [ 140.557369] [ 140.558927] Call trace: [ 140.558936] dump_backtrace+0x0/0x388 [ 140.558940] show_stack+0x24/0x30 [ 140.558946] __dump_stack+0x24/0x2c [ 140.558949] dump_stack+0x8c/0xd0 [ 140.558956] print_address_description+0x74/0x234 [ 140.558960] kasan_report+0x240/0x264 [ 140.558963] __asan_report_load4_noabort+0x2c/0x38 [ 140.558967] xfrm_state_find+0x17e4/0x1cc4 [ 140.558971] xfrm_resolve_and_create_bundle+0x40c/0x1fb8 [ 140.558975] xfrm_lookup+0x238/0x1444 [ 140.558977] xfrm_lookup_route+0x48/0x11c [ 140.558984] ip_route_output_flow+0x88/0xc4 [ 140.558991] raw_sendmsg+0xa74/0x266c [ 140.558996] inet_sendmsg+0x258/0x3b0 [ 140.559002] sock_sendmsg+0xbc/0xec [ 140.559005] SyS_sendto+0x3a8/0x5a8 [ 140.559008] el0_svc_naked+0x34/0x38 [ 140.559009] [ 140.592245] page dumped because: kasan: bad access detected [ 140.597981] page_owner info is not active (free page?) [ 140.603267] [ 140.653503] ================================================================
--- net/xfrm/xfrm_user.c | 3 +++ 1 file changed, 3 insertions(+)
net/xfrm/xfrm_user.c +3 -0
@@ -1455,6 +1455,9 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) (ut[i].family != prev_family))return -EINVAL ; +if (ut[i].mode >=XFRM_MODE_MAX ) +return -EINVAL ; + prev_family = ut[i].family;switch (ut[i].family) {
Signature · 1 line
2.17.1
David Miller
maintainerFrom: Steffen Klassert <[email protected]>
Date: Mon, 1 Oct 2018 10:58:49 +0200
Quoted 25 lines
1) Validate address prefix lengths in the xfrm selector, otherwise we may hit undefined behaviour in the address matching functions if the prefix is too big for the given address family.
2) Fix skb leak on local message size errors.
From Thadeu Lima de Souza Cascardo.3) We currently reset the transport header back to the network header after a transport mode transformation is applied. This leads to an incorrect transport header when multiple transport mode transformations are applied. Reset the transport header only after all transformations are already applied to fix this. From Sowmini Varadhan.
4) We only support one offloaded xfrm, so reset
crypto_doneafter the first transformation inxfrm_input(). Otherwise we may call the wrong input method for subsequent transformations. From Sowmini Varadhan.5) Fix NULL pointer dereference when
skb_dst_forceclears thedst_entry.skb_dst_forcedoes not really force a dst refcount anymore, it might clear it instead. xfrm code did not expect this, add a check to not dereferenceskb_dst()if it was cleared byskb_dst_force.
Quoted 4 lines
6) Validate xfrm template mode, otherwise we can get a stack-out-of-bounds read in
xfrm_state_find. From Sean Tranchetti.Please pull or let me know if there are problems.
Pulled, thanks!