Commit b198d7b4 authored by Steffen Klassert's avatar Steffen Klassert

Merge branch 'xfrm: add extack support to some more message types'

Sabrina Dubroca says:

============
This is the last part of my extack work for xfrm, adding extack
messages to the last remaining operations: NEWSPDINFO, ALLOCSPI,
MIGRATE, NEWAE, DELSA, EXPIRE.

The first patch does a few clean ups on code that will be changed
later on it the series.
============
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parents cc2bbbfd a7417216
...@@ -1681,8 +1681,9 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, ...@@ -1681,8 +1681,9 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net,
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); int xfrm_policy_flush(struct net *net, u8 type, bool task_valid);
void xfrm_policy_hash_rebuild(struct net *net); void xfrm_policy_hash_rebuild(struct net *net);
u32 xfrm_get_acqseq(void); u32 xfrm_get_acqseq(void);
int verify_spi_info(u8 proto, u32 min, u32 max); int verify_spi_info(u8 proto, u32 min, u32 max, struct netlink_ext_ack *extack);
int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi,
struct netlink_ext_ack *extack);
struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark,
u8 mode, u32 reqid, u32 if_id, u8 proto, u8 mode, u32 reqid, u32 if_id, u8 proto,
const xfrm_address_t *daddr, const xfrm_address_t *daddr,
...@@ -1703,7 +1704,8 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, ...@@ -1703,7 +1704,8 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
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, u32 if_id); struct xfrm_encap_tmpl *encap, u32 if_id,
struct netlink_ext_ack *extack);
#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);
......
...@@ -1377,13 +1377,13 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_ ...@@ -1377,13 +1377,13 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_
max_spi = range->sadb_spirange_max; max_spi = range->sadb_spirange_max;
} }
err = verify_spi_info(x->id.proto, min_spi, max_spi); err = verify_spi_info(x->id.proto, min_spi, max_spi, NULL);
if (err) { if (err) {
xfrm_state_put(x); xfrm_state_put(x);
return err; return err;
} }
err = xfrm_alloc_spi(x, min_spi, max_spi); err = xfrm_alloc_spi(x, min_spi, max_spi, NULL);
resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x);
if (IS_ERR(resp_skb)) { if (IS_ERR(resp_skb)) {
...@@ -2626,7 +2626,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, ...@@ -2626,7 +2626,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, 0); kma ? &k : NULL, net, NULL, 0, NULL);
out: out:
return err; return err;
......
...@@ -4333,7 +4333,8 @@ static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tm ...@@ -4333,7 +4333,8 @@ static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tm
/* update endpoint address(es) of template(s) */ /* update endpoint address(es) of template(s) */
static int xfrm_policy_migrate(struct xfrm_policy *pol, static int xfrm_policy_migrate(struct xfrm_policy *pol,
struct xfrm_migrate *m, int num_migrate) struct xfrm_migrate *m, int num_migrate,
struct netlink_ext_ack *extack)
{ {
struct xfrm_migrate *mp; struct xfrm_migrate *mp;
int i, j, n = 0; int i, j, n = 0;
...@@ -4341,6 +4342,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, ...@@ -4341,6 +4342,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
write_lock_bh(&pol->lock); write_lock_bh(&pol->lock);
if (unlikely(pol->walk.dead)) { if (unlikely(pol->walk.dead)) {
/* target policy has been deleted */ /* target policy has been deleted */
NL_SET_ERR_MSG(extack, "Target policy not found");
write_unlock_bh(&pol->lock); write_unlock_bh(&pol->lock);
return -ENOENT; return -ENOENT;
} }
...@@ -4372,17 +4374,22 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, ...@@ -4372,17 +4374,22 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
return 0; return 0;
} }
static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate,
struct netlink_ext_ack *extack)
{ {
int i, j; int i, j;
if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) {
NL_SET_ERR_MSG(extack, "Invalid number of SAs to migrate, must be 0 < num <= XFRM_MAX_DEPTH (6)");
return -EINVAL; return -EINVAL;
}
for (i = 0; i < num_migrate; i++) { for (i = 0; i < num_migrate; i++) {
if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) {
NL_SET_ERR_MSG(extack, "Addresses in the MIGRATE attribute's list cannot be null");
return -EINVAL; return -EINVAL;
}
/* check if there is any duplicated entry */ /* check if there is any duplicated entry */
for (j = i + 1; j < num_migrate; j++) { for (j = i + 1; j < num_migrate; j++) {
...@@ -4393,8 +4400,10 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) ...@@ -4393,8 +4400,10 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
m[i].proto == m[j].proto && m[i].proto == m[j].proto &&
m[i].mode == m[j].mode && m[i].mode == m[j].mode &&
m[i].reqid == m[j].reqid && m[i].reqid == m[j].reqid &&
m[i].old_family == m[j].old_family) m[i].old_family == m[j].old_family) {
NL_SET_ERR_MSG(extack, "Entries in the MIGRATE attribute's list must be unique");
return -EINVAL; return -EINVAL;
}
} }
} }
...@@ -4404,7 +4413,8 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) ...@@ -4404,7 +4413,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, 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, u32 if_id) struct xfrm_encap_tmpl *encap, u32 if_id,
struct netlink_ext_ack *extack)
{ {
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;
...@@ -4414,16 +4424,20 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, ...@@ -4414,16 +4424,20 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
struct xfrm_migrate *mp; struct xfrm_migrate *mp;
/* Stage 0 - sanity checks */ /* Stage 0 - sanity checks */
if ((err = xfrm_migrate_check(m, num_migrate)) < 0) err = xfrm_migrate_check(m, num_migrate, extack);
if (err < 0)
goto out; goto out;
if (dir >= XFRM_POLICY_MAX) { if (dir >= XFRM_POLICY_MAX) {
NL_SET_ERR_MSG(extack, "Invalid policy direction");
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
/* Stage 1 - find policy */ /* Stage 1 - find policy */
if ((pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id)) == NULL) { pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id);
if (!pol) {
NL_SET_ERR_MSG(extack, "Target policy not found");
err = -ENOENT; err = -ENOENT;
goto out; goto out;
} }
...@@ -4445,7 +4459,8 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, ...@@ -4445,7 +4459,8 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
} }
/* Stage 3 - update policy */ /* Stage 3 - update policy */
if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0) err = xfrm_policy_migrate(pol, m, num_migrate, extack);
if (err < 0)
goto restore_state; goto restore_state;
/* Stage 4 - delete old state(s) */ /* Stage 4 - delete old state(s) */
......
...@@ -2017,7 +2017,7 @@ u32 xfrm_get_acqseq(void) ...@@ -2017,7 +2017,7 @@ u32 xfrm_get_acqseq(void)
} }
EXPORT_SYMBOL(xfrm_get_acqseq); EXPORT_SYMBOL(xfrm_get_acqseq);
int verify_spi_info(u8 proto, u32 min, u32 max) int verify_spi_info(u8 proto, u32 min, u32 max, struct netlink_ext_ack *extack)
{ {
switch (proto) { switch (proto) {
case IPPROTO_AH: case IPPROTO_AH:
...@@ -2026,22 +2026,28 @@ int verify_spi_info(u8 proto, u32 min, u32 max) ...@@ -2026,22 +2026,28 @@ int verify_spi_info(u8 proto, u32 min, u32 max)
case IPPROTO_COMP: case IPPROTO_COMP:
/* IPCOMP spi is 16-bits. */ /* IPCOMP spi is 16-bits. */
if (max >= 0x10000) if (max >= 0x10000) {
NL_SET_ERR_MSG(extack, "IPCOMP SPI must be <= 65535");
return -EINVAL; return -EINVAL;
}
break; break;
default: default:
NL_SET_ERR_MSG(extack, "Invalid protocol, must be one of AH, ESP, IPCOMP");
return -EINVAL; return -EINVAL;
} }
if (min > max) if (min > max) {
NL_SET_ERR_MSG(extack, "Invalid SPI range: min > max");
return -EINVAL; return -EINVAL;
}
return 0; return 0;
} }
EXPORT_SYMBOL(verify_spi_info); EXPORT_SYMBOL(verify_spi_info);
int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high,
struct netlink_ext_ack *extack)
{ {
struct net *net = xs_net(x); struct net *net = xs_net(x);
unsigned int h; unsigned int h;
...@@ -2053,8 +2059,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) ...@@ -2053,8 +2059,10 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
u32 mark = x->mark.v & x->mark.m; u32 mark = x->mark.v & x->mark.m;
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
if (x->km.state == XFRM_STATE_DEAD) if (x->km.state == XFRM_STATE_DEAD) {
NL_SET_ERR_MSG(extack, "Target ACQUIRE is in DEAD state");
goto unlock; goto unlock;
}
err = 0; err = 0;
if (x->id.spi) if (x->id.spi)
...@@ -2065,6 +2073,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) ...@@ -2065,6 +2073,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
if (minspi == maxspi) { if (minspi == maxspi) {
x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family);
if (x0) { if (x0) {
NL_SET_ERR_MSG(extack, "Requested SPI is already in use");
xfrm_state_put(x0); xfrm_state_put(x0);
goto unlock; goto unlock;
} }
...@@ -2089,6 +2098,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) ...@@ -2089,6 +2098,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
spin_unlock_bh(&net->xfrm.xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = 0; err = 0;
} else {
NL_SET_ERR_MSG(extack, "No SPI available in the requested range");
} }
unlock: unlock:
......
...@@ -515,7 +515,8 @@ static int attach_aead(struct xfrm_state *x, struct nlattr *rta, ...@@ -515,7 +515,8 @@ static int attach_aead(struct xfrm_state *x, struct nlattr *rta,
} }
static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn, static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn,
struct nlattr *rp) struct nlattr *rp,
struct netlink_ext_ack *extack)
{ {
struct xfrm_replay_state_esn *up; struct xfrm_replay_state_esn *up;
unsigned int ulen; unsigned int ulen;
...@@ -528,13 +529,25 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es ...@@ -528,13 +529,25 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es
/* Check the overall length and the internal bitmap length to avoid /* Check the overall length and the internal bitmap length to avoid
* potential overflow. */ * potential overflow. */
if (nla_len(rp) < (int)ulen || if (nla_len(rp) < (int)ulen) {
xfrm_replay_state_esn_len(replay_esn) != ulen || NL_SET_ERR_MSG(extack, "ESN attribute is too short");
replay_esn->bmp_len != up->bmp_len)
return -EINVAL; return -EINVAL;
}
if (xfrm_replay_state_esn_len(replay_esn) != ulen) {
NL_SET_ERR_MSG(extack, "New ESN size doesn't match the existing SA's ESN size");
return -EINVAL;
}
if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) if (replay_esn->bmp_len != up->bmp_len) {
NL_SET_ERR_MSG(extack, "New ESN bitmap size doesn't match the existing SA's ESN bitmap");
return -EINVAL; return -EINVAL;
}
if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) {
NL_SET_ERR_MSG(extack, "ESN replay window is longer than the bitmap");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -862,12 +875,12 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -862,12 +875,12 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
goto out; goto out;
if (xfrm_state_kern(x)) { if (xfrm_state_kern(x)) {
NL_SET_ERR_MSG(extack, "SA is in use by tunnels");
err = -EPERM; err = -EPERM;
goto out; goto out;
} }
err = xfrm_state_delete(x); err = xfrm_state_delete(x);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -1354,20 +1367,28 @@ static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1354,20 +1367,28 @@ static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
if (attrs[XFRMA_SPD_IPV4_HTHRESH]) { if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH]; struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];
if (nla_len(rta) < sizeof(*thresh4)) if (nla_len(rta) < sizeof(*thresh4)) {
NL_SET_ERR_MSG(extack, "Invalid SPD_IPV4_HTHRESH attribute length");
return -EINVAL; return -EINVAL;
}
thresh4 = nla_data(rta); thresh4 = nla_data(rta);
if (thresh4->lbits > 32 || thresh4->rbits > 32) if (thresh4->lbits > 32 || thresh4->rbits > 32) {
NL_SET_ERR_MSG(extack, "Invalid hash threshold (must be <= 32 for IPv4)");
return -EINVAL; return -EINVAL;
}
} }
if (attrs[XFRMA_SPD_IPV6_HTHRESH]) { if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH]; struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];
if (nla_len(rta) < sizeof(*thresh6)) if (nla_len(rta) < sizeof(*thresh6)) {
NL_SET_ERR_MSG(extack, "Invalid SPD_IPV6_HTHRESH attribute length");
return -EINVAL; return -EINVAL;
}
thresh6 = nla_data(rta); thresh6 = nla_data(rta);
if (thresh6->lbits > 128 || thresh6->rbits > 128) if (thresh6->lbits > 128 || thresh6->rbits > 128) {
NL_SET_ERR_MSG(extack, "Invalid hash threshold (must be <= 128 for IPv6)");
return -EINVAL; return -EINVAL;
}
} }
if (thresh4 || thresh6) { if (thresh4 || thresh6) {
...@@ -1510,7 +1531,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1510,7 +1531,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
u32 if_id = 0; u32 if_id = 0;
p = nlmsg_data(nlh); p = nlmsg_data(nlh);
err = verify_spi_info(p->info.id.proto, p->min, p->max); err = verify_spi_info(p->info.id.proto, p->min, p->max, extack);
if (err) if (err)
goto out_noput; goto out_noput;
...@@ -1538,10 +1559,12 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1538,10 +1559,12 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
&p->info.saddr, 1, &p->info.saddr, 1,
family); family);
err = -ENOENT; err = -ENOENT;
if (x == NULL) if (!x) {
NL_SET_ERR_MSG(extack, "Target ACQUIRE not found");
goto out_noput; goto out_noput;
}
err = xfrm_alloc_spi(x, p->min, p->max); err = xfrm_alloc_spi(x, p->min, p->max, extack);
if (err) if (err)
goto out; goto out;
...@@ -2433,12 +2456,16 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2433,12 +2456,16 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
if (!lt && !rp && !re && !et && !rt) if (!lt && !rp && !re && !et && !rt) {
NL_SET_ERR_MSG(extack, "Missing required attribute for AE");
return err; return err;
}
/* pedantic mode - thou shalt sayeth replaceth */ /* pedantic mode - thou shalt sayeth replaceth */
if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) {
NL_SET_ERR_MSG(extack, "NLM_F_REPLACE flag is required");
return err; return err;
}
mark = xfrm_mark_get(attrs, &m); mark = xfrm_mark_get(attrs, &m);
...@@ -2446,10 +2473,12 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2446,10 +2473,12 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
if (x == NULL) if (x == NULL)
return -ESRCH; return -ESRCH;
if (x->km.state != XFRM_STATE_VALID) if (x->km.state != XFRM_STATE_VALID) {
NL_SET_ERR_MSG(extack, "SA must be in VALID state");
goto out; goto out;
}
err = xfrm_replay_verify_len(x->replay_esn, re); err = xfrm_replay_verify_len(x->replay_esn, re, extack);
if (err) if (err)
goto out; goto out;
...@@ -2584,8 +2613,11 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2584,8 +2613,11 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
err = -EINVAL; err = -EINVAL;
if (x->km.state != XFRM_STATE_VALID) if (x->km.state != XFRM_STATE_VALID) {
NL_SET_ERR_MSG(extack, "SA must be in VALID state");
goto out; goto out;
}
km_state_expired(x, ue->hard, nlh->nlmsg_pid); km_state_expired(x, ue->hard, nlh->nlmsg_pid);
if (ue->hard) { if (ue->hard) {
...@@ -2665,7 +2697,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2665,7 +2697,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
#ifdef CONFIG_XFRM_MIGRATE #ifdef CONFIG_XFRM_MIGRATE
static int copy_from_user_migrate(struct xfrm_migrate *ma, static int copy_from_user_migrate(struct xfrm_migrate *ma,
struct xfrm_kmaddress *k, struct xfrm_kmaddress *k,
struct nlattr **attrs, int *num) struct nlattr **attrs, int *num,
struct netlink_ext_ack *extack)
{ {
struct nlattr *rt = attrs[XFRMA_MIGRATE]; struct nlattr *rt = attrs[XFRMA_MIGRATE];
struct xfrm_user_migrate *um; struct xfrm_user_migrate *um;
...@@ -2684,8 +2717,10 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma, ...@@ -2684,8 +2717,10 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma,
um = nla_data(rt); um = nla_data(rt);
num_migrate = nla_len(rt) / sizeof(*um); num_migrate = nla_len(rt) / sizeof(*um);
if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) {
NL_SET_ERR_MSG(extack, "Invalid number of SAs to migrate, must be 0 < num <= XFRM_MAX_DEPTH (6)");
return -EINVAL; return -EINVAL;
}
for (i = 0; i < num_migrate; i++, um++, ma++) { for (i = 0; i < num_migrate; i++, um++, ma++) {
memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr)); memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
...@@ -2718,8 +2753,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2718,8 +2753,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_encap_tmpl *encap = NULL; struct xfrm_encap_tmpl *encap = NULL;
u32 if_id = 0; u32 if_id = 0;
if (attrs[XFRMA_MIGRATE] == NULL) if (!attrs[XFRMA_MIGRATE]) {
NL_SET_ERR_MSG(extack, "Missing required MIGRATE attribute");
return -EINVAL; return -EINVAL;
}
kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL; kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
...@@ -2727,7 +2764,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2727,7 +2764,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err) if (err)
return err; return err;
err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n); err = copy_from_user_migrate(m, kmp, attrs, &n, extack);
if (err) if (err)
return err; return err;
...@@ -2744,7 +2781,8 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -2744,7 +2781,8 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
if (attrs[XFRMA_IF_ID]) if (attrs[XFRMA_IF_ID])
if_id = nla_get_u32(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); err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap,
if_id, extack);
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