Skip to content

Commit

Permalink
netns xfrm: per-netns xfrm_state_all list
Browse files Browse the repository at this point in the history
This is done to get
a) simple "something leaked" check
b) cover possible DoSes when other netns puts many, many xfrm_states
   onto a list.
c) not miss "alien xfrm_state" check in some of list iterators in future.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alexey Dobriyan authored and David S. Miller committed Nov 26, 2008
1 parent 673c09b commit 9d4139c
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 6 deletions.
3 changes: 3 additions & 0 deletions include/net/netns/xfrm.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#ifndef __NETNS_XFRM_H
#define __NETNS_XFRM_H

#include <linux/list.h>

struct netns_xfrm {
struct list_head state_all;
};

#endif
14 changes: 8 additions & 6 deletions net/xfrm/xfrm_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
* Main use is finding SA after policy selected tunnel or transport mode.
* Also, it can be used by ah/esp icmp error handler to find offending SA.
*/
static LIST_HEAD(xfrm_state_all);
static struct hlist_head *xfrm_state_bydst __read_mostly;
static struct hlist_head *xfrm_state_bysrc __read_mostly;
static struct hlist_head *xfrm_state_byspi __read_mostly;
Expand Down Expand Up @@ -855,7 +854,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,

if (km_query(x, tmpl, pol) == 0) {
x->km.state = XFRM_STATE_ACQ;
list_add(&x->km.all, &xfrm_state_all);
list_add(&x->km.all, &init_net.xfrm.state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Expand Down Expand Up @@ -924,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)

x->genid = ++xfrm_state_genid;

list_add(&x->km.all, &xfrm_state_all);
list_add(&x->km.all, &init_net.xfrm.state_all);

h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family);
Expand Down Expand Up @@ -1053,7 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
xfrm_state_hold(x);
x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
add_timer(&x->timer);
list_add(&x->km.all, &xfrm_state_all);
list_add(&x->km.all, &init_net.xfrm.state_all);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
Expand Down Expand Up @@ -1559,10 +1558,10 @@ int xfrm_state_walk(struct xfrm_state_walk *walk,

spin_lock_bh(&xfrm_state_lock);
if (list_empty(&walk->all))
x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
x = list_first_entry(&init_net.xfrm.state_all, struct xfrm_state_walk, all);
else
x = list_entry(&walk->all, struct xfrm_state_walk, all);
list_for_each_entry_from(x, &xfrm_state_all, all) {
list_for_each_entry_from(x, &init_net.xfrm.state_all, all) {
if (x->state == XFRM_STATE_DEAD)
continue;
state = container_of(x, struct xfrm_state, km);
Expand Down Expand Up @@ -2085,6 +2084,8 @@ int __net_init xfrm_state_init(struct net *net)
{
unsigned int sz;

INIT_LIST_HEAD(&net->xfrm.state_all);

sz = sizeof(struct hlist_head) * 8;

xfrm_state_bydst = xfrm_hash_alloc(sz);
Expand All @@ -2100,6 +2101,7 @@ int __net_init xfrm_state_init(struct net *net)

void xfrm_state_fini(struct net *net)
{
WARN_ON(!list_empty(&net->xfrm.state_all));
}

#ifdef CONFIG_AUDITSYSCALL
Expand Down

0 comments on commit 9d4139c

Please sign in to comment.