Commit b8c203b2 authored by Steffen Klassert's avatar Steffen Klassert

xfrm: Generate queueing routes only from route lookup functions

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: a0073fe1 ("xfrm: Add a state resolution packet queue")
Reported-by: default avatarKonstantinos Kolelis <k.kolelis@sirrix.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent f92ee619
...@@ -480,6 +480,7 @@ void dst_init(void); ...@@ -480,6 +480,7 @@ void dst_init(void);
/* Flags for xfrm_lookup flags argument. */ /* Flags for xfrm_lookup flags argument. */
enum { enum {
XFRM_LOOKUP_ICMP = 1 << 0, XFRM_LOOKUP_ICMP = 1 << 0,
XFRM_LOOKUP_QUEUE = 1 << 1,
}; };
struct flowi; struct flowi;
......
...@@ -39,6 +39,11 @@ ...@@ -39,6 +39,11 @@
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
#define XFRM_MAX_QUEUE_LEN 100 #define XFRM_MAX_QUEUE_LEN 100
struct xfrm_flo {
struct dst_entry *dst_orig;
u8 flags;
};
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
__read_mostly; __read_mostly;
...@@ -1877,13 +1882,14 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb) ...@@ -1877,13 +1882,14 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb)
} }
static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
struct dst_entry *dst, struct xfrm_flo *xflo,
const struct flowi *fl, const struct flowi *fl,
int num_xfrms, int num_xfrms,
u16 family) u16 family)
{ {
int err; int err;
struct net_device *dev; struct net_device *dev;
struct dst_entry *dst;
struct dst_entry *dst1; struct dst_entry *dst1;
struct xfrm_dst *xdst; struct xfrm_dst *xdst;
...@@ -1891,9 +1897,12 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, ...@@ -1891,9 +1897,12 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
if (IS_ERR(xdst)) if (IS_ERR(xdst))
return 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; return xdst;
dst = xflo->dst_orig;
dst1 = &xdst->u.dst; dst1 = &xdst->u.dst;
dst_hold(dst); dst_hold(dst);
xdst->route = dst; xdst->route = dst;
...@@ -1935,7 +1944,7 @@ static struct flow_cache_object * ...@@ -1935,7 +1944,7 @@ static struct flow_cache_object *
xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
struct flow_cache_object *oldflo, void *ctx) 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_policy *pols[XFRM_POLICY_TYPE_MAX];
struct xfrm_dst *xdst, *new_xdst; struct xfrm_dst *xdst, *new_xdst;
int num_pols = 0, num_xfrms = 0, i, err, pol_dead; int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
...@@ -1976,7 +1985,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, ...@@ -1976,7 +1985,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
goto make_dummy_bundle; 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)) { if (IS_ERR(new_xdst)) {
err = PTR_ERR(new_xdst); err = PTR_ERR(new_xdst);
if (err != -EAGAIN) if (err != -EAGAIN)
...@@ -2010,7 +2020,7 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, ...@@ -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: /* We found policies, but there's no bundles to instantiate:
* either because the policy blocks, has no transformations or * either because the policy blocks, has no transformations or
* we could not build template (no xfrm_states).*/ * 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)) { if (IS_ERR(xdst)) {
xfrm_pols_put(pols, num_pols); xfrm_pols_put(pols, num_pols);
return ERR_CAST(xdst); return ERR_CAST(xdst);
...@@ -2104,13 +2114,18 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, ...@@ -2104,13 +2114,18 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
} }
if (xdst == NULL) { if (xdst == NULL) {
struct xfrm_flo xflo;
xflo.dst_orig = dst_orig;
xflo.flags = flags;
/* To accelerate a bit... */ /* To accelerate a bit... */
if ((dst_orig->flags & DST_NOXFRM) || if ((dst_orig->flags & DST_NOXFRM) ||
!net->xfrm.policy_count[XFRM_POLICY_OUT]) !net->xfrm.policy_count[XFRM_POLICY_OUT])
goto nopol; goto nopol;
flo = flow_cache_lookup(net, fl, family, dir, flo = flow_cache_lookup(net, fl, family, dir,
xfrm_bundle_lookup, dst_orig); xfrm_bundle_lookup, &xflo);
if (flo == NULL) if (flo == NULL)
goto nopol; goto nopol;
if (IS_ERR(flo)) { if (IS_ERR(flo)) {
...@@ -2202,7 +2217,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, ...@@ -2202,7 +2217,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl, const struct flowi *fl,
struct sock *sk, int flags) 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) if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
return make_blackhole(net, dst_orig->ops->family, dst_orig); return make_blackhole(net, dst_orig->ops->family, dst_orig);
...@@ -2476,7 +2492,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) ...@@ -2476,7 +2492,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
skb_dst_force(skb); 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)) { if (IS_ERR(dst)) {
res = 0; res = 0;
dst = NULL; dst = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment