Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/klassert/ipsec

Steffen Klassert says:

====================
pull request (net): ipsec 2019-01-25

1) Several patches to fix the fallout from the recent
   tree based policy lookup work. From Florian Westphal.

2) Fix VTI for IPCOMP for 'not compressed' IPCOMP packets.
   We need an extra IPIP handler to process these packets
   correctly. From Su Yanjun.

3) Fix validation of template and selector families for
   MODE_ROUTEOPTIMIZATION with ipv4-in-ipv6 packets.
   This can lead to a stack-out-of-bounds because
   flowi4 struct is treated as flowi6 struct.
   Fix from Florian Westphal.

4) Restore the default behaviour of the xfrm set-mark
   in the output path. This was changed accidentally
   when mark setting was extended to the input path.
   From Benedict Wong.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jan 27, 2019
2 parents 1fc7f56 + e2612cd commit c303a9b
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 56 deletions.
50 changes: 50 additions & 0 deletions net/ipv4/ip_vti.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,33 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi,
return 0;
}

static int vti_input_ipip(struct sk_buff *skb, int nexthdr, __be32 spi,
int encap_type)
{
struct ip_tunnel *tunnel;
const struct iphdr *iph = ip_hdr(skb);
struct net *net = dev_net(skb->dev);
struct ip_tunnel_net *itn = net_generic(net, vti_net_id);

tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
iph->saddr, iph->daddr, 0);
if (tunnel) {
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop;

XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;

skb->dev = tunnel->dev;

return xfrm_input(skb, nexthdr, spi, encap_type);
}

return -EINVAL;
drop:
kfree_skb(skb);
return 0;
}

static int vti_rcv(struct sk_buff *skb)
{
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
Expand All @@ -82,6 +109,14 @@ static int vti_rcv(struct sk_buff *skb)
return vti_input(skb, ip_hdr(skb)->protocol, 0, 0);
}

static int vti_rcv_ipip(struct sk_buff *skb)
{
XFRM_SPI_SKB_CB(skb)->family = AF_INET;
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);

return vti_input_ipip(skb, ip_hdr(skb)->protocol, ip_hdr(skb)->saddr, 0);
}

static int vti_rcv_cb(struct sk_buff *skb, int err)
{
unsigned short family;
Expand Down Expand Up @@ -435,6 +470,12 @@ static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = {
.priority = 100,
};

static struct xfrm_tunnel ipip_handler __read_mostly = {
.handler = vti_rcv_ipip,
.err_handler = vti4_err,
.priority = 0,
};

static int __net_init vti_init_net(struct net *net)
{
int err;
Expand Down Expand Up @@ -603,6 +644,13 @@ static int __init vti_init(void)
if (err < 0)
goto xfrm_proto_comp_failed;

msg = "ipip tunnel";
err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
if (err < 0) {
pr_info("%s: cant't register tunnel\n",__func__);
goto xfrm_tunnel_failed;
}

msg = "netlink interface";
err = rtnl_link_register(&vti_link_ops);
if (err < 0)
Expand All @@ -612,6 +660,8 @@ static int __init vti_init(void)

rtnl_link_failed:
xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
xfrm_tunnel_failed:
xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
xfrm_proto_comp_failed:
xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
xfrm_proto_ah_failed:
Expand Down
63 changes: 33 additions & 30 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,16 +680,6 @@ static void xfrm_hash_resize(struct work_struct *work)
mutex_unlock(&hash_resize_mutex);
}

static void xfrm_hash_reset_inexact_table(struct net *net)
{
struct xfrm_pol_inexact_bin *b;

lockdep_assert_held(&net->xfrm.xfrm_policy_lock);

list_for_each_entry(b, &net->xfrm.inexact_bins, inexact_bins)
INIT_HLIST_HEAD(&b->hhead);
}

/* Make sure *pol can be inserted into fastbin.
* Useful to check that later insert requests will be sucessful
* (provided xfrm_policy_lock is held throughout).
Expand Down Expand Up @@ -833,13 +823,13 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,
u16 family)
{
unsigned int matched_s, matched_d;
struct hlist_node *newpos = NULL;
struct xfrm_policy *policy, *p;

matched_s = 0;
matched_d = 0;

list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) {
struct hlist_node *newpos = NULL;
bool matches_s, matches_d;

if (!policy->bydst_reinsert)
Expand All @@ -849,16 +839,19 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,

policy->bydst_reinsert = false;
hlist_for_each_entry(p, &n->hhead, bydst) {
if (policy->priority >= p->priority)
if (policy->priority > p->priority)
newpos = &p->bydst;
else if (policy->priority == p->priority &&
policy->pos > p->pos)
newpos = &p->bydst;
else
break;
}

if (newpos)
hlist_add_behind(&policy->bydst, newpos);
hlist_add_behind_rcu(&policy->bydst, newpos);
else
hlist_add_head(&policy->bydst, &n->hhead);
hlist_add_head_rcu(&policy->bydst, &n->hhead);

/* paranoia checks follow.
* Check that the reinserted policy matches at least
Expand Down Expand Up @@ -893,12 +886,13 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
struct rb_root *new,
u16 family)
{
struct rb_node **p, *parent = NULL;
struct xfrm_pol_inexact_node *node;
struct rb_node **p, *parent;

/* we should not have another subtree here */
WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root));

restart:
parent = NULL;
p = &new->rb_node;
while (*p) {
u8 prefixlen;
Expand All @@ -918,12 +912,11 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
} else {
struct xfrm_policy *tmp;

hlist_for_each_entry(tmp, &node->hhead, bydst)
tmp->bydst_reinsert = true;
hlist_for_each_entry(tmp, &n->hhead, bydst)
hlist_for_each_entry(tmp, &n->hhead, bydst) {
tmp->bydst_reinsert = true;
hlist_del_rcu(&tmp->bydst);
}

INIT_HLIST_HEAD(&node->hhead);
xfrm_policy_inexact_list_reinsert(net, node, family);

if (node->prefixlen == n->prefixlen) {
Expand All @@ -935,8 +928,7 @@ static void xfrm_policy_inexact_node_reinsert(struct net *net,
kfree_rcu(n, rcu);
n = node;
n->prefixlen = prefixlen;
*p = new->rb_node;
parent = NULL;
goto restart;
}
}

Expand Down Expand Up @@ -965,12 +957,11 @@ static void xfrm_policy_inexact_node_merge(struct net *net,
family);
}

hlist_for_each_entry(tmp, &v->hhead, bydst)
tmp->bydst_reinsert = true;
hlist_for_each_entry(tmp, &n->hhead, bydst)
hlist_for_each_entry(tmp, &v->hhead, bydst) {
tmp->bydst_reinsert = true;
hlist_del_rcu(&tmp->bydst);
}

INIT_HLIST_HEAD(&n->hhead);
xfrm_policy_inexact_list_reinsert(net, n, family);
}

Expand Down Expand Up @@ -1235,6 +1226,7 @@ static void xfrm_hash_rebuild(struct work_struct *work)
} while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq));

spin_lock_bh(&net->xfrm.xfrm_policy_lock);
write_seqcount_begin(&xfrm_policy_hash_generation);

/* make sure that we can insert the indirect policies again before
* we start with destructive action.
Expand Down Expand Up @@ -1278,10 +1270,14 @@ static void xfrm_hash_rebuild(struct work_struct *work)
}

/* reset the bydst and inexact table in all directions */
xfrm_hash_reset_inexact_table(net);

for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
struct hlist_node *n;

hlist_for_each_entry_safe(policy, n,
&net->xfrm.policy_inexact[dir],
bydst_inexact_list)
hlist_del_init(&policy->bydst_inexact_list);

hmask = net->xfrm.policy_bydst[dir].hmask;
odst = net->xfrm.policy_bydst[dir].table;
for (i = hmask; i >= 0; i--)
Expand Down Expand Up @@ -1313,6 +1309,9 @@ static void xfrm_hash_rebuild(struct work_struct *work)
newpos = NULL;
chain = policy_hash_bysel(net, &policy->selector,
policy->family, dir);

hlist_del_rcu(&policy->bydst);

if (!chain) {
void *p = xfrm_policy_inexact_insert(policy, dir, 0);

Expand All @@ -1334,6 +1333,7 @@ static void xfrm_hash_rebuild(struct work_struct *work)

out_unlock:
__xfrm_policy_inexact_flush(net);
write_seqcount_end(&xfrm_policy_hash_generation);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);

mutex_unlock(&hash_resize_mutex);
Expand Down Expand Up @@ -2600,7 +2600,10 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
dst_copy_metrics(dst1, dst);

if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
__u32 mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]);
__u32 mark = 0;

if (xfrm[i]->props.smark.v || xfrm[i]->props.smark.m)
mark = xfrm_smark_get(fl->flowi_mark, xfrm[i]);

family = xfrm[i]->props.family;
dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif,
Expand Down
13 changes: 9 additions & 4 deletions net/xfrm/xfrm_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -1488,10 +1488,15 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
if (!ut[i].family)
ut[i].family = family;

if ((ut[i].mode == XFRM_MODE_TRANSPORT) &&
(ut[i].family != prev_family))
return -EINVAL;

switch (ut[i].mode) {
case XFRM_MODE_TUNNEL:
case XFRM_MODE_BEET:
break;
default:
if (ut[i].family != prev_family)
return -EINVAL;
break;
}
if (ut[i].mode >= XFRM_MODE_MAX)
return -EINVAL;

Expand Down
Loading

0 comments on commit c303a9b

Please sign in to comment.