Commit 31372fe9 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

Steffen Klassert says:

====================
1) Fix PMTU for IPv6 if the reported MTU minus the ESP overhead is
   smaller than 1280. From Jiri Bohac.

2) Fix xfrm interface ID and inter address family tunneling when
   migrating xfrm states. From Yan Yan.

3) Add missing xfrm intrerface ID initialization on xfrmi_changelink.
   From Antony Antony.

4) Enforce validity of xfrm offload input flags so that userspace can't
   send undefined flags to the offload driver.
   From Leon Romanovsky.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 91b0383f 7c76ecd9
...@@ -1568,7 +1568,6 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si); ...@@ -1568,7 +1568,6 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq); u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
int xfrm_init_replay(struct xfrm_state *x); int xfrm_init_replay(struct xfrm_state *x);
u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu);
u32 xfrm_state_mtu(struct xfrm_state *x, int mtu); u32 xfrm_state_mtu(struct xfrm_state *x, int mtu);
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload); int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload);
int xfrm_init_state(struct xfrm_state *x); int xfrm_init_state(struct xfrm_state *x);
...@@ -1681,14 +1680,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, ...@@ -1681,14 +1680,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
const struct xfrm_migrate *m, int num_bundles, const struct xfrm_migrate *m, int num_bundles,
const struct xfrm_kmaddress *k, const struct xfrm_kmaddress *k,
const struct xfrm_encap_tmpl *encap); const struct xfrm_encap_tmpl *encap);
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net); struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
u32 if_id);
struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
struct xfrm_migrate *m, struct xfrm_migrate *m,
struct xfrm_encap_tmpl *encap); struct xfrm_encap_tmpl *encap);
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_bundles, struct xfrm_migrate *m, int num_bundles,
struct xfrm_kmaddress *k, struct net *net, struct xfrm_kmaddress *k, struct net *net,
struct xfrm_encap_tmpl *encap); struct xfrm_encap_tmpl *encap, u32 if_id);
#endif #endif
int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
......
...@@ -511,6 +511,12 @@ struct xfrm_user_offload { ...@@ -511,6 +511,12 @@ struct xfrm_user_offload {
int ifindex; int ifindex;
__u8 flags; __u8 flags;
}; };
/* This flag was exposed without any kernel code that supporting it.
* Unfortunately, strongswan has the code that uses sets this flag,
* which makes impossible to reuse this bit.
*
* So leave it here to make sure that it won't be reused by mistake.
*/
#define XFRM_OFFLOAD_IPV6 1 #define XFRM_OFFLOAD_IPV6 1
#define XFRM_OFFLOAD_INBOUND 2 #define XFRM_OFFLOAD_INBOUND 2
......
...@@ -671,7 +671,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -671,7 +671,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
u32 padto; u32 padto;
padto = min(x->tfcpad, __xfrm_state_mtu(x, dst->child_mtu_cached)); padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
if (skb->len < padto) if (skb->len < padto)
esp.tfclen = padto - skb->len; esp.tfclen = padto - skb->len;
} }
......
...@@ -707,7 +707,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -707,7 +707,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
u32 padto; u32 padto;
padto = min(x->tfcpad, __xfrm_state_mtu(x, dst->child_mtu_cached)); padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
if (skb->len < padto) if (skb->len < padto)
esp.tfclen = padto - skb->len; esp.tfclen = padto - skb->len;
} }
......
...@@ -1408,8 +1408,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, ...@@ -1408,8 +1408,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
if (np->frag_size) if (np->frag_size)
mtu = np->frag_size; mtu = np->frag_size;
} }
if (mtu < IPV6_MIN_MTU)
return -EINVAL;
cork->base.fragsize = mtu; cork->base.fragsize = mtu;
cork->base.gso_size = ipc6->gso_size; cork->base.gso_size = ipc6->gso_size;
cork->base.tx_flags = 0; cork->base.tx_flags = 0;
...@@ -1471,8 +1469,6 @@ static int __ip6_append_data(struct sock *sk, ...@@ -1471,8 +1469,6 @@ static int __ip6_append_data(struct sock *sk,
fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
(opt ? opt->opt_nflen : 0); (opt ? opt->opt_nflen : 0);
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
sizeof(struct frag_hdr);
headersize = sizeof(struct ipv6hdr) + headersize = sizeof(struct ipv6hdr) +
(opt ? opt->opt_flen + opt->opt_nflen : 0) + (opt ? opt->opt_flen + opt->opt_nflen : 0) +
...@@ -1480,6 +1476,13 @@ static int __ip6_append_data(struct sock *sk, ...@@ -1480,6 +1476,13 @@ static int __ip6_append_data(struct sock *sk,
sizeof(struct frag_hdr) : 0) + sizeof(struct frag_hdr) : 0) +
rt->rt6i_nfheader_len; rt->rt6i_nfheader_len;
if (mtu < fragheaderlen ||
((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr))
goto emsgsize;
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
sizeof(struct frag_hdr);
/* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
* the first fragment * the first fragment
*/ */
......
...@@ -2623,7 +2623,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, ...@@ -2623,7 +2623,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
} }
return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
kma ? &k : NULL, net, NULL); kma ? &k : NULL, net, NULL, 0);
out: out:
return err; return err;
......
...@@ -223,6 +223,9 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -223,6 +223,9 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
if (x->encap || x->tfcpad) if (x->encap || x->tfcpad)
return -EINVAL; return -EINVAL;
if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
return -EINVAL;
dev = dev_get_by_index(net, xuo->ifindex); dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) { if (!dev) {
if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) { if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
...@@ -262,7 +265,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -262,7 +265,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC); netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC);
xso->real_dev = dev; xso->real_dev = dev;
xso->num_exthdrs = 1; xso->num_exthdrs = 1;
xso->flags = xuo->flags; /* Don't forward bit that is not implemented */
xso->flags = xuo->flags & ~XFRM_OFFLOAD_IPV6;
err = dev->xfrmdev_ops->xdo_dev_state_add(x); err = dev->xfrmdev_ops->xdo_dev_state_add(x);
if (err) { if (err) {
......
...@@ -673,12 +673,12 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -673,12 +673,12 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
struct net *net = xi->net; struct net *net = xi->net;
struct xfrm_if_parms p = {}; struct xfrm_if_parms p = {};
xfrmi_netlink_parms(data, &p);
if (!p.if_id) { if (!p.if_id) {
NL_SET_ERR_MSG(extack, "if_id must be non zero"); NL_SET_ERR_MSG(extack, "if_id must be non zero");
return -EINVAL; return -EINVAL;
} }
xfrmi_netlink_parms(data, &p);
xi = xfrmi_locate(net, &p); xi = xfrmi_locate(net, &p);
if (!xi) { if (!xi) {
xi = netdev_priv(dev); xi = netdev_priv(dev);
......
...@@ -4256,7 +4256,7 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, ...@@ -4256,7 +4256,7 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
} }
static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel, static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
u8 dir, u8 type, struct net *net) u8 dir, u8 type, struct net *net, u32 if_id)
{ {
struct xfrm_policy *pol, *ret = NULL; struct xfrm_policy *pol, *ret = NULL;
struct hlist_head *chain; struct hlist_head *chain;
...@@ -4265,7 +4265,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector * ...@@ -4265,7 +4265,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
spin_lock_bh(&net->xfrm.xfrm_policy_lock); spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (xfrm_migrate_selector_match(sel, &pol->selector) && if ((if_id == 0 || pol->if_id == if_id) &&
xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) { pol->type == type) {
ret = pol; ret = pol;
priority = ret->priority; priority = ret->priority;
...@@ -4277,7 +4278,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector * ...@@ -4277,7 +4278,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
if ((pol->priority >= priority) && ret) if ((pol->priority >= priority) && ret)
break; break;
if (xfrm_migrate_selector_match(sel, &pol->selector) && if ((if_id == 0 || pol->if_id == if_id) &&
xfrm_migrate_selector_match(sel, &pol->selector) &&
pol->type == type) { pol->type == type) {
ret = pol; ret = pol;
break; break;
...@@ -4393,7 +4395,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) ...@@ -4393,7 +4395,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *m, int num_migrate, struct xfrm_migrate *m, int num_migrate,
struct xfrm_kmaddress *k, struct net *net, struct xfrm_kmaddress *k, struct net *net,
struct xfrm_encap_tmpl *encap) struct xfrm_encap_tmpl *encap, u32 if_id)
{ {
int i, err, nx_cur = 0, nx_new = 0; int i, err, nx_cur = 0, nx_new = 0;
struct xfrm_policy *pol = NULL; struct xfrm_policy *pol = NULL;
...@@ -4412,14 +4414,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, ...@@ -4412,14 +4414,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
} }
/* Stage 1 - find policy */ /* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) { if ((pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id)) == NULL) {
err = -ENOENT; err = -ENOENT;
goto out; goto out;
} }
/* Stage 2 - find and update state(s) */ /* Stage 2 - find and update state(s) */
for (i = 0, mp = m; i < num_migrate; i++, mp++) { for (i = 0, mp = m; i < num_migrate; i++, mp++) {
if ((x = xfrm_migrate_state_find(mp, net))) { if ((x = xfrm_migrate_state_find(mp, net, if_id))) {
x_cur[nx_cur] = x; x_cur[nx_cur] = x;
nx_cur++; nx_cur++;
xc = xfrm_state_migrate(x, mp, encap); xc = xfrm_state_migrate(x, mp, encap);
......
...@@ -1579,9 +1579,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, ...@@ -1579,9 +1579,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
memcpy(&x->mark, &orig->mark, sizeof(x->mark)); memcpy(&x->mark, &orig->mark, sizeof(x->mark));
memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark)); memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
if (xfrm_init_state(x) < 0)
goto error;
x->props.flags = orig->props.flags; x->props.flags = orig->props.flags;
x->props.extra_flags = orig->props.extra_flags; x->props.extra_flags = orig->props.extra_flags;
...@@ -1606,7 +1603,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, ...@@ -1606,7 +1603,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
return NULL; return NULL;
} }
struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
u32 if_id)
{ {
unsigned int h; unsigned int h;
struct xfrm_state *x = NULL; struct xfrm_state *x = NULL;
...@@ -1622,6 +1620,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n ...@@ -1622,6 +1620,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
continue; continue;
if (m->reqid && x->props.reqid != m->reqid) if (m->reqid && x->props.reqid != m->reqid)
continue; continue;
if (if_id != 0 && x->if_id != if_id)
continue;
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
m->old_family) || m->old_family) ||
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr, !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
...@@ -1637,6 +1637,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n ...@@ -1637,6 +1637,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
if (x->props.mode != m->mode || if (x->props.mode != m->mode ||
x->id.proto != m->proto) x->id.proto != m->proto)
continue; continue;
if (if_id != 0 && x->if_id != if_id)
continue;
if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
m->old_family) || m->old_family) ||
!xfrm_addr_equal(&x->props.saddr, &m->old_saddr, !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
...@@ -1663,6 +1665,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, ...@@ -1663,6 +1665,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
if (!xc) if (!xc)
return NULL; return NULL;
xc->props.family = m->new_family;
if (xfrm_init_state(xc) < 0)
goto error;
memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
...@@ -2572,7 +2579,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x) ...@@ -2572,7 +2579,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x)
} }
EXPORT_SYMBOL(xfrm_state_delete_tunnel); EXPORT_SYMBOL(xfrm_state_delete_tunnel);
u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu) u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
{ {
const struct xfrm_type *type = READ_ONCE(x->type); const struct xfrm_type *type = READ_ONCE(x->type);
struct crypto_aead *aead; struct crypto_aead *aead;
...@@ -2603,17 +2610,7 @@ u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu) ...@@ -2603,17 +2610,7 @@ u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu)
return ((mtu - x->props.header_len - crypto_aead_authsize(aead) - return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
net_adj) & ~(blksize - 1)) + net_adj - 2; net_adj) & ~(blksize - 1)) + net_adj - 2;
} }
EXPORT_SYMBOL_GPL(__xfrm_state_mtu); EXPORT_SYMBOL_GPL(xfrm_state_mtu);
u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
{
mtu = __xfrm_state_mtu(x, mtu);
if (x->props.family == AF_INET6 && mtu < IPV6_MIN_MTU)
return IPV6_MIN_MTU;
return mtu;
}
int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
{ {
......
...@@ -2608,6 +2608,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2608,6 +2608,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
int n = 0; int n = 0;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct xfrm_encap_tmpl *encap = NULL; struct xfrm_encap_tmpl *encap = NULL;
u32 if_id = 0;
if (attrs[XFRMA_MIGRATE] == NULL) if (attrs[XFRMA_MIGRATE] == NULL)
return -EINVAL; return -EINVAL;
...@@ -2632,7 +2633,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2632,7 +2633,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
return -ENOMEM; return -ENOMEM;
} }
err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap); if (attrs[XFRMA_IF_ID])
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
kfree(encap); kfree(encap);
......
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