All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ipsec] xfrm: do unconditional template resolution before pcpu cache check
@ 2017-11-02 15:46 Florian Westphal
  2017-11-02 22:57 ` Paul Moore
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Westphal @ 2017-11-02 15:46 UTC (permalink / raw)
  To: netdev; +Cc: sds, steffen.klassert, Florian Westphal, Paul Moore

Stephen Smalley says:
 Since 4.14-rc1, the selinux-testsuite has been encountering sporadic
 failures during testing of labeled IPSEC. git bisect pointed to
 commit ec30d ("xfrm: add xdst pcpu cache").
 The xdst pcpu cache is only checking that the policies are the same,
 but does not validate that the policy, state, and flow match with respect
 to security context labeling.
 As a result, the wrong SA could be used and the receiver could end up
 performing permission checking and providing SO_PEERSEC or SCM_SECURITY
 values for the wrong security context.

This fix makes it so that we always do the template resolution, and
then checks that the found states match those in the pcpu bundle.

This has the disadvantage of doing a bit more work (lookup in state hash
table) if we can reuse the xdst entry (we only avoid xdst alloc/free)
but we don't add a lot of extra work in case we can't reuse.

xfrm_pol_dead() check is removed, reasoning is that
xfrm_tmpl_resolve does all needed checks.

Cc: Paul Moore <paul@paul-moore.com>
Fixes: ec30d78c14a813db39a647b6a348b428 ("xfrm: add xdst pcpu cache")
Reported-by: Stephen Smalley <sds@tycho.nsa.gov>
Tested-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/xfrm/xfrm_policy.c | 42 ++++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 18 deletions(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 8cafb3c0a4ac..a2e531bf4f97 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1787,19 +1787,23 @@ void xfrm_policy_cache_flush(void)
 	put_online_cpus();
 }
 
-static bool xfrm_pol_dead(struct xfrm_dst *xdst)
+static bool xfrm_xdst_can_reuse(struct xfrm_dst *xdst,
+				struct xfrm_state * const xfrm[],
+				int num)
 {
-	unsigned int num_pols = xdst->num_pols;
-	unsigned int pol_dead = 0, i;
+	const struct dst_entry *dst = &xdst->u.dst;
+	int i;
 
-	for (i = 0; i < num_pols; i++)
-		pol_dead |= xdst->pols[i]->walk.dead;
+	if (xdst->num_xfrms != num)
+		return false;
 
-	/* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
-	if (pol_dead)
-		xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
+	for (i = 0; i < num; i++) {
+		if (!dst || dst->xfrm != xfrm[i])
+			return false;
+		dst = dst->child;
+	}
 
-	return pol_dead;
+	return xfrm_bundle_ok(xdst);
 }
 
 static struct xfrm_dst *
@@ -1813,26 +1817,28 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
 	struct dst_entry *dst;
 	int err;
 
+	/* Try to instantiate a bundle */
+	err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
+	if (err <= 0) {
+		if (err != 0 && err != -EAGAIN)
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+		return ERR_PTR(err);
+	}
+
 	xdst = this_cpu_read(xfrm_last_dst);
 	if (xdst &&
 	    xdst->u.dst.dev == dst_orig->dev &&
 	    xdst->num_pols == num_pols &&
-	    !xfrm_pol_dead(xdst) &&
 	    memcmp(xdst->pols, pols,
 		   sizeof(struct xfrm_policy *) * num_pols) == 0 &&
-	    xfrm_bundle_ok(xdst)) {
+	    xfrm_xdst_can_reuse(xdst, xfrm, err)) {
 		dst_hold(&xdst->u.dst);
+		while (err > 0)
+			xfrm_state_put(xfrm[--err]);
 		return xdst;
 	}
 
 	old = xdst;
-	/* Try to instantiate a bundle */
-	err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
-	if (err <= 0) {
-		if (err != 0 && err != -EAGAIN)
-			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
-		return ERR_PTR(err);
-	}
 
 	dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
 	if (IS_ERR(dst)) {
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] xfrm: do unconditional template resolution before pcpu cache check
  2017-11-02 15:46 [PATCH ipsec] xfrm: do unconditional template resolution before pcpu cache check Florian Westphal
@ 2017-11-02 22:57 ` Paul Moore
  2017-11-03  9:27   ` Steffen Klassert
  0 siblings, 1 reply; 5+ messages in thread
From: Paul Moore @ 2017-11-02 22:57 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netdev, Stephen Smalley, steffen.klassert

On Thu, Nov 2, 2017 at 11:46 AM, Florian Westphal <fw@strlen.de> wrote:
> Stephen Smalley says:
>  Since 4.14-rc1, the selinux-testsuite has been encountering sporadic
>  failures during testing of labeled IPSEC. git bisect pointed to
>  commit ec30d ("xfrm: add xdst pcpu cache").
>  The xdst pcpu cache is only checking that the policies are the same,
>  but does not validate that the policy, state, and flow match with respect
>  to security context labeling.
>  As a result, the wrong SA could be used and the receiver could end up
>  performing permission checking and providing SO_PEERSEC or SCM_SECURITY
>  values for the wrong security context.
>
> This fix makes it so that we always do the template resolution, and
> then checks that the found states match those in the pcpu bundle.
>
> This has the disadvantage of doing a bit more work (lookup in state hash
> table) if we can reuse the xdst entry (we only avoid xdst alloc/free)
> but we don't add a lot of extra work in case we can't reuse.
>
> xfrm_pol_dead() check is removed, reasoning is that
> xfrm_tmpl_resolve does all needed checks.
>
> Cc: Paul Moore <paul@paul-moore.com>
> Fixes: ec30d78c14a813db39a647b6a348b428 ("xfrm: add xdst pcpu cache")
> Reported-by: Stephen Smalley <sds@tycho.nsa.gov>
> Tested-by: Stephen Smalley <sds@tycho.nsa.gov>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
>  net/xfrm/xfrm_policy.c | 42 ++++++++++++++++++++++++------------------
>  1 file changed, 24 insertions(+), 18 deletions(-)

This looks reasonable and seems like probably the simplest approach to
me.  I'm building a test kernel with it now, but considering the time
of day here, I probably will not be able to test it until tomorrow
morning; however it is important to note that Stephen did test this
already so please don't wait on my test results - we are likely to be
running the same tests anyway.

Acked-by: Paul Moore <paul@paul-moore.com>

> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 8cafb3c0a4ac..a2e531bf4f97 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -1787,19 +1787,23 @@ void xfrm_policy_cache_flush(void)
>         put_online_cpus();
>  }
>
> -static bool xfrm_pol_dead(struct xfrm_dst *xdst)
> +static bool xfrm_xdst_can_reuse(struct xfrm_dst *xdst,
> +                               struct xfrm_state * const xfrm[],
> +                               int num)
>  {
> -       unsigned int num_pols = xdst->num_pols;
> -       unsigned int pol_dead = 0, i;
> +       const struct dst_entry *dst = &xdst->u.dst;
> +       int i;
>
> -       for (i = 0; i < num_pols; i++)
> -               pol_dead |= xdst->pols[i]->walk.dead;
> +       if (xdst->num_xfrms != num)
> +               return false;
>
> -       /* Mark DST_OBSOLETE_DEAD to fail the next xfrm_dst_check() */
> -       if (pol_dead)
> -               xdst->u.dst.obsolete = DST_OBSOLETE_DEAD;
> +       for (i = 0; i < num; i++) {
> +               if (!dst || dst->xfrm != xfrm[i])
> +                       return false;
> +               dst = dst->child;
> +       }
>
> -       return pol_dead;
> +       return xfrm_bundle_ok(xdst);
>  }
>
>  static struct xfrm_dst *
> @@ -1813,26 +1817,28 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
>         struct dst_entry *dst;
>         int err;
>
> +       /* Try to instantiate a bundle */
> +       err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
> +       if (err <= 0) {
> +               if (err != 0 && err != -EAGAIN)
> +                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
> +               return ERR_PTR(err);
> +       }
> +
>         xdst = this_cpu_read(xfrm_last_dst);
>         if (xdst &&
>             xdst->u.dst.dev == dst_orig->dev &&
>             xdst->num_pols == num_pols &&
> -           !xfrm_pol_dead(xdst) &&
>             memcmp(xdst->pols, pols,
>                    sizeof(struct xfrm_policy *) * num_pols) == 0 &&
> -           xfrm_bundle_ok(xdst)) {
> +           xfrm_xdst_can_reuse(xdst, xfrm, err)) {
>                 dst_hold(&xdst->u.dst);
> +               while (err > 0)
> +                       xfrm_state_put(xfrm[--err]);
>                 return xdst;
>         }
>
>         old = xdst;
> -       /* Try to instantiate a bundle */
> -       err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
> -       if (err <= 0) {
> -               if (err != 0 && err != -EAGAIN)
> -                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
> -               return ERR_PTR(err);
> -       }
>
>         dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
>         if (IS_ERR(dst)) {
> --
> 2.13.6
>



-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH ipsec] xfrm: do unconditional template resolution before pcpu cache check
  2017-11-02 22:57 ` Paul Moore
@ 2017-11-03  9:27   ` Steffen Klassert
  2017-11-14 20:46     ` [regression, 4.14] xfrm: Fix stack-out-of-bounds read in xfrm_state_find breaks selinux-testsuite Stephen Smalley
  0 siblings, 1 reply; 5+ messages in thread
From: Steffen Klassert @ 2017-11-03  9:27 UTC (permalink / raw)
  To: Paul Moore; +Cc: Florian Westphal, netdev, Stephen Smalley

On Thu, Nov 02, 2017 at 06:57:29PM -0400, Paul Moore wrote:
> On Thu, Nov 2, 2017 at 11:46 AM, Florian Westphal <fw@strlen.de> wrote:
> > Stephen Smalley says:
> >  Since 4.14-rc1, the selinux-testsuite has been encountering sporadic
> >  failures during testing of labeled IPSEC. git bisect pointed to
> >  commit ec30d ("xfrm: add xdst pcpu cache").
> >  The xdst pcpu cache is only checking that the policies are the same,
> >  but does not validate that the policy, state, and flow match with respect
> >  to security context labeling.
> >  As a result, the wrong SA could be used and the receiver could end up
> >  performing permission checking and providing SO_PEERSEC or SCM_SECURITY
> >  values for the wrong security context.
> >
> > This fix makes it so that we always do the template resolution, and
> > then checks that the found states match those in the pcpu bundle.
> >
> > This has the disadvantage of doing a bit more work (lookup in state hash
> > table) if we can reuse the xdst entry (we only avoid xdst alloc/free)
> > but we don't add a lot of extra work in case we can't reuse.
> >
> > xfrm_pol_dead() check is removed, reasoning is that
> > xfrm_tmpl_resolve does all needed checks.
> >
> > Cc: Paul Moore <paul@paul-moore.com>
> > Fixes: ec30d78c14a813db39a647b6a348b428 ("xfrm: add xdst pcpu cache")
> > Reported-by: Stephen Smalley <sds@tycho.nsa.gov>
> > Tested-by: Stephen Smalley <sds@tycho.nsa.gov>
> > Signed-off-by: Florian Westphal <fw@strlen.de>
> > ---
> >  net/xfrm/xfrm_policy.c | 42 ++++++++++++++++++++++++------------------
> >  1 file changed, 24 insertions(+), 18 deletions(-)
> 
> This looks reasonable and seems like probably the simplest approach to
> me.  I'm building a test kernel with it now, but considering the time
> of day here, I probably will not be able to test it until tomorrow
> morning; however it is important to note that Stephen did test this
> already so please don't wait on my test results - we are likely to be
> running the same tests anyway.
> 
> Acked-by: Paul Moore <paul@paul-moore.com>

Patch applied, thanks everyone!

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [regression, 4.14] xfrm: Fix stack-out-of-bounds read in xfrm_state_find breaks selinux-testsuite
  2017-11-03  9:27   ` Steffen Klassert
@ 2017-11-14 20:46     ` Stephen Smalley
  2017-11-15  5:40       ` Steffen Klassert
  0 siblings, 1 reply; 5+ messages in thread
From: Stephen Smalley @ 2017-11-14 20:46 UTC (permalink / raw)
  To: Steffen Klassert, Paul Moore; +Cc: Florian Westphal, netdev

Hi,

4.14 is failing the selinux-testsuite labeled IPSEC tests despite
having just been fixed in commit cf37966751747727 ("xfrm: do
unconditional template resolution before pcpu cache check").  The
breaking commit is the very next one, commit c9f3f813d462c72d ("xfrm:
Fix stack-out-of-bounds read in xfrm_state_find.").  Unlike the earlier
breakage, which caused use of the wrong SA, this one leads to a failure
on connect(). Running ip xfrm monitor during one of the failing tests
shows the following:
acquire proto ah 
  sel src 127.0.0.1/32 dst 127.0.0.1/32 proto tcp sport 0 dport 65535
dev lo 
  policy src 127.0.0.1/32 dst 127.0.0.1/32 proto tcp 
        security context
unconfined_u:unconfined_r:test_inet_client_t:s0-s0:c0.c1023 
        dir out priority 0 ptype main 
        tmpl src 0.0.0.0 dst 0.0.0.0
                proto ah reqid 0 mode transport

Expired src 127.0.0.1 dst 0.0.0.0
        proto ah spi 0x00000000 reqid 0 mode transport
        replay-window 0 
        sel src 127.0.0.1/32 dst 127.0.0.1/32 proto tcp sport 0 dport
65535 dev lo 
        hard 1

On the last working commit, connect() instead succeeds and ip xfrm
monitor shows the following:
Async event  (0x20)  timer expired 
	src 127.0.0.1 dst 127.0.0.1  reqid 0x0 protocol ah  SPI 0x200
Async event  (0x10)  replay update 
	src 127.0.0.1 dst 127.0.0.1  reqid 0x0 protocol ah  SPI 0x200
Async event  (0x10)  replay update 
	src 127.0.0.1 dst 127.0.0.1  reqid 0x0 protocol ah  SPI 0x200

Reproducer:
# Install a Fedora VM w/ SELinux enabled (default).
$ git clone https://github.com/SELinuxProject/selinux-testsuite/
# Make sure you have the requisite kernel config options enabled.
$ cd linux
$ ./scripts/kconfig/merge_config.sh .config ../selinux-
testsuite/defconfig
$ make
$ sudo make modules_install install
$ sudo reboot
# Install dependencies.
sudo dnf install perl-Test perl-Test-Harness perl-Test-Simple selinux-
policy-devel gcc libselinux-devel net-tools netlabel_tools iptables
# Build and run the tests
sudo make test

After running once as above, you can run just the inet socket tests
again via:
cd tests/inet_socket
./test

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [regression, 4.14] xfrm: Fix stack-out-of-bounds read in xfrm_state_find breaks selinux-testsuite
  2017-11-14 20:46     ` [regression, 4.14] xfrm: Fix stack-out-of-bounds read in xfrm_state_find breaks selinux-testsuite Stephen Smalley
@ 2017-11-15  5:40       ` Steffen Klassert
  0 siblings, 0 replies; 5+ messages in thread
From: Steffen Klassert @ 2017-11-15  5:40 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: Paul Moore, Florian Westphal, netdev

On Tue, Nov 14, 2017 at 03:46:30PM -0500, Stephen Smalley wrote:
> Hi,
> 
> 4.14 is failing the selinux-testsuite labeled IPSEC tests despite
> having just been fixed in commit cf37966751747727 ("xfrm: do
> unconditional template resolution before pcpu cache check").  The
> breaking commit is the very next one, commit c9f3f813d462c72d ("xfrm:
> Fix stack-out-of-bounds read in xfrm_state_find.").  Unlike the earlier
> breakage, which caused use of the wrong SA, this one leads to a failure
> on connect(). Running ip xfrm monitor during one of the failing tests
> shows the following:
> acquire proto ah 
>   sel src 127.0.0.1/32 dst 127.0.0.1/32 proto tcp sport 0 dport 65535
> dev lo 
>   policy src 127.0.0.1/32 dst 127.0.0.1/32 proto tcp 
>         security context
> unconfined_u:unconfined_r:test_inet_client_t:s0-s0:c0.c1023 
>         dir out priority 0 ptype main 
>         tmpl src 0.0.0.0 dst 0.0.0.0
>                 proto ah reqid 0 mode transport

Yes, I see. This is because there are wildcard src and dst
addresses on the template. I'll revert this one for now.

I slowly start to think that the concept of having a socket
policy on a IPv6 socket that maps to IPv4 is fundamentally
broken. The bug I tried to fix here is not the first one
that were reported from syzkaller for this szenario and I
fear it is not the last one.

Thanks for reporting this!

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-11-15  5:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-02 15:46 [PATCH ipsec] xfrm: do unconditional template resolution before pcpu cache check Florian Westphal
2017-11-02 22:57 ` Paul Moore
2017-11-03  9:27   ` Steffen Klassert
2017-11-14 20:46     ` [regression, 4.14] xfrm: Fix stack-out-of-bounds read in xfrm_state_find breaks selinux-testsuite Stephen Smalley
2017-11-15  5:40       ` Steffen Klassert

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.