Skip to content

Commit

Permalink
xfrm: Generate queueing routes only from route lookup functions
Browse files Browse the repository at this point in the history
Currently we genarate a queueing route if we have matching policies
but can not resolve the states and the sysctl xfrm_larval_drop is
disabled. Here we assume that dst_output() is called to kill the
queued packets. Unfortunately this assumption is not true in all
cases, so it is possible that these packets leave the system unwanted.

We fix this by generating queueing routes only from the
route lookup functions, here we can guarantee a call to
dst_output() afterwards.

Fixes: a0073fe ("xfrm: Add a state resolution packet queue")
Reported-by: Konstantinos Kolelis <[email protected]>
Signed-off-by: Steffen Klassert <[email protected]>
  • Loading branch information
klassert committed Sep 16, 2014
1 parent f92ee61 commit b8c203b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
1 change: 1 addition & 0 deletions include/net/dst.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ void dst_init(void);
/* Flags for xfrm_lookup flags argument. */
enum {
XFRM_LOOKUP_ICMP = 1 << 0,
XFRM_LOOKUP_QUEUE = 1 << 1,
};

struct flowi;
Expand Down
32 changes: 24 additions & 8 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#define XFRM_MAX_QUEUE_LEN 100

struct xfrm_flo {
struct dst_entry *dst_orig;
u8 flags;
};

static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
__read_mostly;
Expand Down Expand Up @@ -1877,23 +1882,27 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb)
}

static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
struct dst_entry *dst,
struct xfrm_flo *xflo,
const struct flowi *fl,
int num_xfrms,
u16 family)
{
int err;
struct net_device *dev;
struct dst_entry *dst;
struct dst_entry *dst1;
struct xfrm_dst *xdst;

xdst = xfrm_alloc_dst(net, family);
if (IS_ERR(xdst))
return xdst;

if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0)
if (!(xflo->flags & XFRM_LOOKUP_QUEUE) ||
net->xfrm.sysctl_larval_drop ||
num_xfrms <= 0)
return xdst;

dst = xflo->dst_orig;
dst1 = &xdst->u.dst;
dst_hold(dst);
xdst->route = dst;
Expand Down Expand Up @@ -1935,7 +1944,7 @@ static struct flow_cache_object *
xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
struct flow_cache_object *oldflo, void *ctx)
{
struct dst_entry *dst_orig = (struct dst_entry *)ctx;
struct xfrm_flo *xflo = (struct xfrm_flo *)ctx;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
struct xfrm_dst *xdst, *new_xdst;
int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
Expand Down Expand Up @@ -1976,7 +1985,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
goto make_dummy_bundle;
}

new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig);
new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
xflo->dst_orig);
if (IS_ERR(new_xdst)) {
err = PTR_ERR(new_xdst);
if (err != -EAGAIN)
Expand Down Expand Up @@ -2010,7 +2020,7 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
/* We found policies, but there's no bundles to instantiate:
* either because the policy blocks, has no transformations or
* we could not build template (no xfrm_states).*/
xdst = xfrm_create_dummy_bundle(net, dst_orig, fl, num_xfrms, family);
xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family);
if (IS_ERR(xdst)) {
xfrm_pols_put(pols, num_pols);
return ERR_CAST(xdst);
Expand Down Expand Up @@ -2104,13 +2114,18 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
}

if (xdst == NULL) {
struct xfrm_flo xflo;

xflo.dst_orig = dst_orig;
xflo.flags = flags;

/* To accelerate a bit... */
if ((dst_orig->flags & DST_NOXFRM) ||
!net->xfrm.policy_count[XFRM_POLICY_OUT])
goto nopol;

flo = flow_cache_lookup(net, fl, family, dir,
xfrm_bundle_lookup, dst_orig);
xfrm_bundle_lookup, &xflo);
if (flo == NULL)
goto nopol;
if (IS_ERR(flo)) {
Expand Down Expand Up @@ -2202,7 +2217,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl,
struct sock *sk, int flags)
{
struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, flags);
struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
flags | XFRM_LOOKUP_QUEUE);

if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
return make_blackhole(net, dst_orig->ops->family, dst_orig);
Expand Down Expand Up @@ -2476,7 +2492,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)

skb_dst_force(skb);

dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0);
dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE);
if (IS_ERR(dst)) {
res = 0;
dst = NULL;
Expand Down

0 comments on commit b8c203b

Please sign in to comment.