diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2008-09-22 22:48:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-09-22 22:48:19 -0400 |
commit | 5c1824587f0797373c95719a196f6098f7c6d20c (patch) | |
tree | c3a5af01afc01d88e111c7e1821b03bf404566f6 /include/net/xfrm.h | |
parent | fcaa40669cd798ca2ac0d15441e8a1d1145f2b16 (diff) |
ipsec: Fix xfrm_state_walk race
As discovered by Timo Teräs, the currently xfrm_state_walk scheme
is racy because if a second dump finishes before the first, we
may free xfrm states that the first dump would walk over later.
This patch fixes this by storing the dumps in a list in order
to calculate the correct completion counter which cures this
problem.
I've expanded netlink_cb in order to accomodate the extra state
related to this. It shouldn't be a big deal since netlink_cb
is kmalloced for each dump and we're just increasing it by 4 or
8 bytes.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net/xfrm.h')
-rw-r--r-- | include/net/xfrm.h | 10 |
1 files changed, 3 insertions, 7 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 4bb94992b5fa..48630b266593 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -1246,6 +1246,8 @@ struct xfrm6_tunnel { | |||
1246 | }; | 1246 | }; |
1247 | 1247 | ||
1248 | struct xfrm_state_walk { | 1248 | struct xfrm_state_walk { |
1249 | struct list_head list; | ||
1250 | unsigned long genid; | ||
1249 | struct xfrm_state *state; | 1251 | struct xfrm_state *state; |
1250 | int count; | 1252 | int count; |
1251 | u8 proto; | 1253 | u8 proto; |
@@ -1281,13 +1283,7 @@ static inline void xfrm6_fini(void) | |||
1281 | extern int xfrm_proc_init(void); | 1283 | extern int xfrm_proc_init(void); |
1282 | #endif | 1284 | #endif |
1283 | 1285 | ||
1284 | static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) | 1286 | extern void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); |
1285 | { | ||
1286 | walk->proto = proto; | ||
1287 | walk->state = NULL; | ||
1288 | walk->count = 0; | ||
1289 | } | ||
1290 | |||
1291 | extern int xfrm_state_walk(struct xfrm_state_walk *walk, | 1287 | extern int xfrm_state_walk(struct xfrm_state_walk *walk, |
1292 | int (*func)(struct xfrm_state *, int, void*), void *); | 1288 | int (*func)(struct xfrm_state *, int, void*), void *); |
1293 | extern void xfrm_state_walk_done(struct xfrm_state_walk *walk); | 1289 | extern void xfrm_state_walk_done(struct xfrm_state_walk *walk); |