diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2007-12-14 14:38:04 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:58:07 -0500 |
commit | 4bda4f250d21c3e4f2a2da5f4cef829a434a4046 (patch) | |
tree | 2632bc368ceab622cf119ef5aee154617fe43f1c /net | |
parent | 5e41fb83216d370d158fe17675af82d12c6c72c9 (diff) |
[XFRM]: Fix potential race vs xfrm_state(only)_find and xfrm_hash_resize.
The _find calls calculate the hash value using the
xfrm_state_hmask, without the xfrm_state_lock. But the
value of this mask can change in the _resize call under
the state_lock, so we risk to fail in finding the desired
entry in hash.
I think, that the hash value is better to calculate
under the state lock.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/xfrm/xfrm_state.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index b2343d48fe96..f7c0951c9fd9 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -756,7 +756,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
756 | struct xfrm_policy *pol, int *err, | 756 | struct xfrm_policy *pol, int *err, |
757 | unsigned short family) | 757 | unsigned short family) |
758 | { | 758 | { |
759 | unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); | 759 | unsigned int h; |
760 | struct hlist_node *entry; | 760 | struct hlist_node *entry; |
761 | struct xfrm_state *x, *x0; | 761 | struct xfrm_state *x, *x0; |
762 | int acquire_in_progress = 0; | 762 | int acquire_in_progress = 0; |
@@ -764,6 +764,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
764 | struct xfrm_state *best = NULL; | 764 | struct xfrm_state *best = NULL; |
765 | 765 | ||
766 | spin_lock_bh(&xfrm_state_lock); | 766 | spin_lock_bh(&xfrm_state_lock); |
767 | h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); | ||
767 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | 768 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { |
768 | if (x->props.family == family && | 769 | if (x->props.family == family && |
769 | x->props.reqid == tmpl->reqid && | 770 | x->props.reqid == tmpl->reqid && |
@@ -865,11 +866,12 @@ struct xfrm_state * | |||
865 | xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | 866 | xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, |
866 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 867 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
867 | { | 868 | { |
868 | unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); | 869 | unsigned int h; |
869 | struct xfrm_state *rx = NULL, *x = NULL; | 870 | struct xfrm_state *rx = NULL, *x = NULL; |
870 | struct hlist_node *entry; | 871 | struct hlist_node *entry; |
871 | 872 | ||
872 | spin_lock(&xfrm_state_lock); | 873 | spin_lock(&xfrm_state_lock); |
874 | h = xfrm_dst_hash(daddr, saddr, reqid, family); | ||
873 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { | 875 | hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { |
874 | if (x->props.family == family && | 876 | if (x->props.family == family && |
875 | x->props.reqid == reqid && | 877 | x->props.reqid == reqid && |