diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 7e7e2b0d2915..01f5bc144ee5 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -631,7 +631,8 @@ struct xfrm_mgr { u8 dir, u8 type, const struct xfrm_migrate *m, int num_bundles, - const struct xfrm_kmaddress *k); + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap); bool (*is_alive)(const struct km_event *c); }; @@ -1675,13 +1676,16 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); #ifdef CONFIG_XFRM_MIGRATE int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_bundles, - const struct xfrm_kmaddress *k); + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap); struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net); struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, - struct xfrm_migrate *m); + struct xfrm_migrate *m, + struct xfrm_encap_tmpl *encap); int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 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); #endif int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index e8f862358518..37db44f60718 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -1,5 +1,6 @@ #define pr_fmt(fmt) "IPsec: " fmt +#include #include #include #include @@ -279,7 +280,7 @@ static void ah_input_done(struct crypto_async_request *base, int err) auth_data = ah_tmp_auth(work_iph, ihl); icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); - err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; if (err) goto out; @@ -417,7 +418,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) goto out_free; } - err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; if (err) goto out_free; diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 755f38271dd5..7802b72196f3 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -25,6 +25,7 @@ #define pr_fmt(fmt) "IPv6: " fmt +#include #include #include #include @@ -483,7 +484,7 @@ static void ah6_input_done(struct crypto_async_request *base, int err) auth_data = ah_tmp_auth(work_iph, hdr_len); icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); - err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; if (err) goto out; @@ -631,7 +632,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) goto out_free; } - err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; + err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; if (err) goto out_free; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index d8b40ff4b2e6..71faffdd55d9 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -118,7 +118,6 @@ static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, static void esp_ssg_unref(struct xfrm_state *x, void *tmp) { - __be32 *seqhi; struct crypto_aead *aead = x->data; int seqhilen = 0; u8 *iv; @@ -128,7 +127,6 @@ static void esp_ssg_unref(struct xfrm_state *x, void *tmp) if (x->props.flags & XFRM_STATE_ESN) seqhilen += sizeof(__be32); - seqhi = esp_tmp_seqhi(tmp); iv = esp_tmp_iv(aead, tmp, seqhilen); req = esp_tmp_req(aead, iv); @@ -224,12 +222,9 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info u8 *vaddr; int nfrags; struct page *page; - struct ip_esp_hdr *esph; struct sk_buff *trailer; int tailen = esp->tailen; - esph = ip_esp_hdr(skb); - if (!skb_cloned(skb)) { if (tailen <= skb_availroom(skb)) { nfrags = 1; diff --git a/net/key/af_key.c b/net/key/af_key.c index daa4e90dc4db..ce9b8565d825 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2589,7 +2589,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, } return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, - kma ? &k : NULL, net); + kma ? &k : NULL, net, NULL); out: return err; @@ -3488,7 +3488,8 @@ static int set_ipsecrequest(struct sk_buff *skb, #ifdef CONFIG_NET_KEY_MIGRATE static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_bundles, - const struct xfrm_kmaddress *k) + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap) { int i; int sasize_sel; @@ -3598,7 +3599,8 @@ err: #else static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_bundles, - const struct xfrm_kmaddress *k) + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap) { return -ENOPROTOOPT; } diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 574e6f32f94f..6d4a60d1bf19 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -138,7 +138,7 @@ ok: } EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok); -int xfrm_dev_register(struct net_device *dev) +static int xfrm_dev_register(struct net_device *dev) { if ((dev->features & NETIF_F_HW_ESP) && !dev->xfrmdev_ops) return NOTIFY_BAD; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index af8e38f47b5b..a3dc7ab0b7ed 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -3279,11 +3279,6 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) return -EINVAL; for (i = 0; i < num_migrate; i++) { - if (xfrm_addr_equal(&m[i].old_daddr, &m[i].new_daddr, - m[i].old_family) && - xfrm_addr_equal(&m[i].old_saddr, &m[i].new_saddr, - m[i].old_family)) - return -EINVAL; if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) return -EINVAL; @@ -3307,7 +3302,8 @@ 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, 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) { int i, err, nx_cur = 0, nx_new = 0; struct xfrm_policy *pol = NULL; @@ -3330,7 +3326,8 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, if ((x = xfrm_migrate_state_find(mp, net))) { x_cur[nx_cur] = x; nx_cur++; - if ((xc = xfrm_state_migrate(x, mp))) { + xc = xfrm_state_migrate(x, mp, encap); + if (xc) { x_new[nx_new] = xc; nx_new++; } else { @@ -3351,7 +3348,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, } /* Stage 5 - announce */ - km_migrate(sel, dir, type, m, num_migrate, k); + km_migrate(sel, dir, type, m, num_migrate, k, encap); xfrm_pol_put(pol); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 2e291bc5f1fc..4a28f669c915 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1309,7 +1309,8 @@ out: EXPORT_SYMBOL(xfrm_state_add); #ifdef CONFIG_XFRM_MIGRATE -static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig) +static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, + struct xfrm_encap_tmpl *encap) { struct net *net = xs_net(orig); struct xfrm_state *x = xfrm_state_alloc(net); @@ -1351,8 +1352,14 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig) } x->props.calgo = orig->props.calgo; - if (orig->encap) { - x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); + if (encap || orig->encap) { + if (encap) + x->encap = kmemdup(encap, sizeof(*x->encap), + GFP_KERNEL); + else + x->encap = kmemdup(orig->encap, sizeof(*x->encap), + GFP_KERNEL); + if (!x->encap) goto error; } @@ -1442,11 +1449,12 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n EXPORT_SYMBOL(xfrm_migrate_state_find); 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_state *xc; - xc = xfrm_state_clone(x); + xc = xfrm_state_clone(x, encap); if (!xc) return NULL; @@ -1958,7 +1966,8 @@ EXPORT_SYMBOL(km_policy_expired); #ifdef CONFIG_XFRM_MIGRATE int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_migrate, - const struct xfrm_kmaddress *k) + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap) { int err = -EINVAL; int ret; @@ -1967,7 +1976,8 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, rcu_read_lock(); list_for_each_entry_rcu(km, &xfrm_km_list, list) { if (km->migrate) { - ret = km->migrate(sel, dir, type, m, num_migrate, k); + ret = km->migrate(sel, dir, type, m, num_migrate, k, + encap); if (!ret) err = ret; } @@ -2025,13 +2035,9 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen if (optlen <= 0 || optlen > PAGE_SIZE) return -EMSGSIZE; - data = kmalloc(optlen, GFP_KERNEL); - if (!data) - return -ENOMEM; - - err = -EFAULT; - if (copy_from_user(data, optval, optlen)) - goto out; + data = memdup_user(optval, optlen); + if (IS_ERR(data)) + return PTR_ERR(data); err = -EINVAL; rcu_read_lock(); @@ -2049,7 +2055,6 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen err = 0; } -out: kfree(data); return err; } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 38614df33ec8..6197c7231bc7 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2243,6 +2243,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, int err; int n = 0; struct net *net = sock_net(skb->sk); + struct xfrm_encap_tmpl *encap = NULL; if (attrs[XFRMA_MIGRATE] == NULL) return -EINVAL; @@ -2260,9 +2261,18 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, if (!n) return 0; - xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net); + if (attrs[XFRMA_ENCAP]) { + encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]), + sizeof(*encap), GFP_KERNEL); + if (!encap) + return 0; + } - return 0; + err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap); + + kfree(encap); + + return err; } #else static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2304,17 +2314,20 @@ static int copy_to_user_kmaddress(const struct xfrm_kmaddress *k, struct sk_buff return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk); } -static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma) +static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma, + int with_encp) { return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0) + + (with_encp ? nla_total_size(sizeof(struct xfrm_encap_tmpl)) : 0) + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) + userpolicy_type_attrsize(); } static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m, int num_migrate, const struct xfrm_kmaddress *k, - const struct xfrm_selector *sel, u8 dir, u8 type) + const struct xfrm_selector *sel, + const struct xfrm_encap_tmpl *encap, u8 dir, u8 type) { const struct xfrm_migrate *mp; struct xfrm_userpolicy_id *pol_id; @@ -2336,6 +2349,11 @@ static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m, if (err) goto out_cancel; } + if (encap) { + err = nla_put(skb, XFRMA_ENCAP, sizeof(*encap), encap); + if (err) + goto out_cancel; + } err = copy_to_user_policy_type(type, skb); if (err) goto out_cancel; @@ -2355,17 +2373,19 @@ out_cancel: static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_migrate, - const struct xfrm_kmaddress *k) + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap) { struct net *net = &init_net; struct sk_buff *skb; - skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); + skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k, !!encap), + GFP_ATOMIC); if (skb == NULL) return -ENOMEM; /* build migrate */ - if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) + if (build_migrate(skb, m, num_migrate, k, sel, encap, dir, type) < 0) BUG(); return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE); @@ -2373,7 +2393,8 @@ static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, #else static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, int num_migrate, - const struct xfrm_kmaddress *k) + const struct xfrm_kmaddress *k, + const struct xfrm_encap_tmpl *encap) { return -ENOPROTOOPT; }