1) Build fix for ip_vti when NET_IP_TUNNEL is not set.
We need this set to have ip_tunnel_get_stats64()
available.
2) Fix a NULL pointer dereference on sub policy usage.
We try to access a xfrm_state from the wrong array.
3) Take xfrm_state_lock in xfrm_migrate_state_find(),
we need it to traverse through the state lists.
4) Clone states properly on migration, otherwise we crash
when we migrate a state with aead algorithm attached.
5) Fix unlink race when between thread context and timer
when policies are deleted.
Please pull or let me know if there are problems.
Thanks!
The following changes since commit 960dfc4eb23a28495276b02604d7458e0e1a1ed8:
Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux (2014-02-18 16:36:07 -0800)
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 3a9016f97fdc8bfbb26ff36ba8f3dc9162eb691b:
xfrm: Fix unlink race when policies are deleted. (2014-02-26 09:52:02 +0100)
----------------------------------------------------------------
Steffen Klassert (5):
ip6_vti: Fix build when NET_IP_TUNNEL is not set.
xfrm: Fix NULL pointer dereference on sub policy usage
xfrm: Take xfrm_state_lock in xfrm_migrate_state_find
xfrm: Clone states properly on migration
xfrm: Fix unlink race when policies are deleted.
include/net/xfrm.h | 11 +++++++++++
net/ipv6/Kconfig | 1 +
net/xfrm/xfrm_policy.c | 2 +-
net/xfrm/xfrm_state.c | 23 +++++++++++++++++------
net/xfrm/xfrm_user.c | 5 -----
5 files changed, 30 insertions(+), 12 deletions(-)
xfrm_state_sort() takes the unsorted states from the src array
and stores them into the dst array. We try to get the namespace
from the dst array which is empty at this time, so take the
namespace from the src array instead.
Fixes: 283bc9f35bbbc ("xfrm: Namespacify xfrm state/policy locks")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_state.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Since commit 469bdcefdc47a ip6_vti uses ip_tunnel_get_stats64(),
so we need to select NET_IP_TUNNEL to have this function available.
Fixes: 469bdcefdc ("ipv6: fix the use of pcpu_tstats in ip6_vti.c")
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/ipv6/Kconfig | 1 +
1 file changed, 1 insertion(+)
When a policy is unlinked from the lists in thread context,
the xfrm timer can fire before we can mark this policy as dead.
So reinitialize the bydst hlist, then hlist_unhashed() will
notice that this policy is not linked and will avoid a
doulble unlink of that policy.
Reported-by: Xianpeng Zhao <redacted>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_policy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
A comment on xfrm_migrate_state_find() says that xfrm_state_lock
is held. This is apparently not the case, but we need it to
traverse through the state lists.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
net/xfrm/xfrm_state.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
@@ -1215,11 +1215,12 @@ out:returnNULL;}-/* net->xfrm.xfrm_state_lock is held */structxfrm_state*xfrm_migrate_state_find(structxfrm_migrate*m,structnet*net){unsignedinth;-structxfrm_state*x;+structxfrm_state*x=NULL;++spin_lock_bh(&net->xfrm.xfrm_state_lock);if(m->reqid){h=xfrm_dst_hash(net,&m->old_daddr,&m->old_saddr,
We loose a lot of information of the original state if we
clone it with xfrm_state_clone(). In particular, there is
no crypto algorithm attached if the original state uses
an aead algorithm. This patch add the missing information
to the clone state.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
include/net/xfrm.h | 11 +++++++++++
net/xfrm/xfrm_state.c | 8 ++++++++
net/xfrm/xfrm_user.c | 5 -----
3 files changed, 19 insertions(+), 5 deletions(-)
@@ -1648,6 +1648,11 @@ static inline int xfrm_aevent_is_on(struct net *net)}#endif+staticinlineintaead_len(structxfrm_algo_aead*alg)+{+returnsizeof(*alg)+((alg->alg_key_len+7)/8);+}+staticinlineintxfrm_alg_len(conststructxfrm_algo*alg){returnsizeof(*alg)+((alg->alg_key_len+7)/8);
@@ -1686,6 +1691,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x,return0;}+staticinlinestructxfrm_algo_aead*xfrm_algo_aead_clone(structxfrm_algo_aead*orig)+{+returnkmemdup(orig,aead_len(orig),GFP_KERNEL);+}++staticinlinestructxfrm_algo*xfrm_algo_clone(structxfrm_algo*orig){returnkmemdup(orig,xfrm_alg_len(orig),GFP_KERNEL);
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2014-02-27 06:27:54
On Thu, Feb 27, 2014 at 07:16:39AM +0100, Steffen Klassert wrote:
When a policy is unlinked from the lists in thread context,
the xfrm timer can fire before we can mark this policy as dead.
So reinitialize the bydst hlist, then hlist_unhashed() will
notice that this policy is not linked and will avoid a
doulble unlink of that policy.
Reported-by: Xianpeng Zhao <redacted>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2014-02-27 06:30:25
On Thu, Feb 27, 2014 at 02:27:12PM +0800, Herbert Xu wrote:
On Thu, Feb 27, 2014 at 07:16:39AM +0100, Steffen Klassert wrote:
quoted
When a policy is unlinked from the lists in thread context,
the xfrm timer can fire before we can mark this policy as dead.
So reinitialize the bydst hlist, then hlist_unhashed() will
notice that this policy is not linked and will avoid a
doulble unlink of that policy.
Reported-by: Xianpeng Zhao <redacted>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
If this race condition is real then I don't see how this fix
can be correct since there aren't any barriers between the check
and the unlink.
On Thu, Feb 27, 2014 at 02:30:15PM +0800, Herbert Xu wrote:
On Thu, Feb 27, 2014 at 02:27:12PM +0800, Herbert Xu wrote:
quoted
On Thu, Feb 27, 2014 at 07:16:39AM +0100, Steffen Klassert wrote:
quoted
When a policy is unlinked from the lists in thread context,
the xfrm timer can fire before we can mark this policy as dead.
So reinitialize the bydst hlist, then hlist_unhashed() will
notice that this policy is not linked and will avoid a
doulble unlink of that policy.
Reported-by: Xianpeng Zhao <redacted>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
If this race condition is real then I don't see how this fix
can be correct since there aren't any barriers between the check
and the unlink.
Looking at the code it seems that we've already taken the policy
lock so how can this race occur?
We take the policy lock in xfrm_policy_delete() before we
unlink the policy. But we release it before we mark the
policy as dead with xfrm_policy_kill(). If the timer fires
in the meantime it can be unlinked from the timer first
and then again from xfrm_policy_delete().
This issue was originally reported here:
https://bugzilla.kernel.org/show_bug.cgi?id=70471
From: Herbert Xu <herbert@gondor.apana.org.au> Date: 2014-02-27 07:01:26
On Thu, Feb 27, 2014 at 07:53:53AM +0100, Steffen Klassert wrote:
On Thu, Feb 27, 2014 at 02:30:15PM +0800, Herbert Xu wrote:
quoted
On Thu, Feb 27, 2014 at 02:27:12PM +0800, Herbert Xu wrote:
quoted
On Thu, Feb 27, 2014 at 07:16:39AM +0100, Steffen Klassert wrote:
quoted
When a policy is unlinked from the lists in thread context,
the xfrm timer can fire before we can mark this policy as dead.
So reinitialize the bydst hlist, then hlist_unhashed() will
notice that this policy is not linked and will avoid a
doulble unlink of that policy.
Reported-by: Xianpeng Zhao <redacted>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
If this race condition is real then I don't see how this fix
can be correct since there aren't any barriers between the check
and the unlink.
Looking at the code it seems that we've already taken the policy
lock so how can this race occur?
We take the policy lock in xfrm_policy_delete() before we
unlink the policy. But we release it before we mark the
policy as dead with xfrm_policy_kill(). If the timer fires
in the meantime it can be unlinked from the timer first
and then again from xfrm_policy_delete().
This issue was originally reported here:
https://bugzilla.kernel.org/show_bug.cgi?id=70471
1) Build fix for ip_vti when NET_IP_TUNNEL is not set.
We need this set to have ip_tunnel_get_stats64()
available.
2) Fix a NULL pointer dereference on sub policy usage.
We try to access a xfrm_state from the wrong array.
3) Take xfrm_state_lock in xfrm_migrate_state_find(),
we need it to traverse through the state lists.
4) Clone states properly on migration, otherwise we crash
when we migrate a state with aead algorithm attached.
5) Fix unlink race when between thread context and timer
when policies are deleted.