Commit 42e8e6d9 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-next

Steffen Klassert says:

====================
1) Refactor selftests to use an array of structs in xfrm_fill_key().
   From Gautam Menghani.

2) Drop an unused argument from xfrm_policy_match.
   From Hongbin Wang.

3) Support collect metadata mode for xfrm interfaces.
   From Eyal Birger.

4) Add netlink extack support to xfrm.
   From Sabrina Dubroca.

Please note, there is a merge conflict in:

include/net/dst_metadata.h

between commit:

0a28bfd4 ("net/macsec: Add MACsec skb_metadata_dst Tx Data path support")

from the net-next tree and commit:

5182a5d4 ("net: allow storing xfrm interface metadata in metadata_dst")

from the ipsec-next tree.

Can be solved as done in linux-next.

Please pull or let me know if there are problems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d435073 c39596f6
......@@ -11,6 +11,7 @@ enum metadata_type {
METADATA_IP_TUNNEL,
METADATA_HW_PORT_MUX,
METADATA_MACSEC,
METADATA_XFRM,
};
struct hw_port_info {
......@@ -22,6 +23,11 @@ struct macsec_info {
sci_t sci;
};
struct xfrm_md_info {
u32 if_id;
int link;
};
struct metadata_dst {
struct dst_entry dst;
enum metadata_type type;
......@@ -29,6 +35,7 @@ struct metadata_dst {
struct ip_tunnel_info tun_info;
struct hw_port_info port_info;
struct macsec_info macsec_info;
struct xfrm_md_info xfrm_info;
} u;
};
......@@ -60,6 +67,27 @@ skb_tunnel_info(const struct sk_buff *skb)
return NULL;
}
static inline struct xfrm_md_info *lwt_xfrm_info(struct lwtunnel_state *lwt)
{
return (struct xfrm_md_info *)lwt->data;
}
static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
struct dst_entry *dst;
if (md_dst && md_dst->type == METADATA_XFRM)
return &md_dst->u.xfrm_info;
dst = skb_dst(skb);
if (dst && dst->lwtstate &&
dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM)
return lwt_xfrm_info(dst->lwtstate);
return NULL;
}
static inline bool skb_valid_dst(const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
......@@ -92,6 +120,9 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
case METADATA_MACSEC:
return memcmp(&a->u.macsec_info, &b->u.macsec_info,
sizeof(a->u.macsec_info));
case METADATA_XFRM:
return memcmp(&a->u.xfrm_info, &b->u.xfrm_info,
sizeof(a->u.xfrm_info));
default:
return 1;
}
......
......@@ -22,7 +22,7 @@ struct xfrm_state;
int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb);
int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb);
void ipcomp_destroy(struct xfrm_state *x);
int ipcomp_init_state(struct xfrm_state *x);
int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack);
static inline struct ip_comp_hdr *ip_comp_hdr(const struct sk_buff *skb)
{
......
......@@ -312,9 +312,15 @@ struct km_event {
struct net *net;
};
struct xfrm_if_decode_session_result {
struct net *net;
u32 if_id;
};
struct xfrm_if_cb {
struct xfrm_if *(*decode_session)(struct sk_buff *skb,
unsigned short family);
bool (*decode_session)(struct sk_buff *skb,
unsigned short family,
struct xfrm_if_decode_session_result *res);
};
void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb);
......@@ -399,7 +405,8 @@ struct xfrm_type {
#define XFRM_TYPE_LOCAL_COADDR 4
#define XFRM_TYPE_REMOTE_COADDR 8
int (*init_state)(struct xfrm_state *x);
int (*init_state)(struct xfrm_state *x,
struct netlink_ext_ack *extack);
void (*destructor)(struct xfrm_state *);
int (*input)(struct xfrm_state *, struct sk_buff *skb);
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
......@@ -985,6 +992,7 @@ void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
struct xfrm_if_parms {
int link; /* ifindex of underlying L2 interface */
u32 if_id; /* interface identifyer */
bool collect_md;
};
struct xfrm_if {
......@@ -1573,9 +1581,10 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
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, struct netlink_ext_ack *extack);
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,
struct netlink_ext_ack *extack);
int xfrm_init_state(struct xfrm_state *x);
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
......@@ -1879,7 +1888,8 @@ void xfrm_dev_resume(struct sk_buff *skb);
void xfrm_dev_backlog(struct softnet_data *sd);
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo);
struct xfrm_user_offload *xuo,
struct netlink_ext_ack *extack);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
......@@ -1942,7 +1952,7 @@ static inline struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_fea
return skb;
}
static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo)
static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo, struct netlink_ext_ack *extack)
{
return 0;
}
......
......@@ -695,6 +695,7 @@ enum {
IFLA_XFRM_UNSPEC,
IFLA_XFRM_LINK,
IFLA_XFRM_IF_ID,
IFLA_XFRM_COLLECT_METADATA,
__IFLA_XFRM_MAX
};
......
......@@ -15,6 +15,7 @@ enum lwtunnel_encap_types {
LWTUNNEL_ENCAP_SEG6_LOCAL,
LWTUNNEL_ENCAP_RPL,
LWTUNNEL_ENCAP_IOAM6,
LWTUNNEL_ENCAP_XFRM,
__LWTUNNEL_ENCAP_MAX,
};
......@@ -111,4 +112,13 @@ enum {
#define LWT_BPF_MAX_HEADROOM 256
enum {
LWT_XFRM_UNSPEC,
LWT_XFRM_IF_ID,
LWT_XFRM_LINK,
__LWT_XFRM_MAX,
};
#define LWT_XFRM_MAX (__LWT_XFRM_MAX - 1)
#endif /* _UAPI_LWTUNNEL_H_ */
......@@ -50,6 +50,7 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
return "IOAM6";
case LWTUNNEL_ENCAP_IP6:
case LWTUNNEL_ENCAP_IP:
case LWTUNNEL_ENCAP_XFRM:
case LWTUNNEL_ENCAP_NONE:
case __LWTUNNEL_ENCAP_MAX:
/* should not have got here */
......
......@@ -471,30 +471,38 @@ static int ah4_err(struct sk_buff *skb, u32 info)
return 0;
}
static int ah_init_state(struct xfrm_state *x)
static int ah_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
struct crypto_ahash *ahash;
if (!x->aalg)
if (!x->aalg) {
NL_SET_ERR_MSG(extack, "AH requires a state with an AUTH algorithm");
goto error;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "AH is not compatible with encapsulation");
goto error;
}
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
if (!ahp)
return -ENOMEM;
ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
if (IS_ERR(ahash))
if (IS_ERR(ahash)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
ahp->ahash = ahash;
if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
(x->aalg->alg_key_len + 7) / 8))
(x->aalg->alg_key_len + 7) / 8)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
/*
* Lookup the algorithm description maintained by xfrm_algo,
......@@ -507,10 +515,7 @@ static int ah_init_state(struct xfrm_state *x)
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
crypto_ahash_digestsize(ahash)) {
pr_info("%s: %s digestsize %u != %u\n",
__func__, x->aalg->alg_name,
crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
......
......@@ -1008,16 +1008,17 @@ static void esp_destroy(struct xfrm_state *x)
crypto_free_aead(aead);
}
static int esp_init_aead(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
char aead_name[CRYPTO_MAX_ALG_NAME];
struct crypto_aead *aead;
int err;
err = -ENAMETOOLONG;
if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
return -ENAMETOOLONG;
}
aead = crypto_alloc_aead(aead_name, 0, 0);
err = PTR_ERR(aead);
......@@ -1035,11 +1036,15 @@ static int esp_init_aead(struct xfrm_state *x)
if (err)
goto error;
return 0;
error:
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
return err;
}
static int esp_init_authenc(struct xfrm_state *x)
static int esp_init_authenc(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
......@@ -1050,10 +1055,6 @@ static int esp_init_authenc(struct xfrm_state *x)
unsigned int keylen;
int err;
err = -EINVAL;
if (!x->ealg)
goto error;
err = -ENAMETOOLONG;
if ((x->props.flags & XFRM_STATE_ESN)) {
......@@ -1062,22 +1063,28 @@ static int esp_init_authenc(struct xfrm_state *x)
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
} else {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"%s%sauthenc(%s,%s)%s",
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
}
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
if (IS_ERR(aead))
if (IS_ERR(aead)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
x->data = aead;
......@@ -1107,17 +1114,16 @@ static int esp_init_authenc(struct xfrm_state *x)
err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
pr_info("ESP: %s digestsize %u != %u\n",
x->aalg->alg_name,
crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
err = crypto_aead_setauthsize(
aead, x->aalg->alg_trunc_len / 8);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
}
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
......@@ -1132,7 +1138,7 @@ static int esp_init_authenc(struct xfrm_state *x)
return err;
}
static int esp_init_state(struct xfrm_state *x)
static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
u32 align;
......@@ -1140,10 +1146,14 @@ static int esp_init_state(struct xfrm_state *x)
x->data = NULL;
if (x->aead)
err = esp_init_aead(x);
else
err = esp_init_authenc(x);
if (x->aead) {
err = esp_init_aead(x, extack);
} else if (x->ealg) {
err = esp_init_authenc(x, extack);
} else {
NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
err = -EINVAL;
}
if (err)
goto error;
......@@ -1161,6 +1171,7 @@ static int esp_init_state(struct xfrm_state *x)
switch (encap->encap_type) {
default:
NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
err = -EINVAL;
goto error;
case UDP_ENCAP_ESPINUDP:
......
......@@ -117,7 +117,8 @@ static int ipcomp_tunnel_attach(struct xfrm_state *x)
return err;
}
static int ipcomp4_init_state(struct xfrm_state *x)
static int ipcomp4_init_state(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
int err = -EINVAL;
......@@ -129,17 +130,20 @@ static int ipcomp4_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct iphdr);
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported XFRM mode for IPcomp");
goto out;
}
err = ipcomp_init_state(x);
err = ipcomp_init_state(x, extack);
if (err)
goto out;
if (x->props.mode == XFRM_MODE_TUNNEL) {
err = ipcomp_tunnel_attach(x);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel error: failed to initialize the associated state");
goto out;
}
}
err = 0;
......
......@@ -22,13 +22,17 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
return ip_hdr(skb)->protocol;
}
static int ipip_init_state(struct xfrm_state *x)
static int ipip_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->props.mode != XFRM_MODE_TUNNEL)
if (x->props.mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "IPv4 tunnel can only be used with tunnel mode");
return -EINVAL;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPv4 tunnel is not compatible with encapsulation");
return -EINVAL;
}
x->props.header_len = sizeof(struct iphdr);
......
......@@ -666,30 +666,38 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
static int ah6_init_state(struct xfrm_state *x)
static int ah6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
struct crypto_ahash *ahash;
if (!x->aalg)
if (!x->aalg) {
NL_SET_ERR_MSG(extack, "AH requires a state with an AUTH algorithm");
goto error;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "AH is not compatible with encapsulation");
goto error;
}
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
if (!ahp)
return -ENOMEM;
ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
if (IS_ERR(ahash))
if (IS_ERR(ahash)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
ahp->ahash = ahash;
if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
(x->aalg->alg_key_len + 7) / 8))
(x->aalg->alg_key_len + 7) / 8)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
/*
* Lookup the algorithm description maintained by xfrm_algo,
......@@ -702,9 +710,7 @@ static int ah6_init_state(struct xfrm_state *x)
if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
crypto_ahash_digestsize(ahash)) {
pr_info("AH: %s digestsize %u != %u\n",
x->aalg->alg_name, crypto_ahash_digestsize(ahash),
aalg_desc->uinfo.auth.icv_fullbits/8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
......@@ -721,6 +727,7 @@ static int ah6_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct ipv6hdr);
break;
default:
NL_SET_ERR_MSG(extack, "Invalid mode requested for AH, must be one of TRANSPORT, TUNNEL, BEET");
goto error;
}
x->data = ahp;
......
......@@ -1051,16 +1051,17 @@ static void esp6_destroy(struct xfrm_state *x)
crypto_free_aead(aead);
}
static int esp_init_aead(struct xfrm_state *x)
static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
char aead_name[CRYPTO_MAX_ALG_NAME];
struct crypto_aead *aead;
int err;
err = -ENAMETOOLONG;
if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
goto error;
x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
return -ENAMETOOLONG;
}
aead = crypto_alloc_aead(aead_name, 0, 0);
err = PTR_ERR(aead);
......@@ -1078,11 +1079,15 @@ static int esp_init_aead(struct xfrm_state *x)
if (err)
goto error;
return 0;
error:
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
return err;
}
static int esp_init_authenc(struct xfrm_state *x)
static int esp_init_authenc(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
struct crypto_authenc_key_param *param;
......@@ -1093,10 +1098,6 @@ static int esp_init_authenc(struct xfrm_state *x)
unsigned int keylen;
int err;
err = -EINVAL;
if (!x->ealg)
goto error;
err = -ENAMETOOLONG;
if ((x->props.flags & XFRM_STATE_ESN)) {
......@@ -1105,22 +1106,28 @@ static int esp_init_authenc(struct xfrm_state *x)
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
} else {
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
"%s%sauthenc(%s,%s)%s",
x->geniv ?: "", x->geniv ? "(" : "",
x->aalg ? x->aalg->alg_name : "digest_null",
x->ealg->alg_name,
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
NL_SET_ERR_MSG(extack, "Algorithm name is too long");
goto error;
}
}
aead = crypto_alloc_aead(authenc_name, 0, 0);
err = PTR_ERR(aead);
if (IS_ERR(aead))
if (IS_ERR(aead)) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto error;
}
x->data = aead;
......@@ -1150,17 +1157,16 @@ static int esp_init_authenc(struct xfrm_state *x)
err = -EINVAL;
if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
crypto_aead_authsize(aead)) {
pr_info("ESP: %s digestsize %u != %u\n",
x->aalg->alg_name,
crypto_aead_authsize(aead),
aalg_desc->uinfo.auth.icv_fullbits / 8);
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
err = crypto_aead_setauthsize(
aead, x->aalg->alg_trunc_len / 8);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
goto free_key;
}
}
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
......@@ -1175,7 +1181,7 @@ static int esp_init_authenc(struct xfrm_state *x)
return err;
}
static int esp6_init_state(struct xfrm_state *x)
static int esp6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct crypto_aead *aead;
u32 align;
......@@ -1183,10 +1189,14 @@ static int esp6_init_state(struct xfrm_state *x)
x->data = NULL;
if (x->aead)
err = esp_init_aead(x);
else
err = esp_init_authenc(x);
if (x->aead) {
err = esp_init_aead(x, extack);
} else if (x->ealg) {
err = esp_init_authenc(x, extack);
} else {
NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
err = -EINVAL;
}
if (err)
goto error;
......@@ -1214,6 +1224,7 @@ static int esp6_init_state(struct xfrm_state *x)
switch (encap->encap_type) {
default:
NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
err = -EINVAL;
goto error;
case UDP_ENCAP_ESPINUDP:
......
......@@ -136,7 +136,8 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x)
return err;
}
static int ipcomp6_init_state(struct xfrm_state *x)
static int ipcomp6_init_state(struct xfrm_state *x,
struct netlink_ext_ack *extack)
{
int err = -EINVAL;
......@@ -148,17 +149,20 @@ static int ipcomp6_init_state(struct xfrm_state *x)
x->props.header_len += sizeof(struct ipv6hdr);
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported XFRM mode for IPcomp");
goto out;
}
err = ipcomp_init_state(x);
err = ipcomp_init_state(x, extack);
if (err)
goto out;
if (x->props.mode == XFRM_MODE_TUNNEL) {
err = ipcomp6_tunnel_attach(x);
if (err)
if (err) {
NL_SET_ERR_MSG(extack, "Kernel error: failed to initialize the associated state");
goto out;
}
}
err = 0;
......
......@@ -247,15 +247,14 @@ static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb,
return err;
}
static int mip6_destopt_init_state(struct xfrm_state *x)
static int mip6_destopt_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->id.spi) {
pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
NL_SET_ERR_MSG(extack, "SPI must be 0");
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
pr_info("%s: state's mode is not %u: %u\n",
__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
NL_SET_ERR_MSG(extack, "XFRM mode must be XFRM_MODE_ROUTEOPTIMIZATION");
return -EINVAL;
}
......@@ -333,15 +332,14 @@ static int mip6_rthdr_output(struct xfrm_state *x, struct sk_buff *skb)
return 0;
}
static int mip6_rthdr_init_state(struct xfrm_state *x)
static int mip6_rthdr_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->id.spi) {
pr_info("%s: spi is not 0: %u\n", __func__, x->id.spi);
NL_SET_ERR_MSG(extack, "SPI must be 0");
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
pr_info("%s: state's mode is not %u: %u\n",
__func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
NL_SET_ERR_MSG(extack, "XFRM mode must be XFRM_MODE_ROUTEOPTIMIZATION");
return -EINVAL;
}
......
......@@ -270,13 +270,17 @@ static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
return 0;
}
static int xfrm6_tunnel_init_state(struct xfrm_state *x)
static int xfrm6_tunnel_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
if (x->props.mode != XFRM_MODE_TUNNEL)
if (x->props.mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "IPv6 tunnel can only be used with tunnel mode");
return -EINVAL;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPv6 tunnel is not compatible with encapsulation");
return -EINVAL;
}
x->props.header_len = sizeof(struct ipv6hdr);
......
......@@ -207,7 +207,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo)
struct xfrm_user_offload *xuo,
struct netlink_ext_ack *extack)
{
int err;
struct dst_entry *dst;
......@@ -216,15 +217,21 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xfrm_address_t *saddr;
xfrm_address_t *daddr;
if (!x->type_offload)
if (!x->type_offload) {
NL_SET_ERR_MSG(extack, "Type doesn't support offload");
return -EINVAL;
}
/* We don't yet support UDP encapsulation and TFC padding. */
if (x->encap || x->tfcpad)
if (x->encap || x->tfcpad) {
NL_SET_ERR_MSG(extack, "Encapsulation and TFC padding can't be offloaded");
return -EINVAL;
}
if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND)) {
NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request");
return -EINVAL;
}
dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) {
......@@ -256,6 +263,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
if (x->props.flags & XFRM_STATE_ESN &&
!dev->xfrmdev_ops->xdo_dev_state_advance_esn) {
NL_SET_ERR_MSG(extack, "Device doesn't support offload with ESN");
xso->dev = NULL;
dev_put(dev);
return -EINVAL;
......@@ -277,8 +285,10 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
xso->real_dev = NULL;
netdev_put(dev, &xso->dev_tracker);
if (err != -EOPNOTSUPP)
if (err != -EOPNOTSUPP) {
NL_SET_ERR_MSG(extack, "Device failed to offload this state");
return err;
}
}
return 0;
......
......@@ -20,6 +20,7 @@
#include <net/xfrm.h>
#include <net/ip_tunnels.h>
#include <net/ip6_tunnel.h>
#include <net/dst_metadata.h>
#include "xfrm_inout.h"
......@@ -719,7 +720,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp = skb_sec_path(skb);
if (sp)
sp->olen = 0;
skb_dst_drop(skb);
if (skb_valid_dst(skb))
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return 0;
} else {
......@@ -737,7 +739,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
sp = skb_sec_path(skb);
if (sp)
sp->olen = 0;
skb_dst_drop(skb);
if (skb_valid_dst(skb))
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return err;
}
......
......@@ -41,6 +41,7 @@
#include <net/addrconf.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/dst_metadata.h>
#include <net/netns/generic.h>
#include <linux/etherdevice.h>
......@@ -56,6 +57,89 @@ static const struct net_device_ops xfrmi_netdev_ops;
struct xfrmi_net {
/* lists for storing interfaces in use */
struct xfrm_if __rcu *xfrmi[XFRMI_HASH_SIZE];
struct xfrm_if __rcu *collect_md_xfrmi;
};
static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = {
[LWT_XFRM_IF_ID] = NLA_POLICY_MIN(NLA_U32, 1),
[LWT_XFRM_LINK] = NLA_POLICY_MIN(NLA_U32, 1),
};
static void xfrmi_destroy_state(struct lwtunnel_state *lwt)
{
}
static int xfrmi_build_state(struct net *net, struct nlattr *nla,
unsigned int family, const void *cfg,
struct lwtunnel_state **ts,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[LWT_XFRM_MAX + 1];
struct lwtunnel_state *new_state;
struct xfrm_md_info *info;
int ret;
ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack);
if (ret < 0)
return ret;
if (!tb[LWT_XFRM_IF_ID]) {
NL_SET_ERR_MSG(extack, "if_id must be set");
return -EINVAL;
}
new_state = lwtunnel_state_alloc(sizeof(*info));
if (!new_state) {
NL_SET_ERR_MSG(extack, "failed to create encap info");
return -ENOMEM;
}
new_state->type = LWTUNNEL_ENCAP_XFRM;
info = lwt_xfrm_info(new_state);
info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]);
if (tb[LWT_XFRM_LINK])
info->link = nla_get_u32(tb[LWT_XFRM_LINK]);
*ts = new_state;
return 0;
}
static int xfrmi_fill_encap_info(struct sk_buff *skb,
struct lwtunnel_state *lwt)
{
struct xfrm_md_info *info = lwt_xfrm_info(lwt);
if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id) ||
(info->link && nla_put_u32(skb, LWT_XFRM_LINK, info->link)))
return -EMSGSIZE;
return 0;
}
static int xfrmi_encap_nlsize(struct lwtunnel_state *lwtstate)
{
return nla_total_size(sizeof(u32)) + /* LWT_XFRM_IF_ID */
nla_total_size(sizeof(u32)); /* LWT_XFRM_LINK */
}
static int xfrmi_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
{
struct xfrm_md_info *a_info = lwt_xfrm_info(a);
struct xfrm_md_info *b_info = lwt_xfrm_info(b);
return memcmp(a_info, b_info, sizeof(*a_info));
}
static const struct lwtunnel_encap_ops xfrmi_encap_ops = {
.build_state = xfrmi_build_state,
.destroy_state = xfrmi_destroy_state,
.fill_encap = xfrmi_fill_encap_info,
.get_encap_size = xfrmi_encap_nlsize,
.cmp_encap = xfrmi_encap_cmp,
.owner = THIS_MODULE,
};
#define for_each_xfrmi_rcu(start, xi) \
......@@ -77,17 +161,23 @@ static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x)
return xi;
}
xi = rcu_dereference(xfrmn->collect_md_xfrmi);
if (xi && (xi->dev->flags & IFF_UP))
return xi;
return NULL;
}
static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
unsigned short family)
static bool xfrmi_decode_session(struct sk_buff *skb,
unsigned short family,
struct xfrm_if_decode_session_result *res)
{
struct net_device *dev;
struct xfrm_if *xi;
int ifindex = 0;
if (!secpath_exists(skb) || !skb->dev)
return NULL;
return false;
switch (family) {
case AF_INET6:
......@@ -107,11 +197,18 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb,
}
if (!dev || !(dev->flags & IFF_UP))
return NULL;
return false;
if (dev->netdev_ops != &xfrmi_netdev_ops)
return NULL;
return false;
return netdev_priv(dev);
xi = netdev_priv(dev);
res->net = xi->net;
if (xi->p.collect_md)
res->if_id = xfrm_input_state(skb)->if_id;
else
res->if_id = xi->p.if_id;
return true;
}
static void xfrmi_link(struct xfrmi_net *xfrmn, struct xfrm_if *xi)
......@@ -157,7 +254,10 @@ static int xfrmi_create(struct net_device *dev)
if (err < 0)
goto out;
xfrmi_link(xfrmn, xi);
if (xi->p.collect_md)
rcu_assign_pointer(xfrmn->collect_md_xfrmi, xi);
else
xfrmi_link(xfrmn, xi);
return 0;
......@@ -185,7 +285,10 @@ static void xfrmi_dev_uninit(struct net_device *dev)
struct xfrm_if *xi = netdev_priv(dev);
struct xfrmi_net *xfrmn = net_generic(xi->net, xfrmi_net_id);
xfrmi_unlink(xfrmn, xi);
if (xi->p.collect_md)
RCU_INIT_POINTER(xfrmn->collect_md_xfrmi, NULL);
else
xfrmi_unlink(xfrmn, xi);
}
static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
......@@ -214,6 +317,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
struct xfrm_state *x;
struct xfrm_if *xi;
bool xnet;
int link;
if (err && !secpath_exists(skb))
return 0;
......@@ -224,6 +328,7 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
if (!xi)
return 1;
link = skb->dev->ifindex;
dev = xi->dev;
skb->dev = dev;
......@@ -254,6 +359,17 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
}
xfrmi_scrub_packet(skb, xnet);
if (xi->p.collect_md) {
struct metadata_dst *md_dst;
md_dst = metadata_dst_alloc(0, METADATA_XFRM, GFP_ATOMIC);
if (!md_dst)
return -ENOMEM;
md_dst->u.xfrm_info.if_id = x->if_id;
md_dst->u.xfrm_info.link = link;
skb_dst_set(skb, (struct dst_entry *)md_dst);
}
dev_sw_netstats_rx_add(dev, skb->len);
return 0;
......@@ -269,10 +385,23 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
struct net_device *tdev;
struct xfrm_state *x;
int err = -1;
u32 if_id;
int mtu;
if (xi->p.collect_md) {
struct xfrm_md_info *md_info = skb_xfrm_md_info(skb);
if (unlikely(!md_info))
return -EINVAL;
if_id = md_info->if_id;
fl->flowi_oif = md_info->link;
} else {
if_id = xi->p.if_id;
}
dst_hold(dst);
dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id);
dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, if_id);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
......@@ -283,7 +412,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
if (!x)
goto tx_err_link_failure;
if (x->if_id != xi->p.if_id)
if (x->if_id != if_id)
goto tx_err_link_failure;
tdev = dst->dev;
......@@ -633,6 +762,9 @@ static void xfrmi_netlink_parms(struct nlattr *data[],
if (data[IFLA_XFRM_IF_ID])
parms->if_id = nla_get_u32(data[IFLA_XFRM_IF_ID]);
if (data[IFLA_XFRM_COLLECT_METADATA])
parms->collect_md = true;
}
static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
......@@ -645,14 +777,27 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
int err;
xfrmi_netlink_parms(data, &p);
if (!p.if_id) {
NL_SET_ERR_MSG(extack, "if_id must be non zero");
return -EINVAL;
}
if (p.collect_md) {
struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id);
xi = xfrmi_locate(net, &p);
if (xi)
return -EEXIST;
if (p.link || p.if_id) {
NL_SET_ERR_MSG(extack, "link and if_id must be zero");
return -EINVAL;
}
if (rtnl_dereference(xfrmn->collect_md_xfrmi))
return -EEXIST;
} else {
if (!p.if_id) {
NL_SET_ERR_MSG(extack, "if_id must be non zero");
return -EINVAL;
}
xi = xfrmi_locate(net, &p);
if (xi)
return -EEXIST;
}
xi = netdev_priv(dev);
xi->p = p;
......@@ -682,12 +827,22 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
return -EINVAL;
}
if (p.collect_md) {
NL_SET_ERR_MSG(extack, "collect_md can't be changed");
return -EINVAL;
}
xi = xfrmi_locate(net, &p);
if (!xi) {
xi = netdev_priv(dev);
} else {
if (xi->dev != dev)
return -EEXIST;
if (xi->p.collect_md) {
NL_SET_ERR_MSG(extack,
"device can't be changed to collect_md");
return -EINVAL;
}
}
return xfrmi_update(xi, &p);
......@@ -700,6 +855,8 @@ static size_t xfrmi_get_size(const struct net_device *dev)
nla_total_size(4) +
/* IFLA_XFRM_IF_ID */
nla_total_size(4) +
/* IFLA_XFRM_COLLECT_METADATA */
nla_total_size(0) +
0;
}
......@@ -709,7 +866,8 @@ static int xfrmi_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct xfrm_if_parms *parm = &xi->p;
if (nla_put_u32(skb, IFLA_XFRM_LINK, parm->link) ||
nla_put_u32(skb, IFLA_XFRM_IF_ID, parm->if_id))
nla_put_u32(skb, IFLA_XFRM_IF_ID, parm->if_id) ||
(xi->p.collect_md && nla_put_flag(skb, IFLA_XFRM_COLLECT_METADATA)))
goto nla_put_failure;
return 0;
......@@ -725,8 +883,10 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev)
}
static const struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
[IFLA_XFRM_LINK] = { .type = NLA_U32 },
[IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
[IFLA_XFRM_UNSPEC] = { .strict_start_type = IFLA_XFRM_COLLECT_METADATA },
[IFLA_XFRM_LINK] = { .type = NLA_U32 },
[IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
[IFLA_XFRM_COLLECT_METADATA] = { .type = NLA_FLAG },
};
static struct rtnl_link_ops xfrmi_link_ops __read_mostly = {
......@@ -762,6 +922,9 @@ static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list)
xip = &xi->next)
unregister_netdevice_queue(xi->dev, &list);
}
xi = rtnl_dereference(xfrmn->collect_md_xfrmi);
if (xi)
unregister_netdevice_queue(xi->dev, &list);
}
unregister_netdevice_many(&list);
rtnl_unlock();
......@@ -999,6 +1162,8 @@ static int __init xfrmi_init(void)
if (err < 0)
goto rtnl_link_failed;
lwtunnel_encap_add_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
xfrm_if_register_cb(&xfrm_if_cb);
return err;
......@@ -1017,6 +1182,7 @@ static int __init xfrmi_init(void)
static void __exit xfrmi_fini(void)
{
xfrm_if_unregister_cb();
lwtunnel_encap_del_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
rtnl_link_unregister(&xfrmi_link_ops);
xfrmi4_fini();
xfrmi6_fini();
......
......@@ -325,18 +325,22 @@ void ipcomp_destroy(struct xfrm_state *x)
}
EXPORT_SYMBOL_GPL(ipcomp_destroy);
int ipcomp_init_state(struct xfrm_state *x)
int ipcomp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
int err;
struct ipcomp_data *ipcd;
struct xfrm_algo_desc *calg_desc;
err = -EINVAL;
if (!x->calg)
if (!x->calg) {
NL_SET_ERR_MSG(extack, "Missing required compression algorithm");
goto out;
}
if (x->encap)
if (x->encap) {
NL_SET_ERR_MSG(extack, "IPComp is not compatible with encapsulation");
goto out;
}
err = -ENOMEM;
ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL);
......
......@@ -1889,7 +1889,7 @@ EXPORT_SYMBOL(xfrm_policy_walk_done);
*/
static int xfrm_policy_match(const struct xfrm_policy *pol,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
const struct xfrm_selector *sel = &pol->selector;
int ret = -ESRCH;
......@@ -2014,7 +2014,7 @@ static struct xfrm_policy *
__xfrm_policy_eval_candidates(struct hlist_head *chain,
struct xfrm_policy *prefer,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
u32 priority = prefer ? prefer->priority : ~0u;
struct xfrm_policy *pol;
......@@ -2028,7 +2028,7 @@ __xfrm_policy_eval_candidates(struct hlist_head *chain,
if (pol->priority > priority)
break;
err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
err = xfrm_policy_match(pol, fl, type, family, if_id);
if (err) {
if (err != -ESRCH)
return ERR_PTR(err);
......@@ -2053,7 +2053,7 @@ static struct xfrm_policy *
xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand,
struct xfrm_policy *prefer,
const struct flowi *fl,
u8 type, u16 family, int dir, u32 if_id)
u8 type, u16 family, u32 if_id)
{
struct xfrm_policy *tmp;
int i;
......@@ -2061,8 +2061,7 @@ xfrm_policy_eval_candidates(struct xfrm_pol_inexact_candidates *cand,
for (i = 0; i < ARRAY_SIZE(cand->res); i++) {
tmp = __xfrm_policy_eval_candidates(cand->res[i],
prefer,
fl, type, family, dir,
if_id);
fl, type, family, if_id);
if (!tmp)
continue;
......@@ -2101,7 +2100,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
ret = NULL;
hlist_for_each_entry_rcu(pol, chain, bydst) {
err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
err = xfrm_policy_match(pol, fl, type, family, if_id);
if (err) {
if (err == -ESRCH)
continue;
......@@ -2120,7 +2119,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
goto skip_inexact;
pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
family, dir, if_id);
family, if_id);
if (pol) {
ret = pol;
if (IS_ERR(pol))
......@@ -3516,17 +3515,17 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int xerr_idx = -1;
const struct xfrm_if_cb *ifcb;
struct sec_path *sp;
struct xfrm_if *xi;
u32 if_id = 0;
rcu_read_lock();
ifcb = xfrm_if_get_cb();
if (ifcb) {
xi = ifcb->decode_session(skb, family);
if (xi) {
if_id = xi->p.if_id;
net = xi->net;
struct xfrm_if_decode_session_result r;
if (ifcb->decode_session(skb, family, &r)) {
if_id = r.if_id;
net = r.net;
}
}
rcu_read_unlock();
......
......@@ -766,18 +766,22 @@ int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
}
#endif
int xfrm_init_replay(struct xfrm_state *x)
int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack)
{
struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
if (replay_esn) {
if (replay_esn->replay_window >
replay_esn->bmp_len * sizeof(__u32) * 8)
replay_esn->bmp_len * sizeof(__u32) * 8) {
NL_SET_ERR_MSG(extack, "ESN replay window is too large for the chosen bitmap size");
return -EINVAL;
}
if (x->props.flags & XFRM_STATE_ESN) {
if (replay_esn->replay_window == 0)
if (replay_esn->replay_window == 0) {
NL_SET_ERR_MSG(extack, "ESN replay window must be > 0");
return -EINVAL;
}
x->repl_mode = XFRM_REPLAY_MODE_ESN;
} else {
x->repl_mode = XFRM_REPLAY_MODE_BMP;
......
......@@ -2611,7 +2611,8 @@ u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
}
EXPORT_SYMBOL_GPL(xfrm_state_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,
struct netlink_ext_ack *extack)
{
const struct xfrm_mode *inner_mode;
const struct xfrm_mode *outer_mode;
......@@ -2626,12 +2627,16 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
if (x->sel.family != AF_UNSPEC) {
inner_mode = xfrm_get_mode(x->props.mode, x->sel.family);
if (inner_mode == NULL)
if (inner_mode == NULL) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
goto error;
}
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) &&
family != x->sel.family)
family != x->sel.family) {
NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate a change of family");
goto error;
}
x->inner_mode = *inner_mode;
} else {
......@@ -2639,11 +2644,15 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
int iafamily = AF_INET;
inner_mode = xfrm_get_mode(x->props.mode, x->props.family);
if (inner_mode == NULL)
if (inner_mode == NULL) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
goto error;
}
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL))
if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) {
NL_SET_ERR_MSG(extack, "Only tunnel modes can accommodate an AF_UNSPEC selector");
goto error;
}
x->inner_mode = *inner_mode;
......@@ -2658,24 +2667,27 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
}
x->type = xfrm_get_type(x->id.proto, family);
if (x->type == NULL)
if (x->type == NULL) {
NL_SET_ERR_MSG(extack, "Requested type not found");
goto error;
}
x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload);
err = x->type->init_state(x);
err = x->type->init_state(x, extack);
if (err)
goto error;
outer_mode = xfrm_get_mode(x->props.mode, family);
if (!outer_mode) {
NL_SET_ERR_MSG(extack, "Requested mode not found");
err = -EPROTONOSUPPORT;
goto error;
}
x->outer_mode = *outer_mode;
if (init_replay) {
err = xfrm_init_replay(x);
err = xfrm_init_replay(x, extack);
if (err)
goto error;
}
......@@ -2690,7 +2702,7 @@ int xfrm_init_state(struct xfrm_state *x)
{
int err;
err = __xfrm_init_state(x, true, false);
err = __xfrm_init_state(x, true, false, NULL);
if (!err)
x->km.state = XFRM_STATE_VALID;
......
......@@ -35,7 +35,8 @@
#endif
#include <asm/unaligned.h>
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type,
struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[type];
struct xfrm_algo *algp;
......@@ -44,8 +45,10 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
return 0;
algp = nla_data(rt);
if (nla_len(rt) < (int)xfrm_alg_len(algp))
if (nla_len(rt) < (int)xfrm_alg_len(algp)) {
NL_SET_ERR_MSG(extack, "Invalid AUTH/CRYPT/COMP attribute length");
return -EINVAL;
}
switch (type) {
case XFRMA_ALG_AUTH:
......@@ -54,6 +57,7 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
break;
default:
NL_SET_ERR_MSG(extack, "Invalid algorithm attribute type");
return -EINVAL;
}
......@@ -61,7 +65,8 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
return 0;
}
static int verify_auth_trunc(struct nlattr **attrs)
static int verify_auth_trunc(struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC];
struct xfrm_algo_auth *algp;
......@@ -70,14 +75,16 @@ static int verify_auth_trunc(struct nlattr **attrs)
return 0;
algp = nla_data(rt);
if (nla_len(rt) < (int)xfrm_alg_auth_len(algp))
if (nla_len(rt) < (int)xfrm_alg_auth_len(algp)) {
NL_SET_ERR_MSG(extack, "Invalid AUTH_TRUNC attribute length");
return -EINVAL;
}
algp->alg_name[sizeof(algp->alg_name) - 1] = '\0';
return 0;
}
static int verify_aead(struct nlattr **attrs)
static int verify_aead(struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
struct xfrm_algo_aead *algp;
......@@ -86,8 +93,10 @@ static int verify_aead(struct nlattr **attrs)
return 0;
algp = nla_data(rt);
if (nla_len(rt) < (int)aead_len(algp))
if (nla_len(rt) < (int)aead_len(algp)) {
NL_SET_ERR_MSG(extack, "Invalid AEAD attribute length");
return -EINVAL;
}
algp->alg_name[sizeof(algp->alg_name) - 1] = '\0';
return 0;
......@@ -102,7 +111,7 @@ static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
*addrp = nla_data(rt);
}
static inline int verify_sec_ctx_len(struct nlattr **attrs)
static inline int verify_sec_ctx_len(struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
struct xfrm_user_sec_ctx *uctx;
......@@ -112,42 +121,59 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs)
uctx = nla_data(rt);
if (uctx->len > nla_len(rt) ||
uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) {
NL_SET_ERR_MSG(extack, "Invalid security context length");
return -EINVAL;
}
return 0;
}
static inline int verify_replay(struct xfrm_usersa_info *p,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
struct xfrm_replay_state_esn *rs;
if (!rt)
return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
if (!rt) {
if (p->flags & XFRM_STATE_ESN) {
NL_SET_ERR_MSG(extack, "Missing required attribute for ESN");
return -EINVAL;
}
return 0;
}
rs = nla_data(rt);
if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) {
NL_SET_ERR_MSG(extack, "ESN bitmap length must be <= 128");
return -EINVAL;
}
if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
nla_len(rt) != sizeof(*rs))
nla_len(rt) != sizeof(*rs)) {
NL_SET_ERR_MSG(extack, "ESN attribute is too short to fit the full bitmap length");
return -EINVAL;
}
/* As only ESP and AH support ESN feature. */
if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) {
NL_SET_ERR_MSG(extack, "ESN only supported for ESP and AH");
return -EINVAL;
}
if (p->replay_window != 0)
if (p->replay_window != 0) {
NL_SET_ERR_MSG(extack, "ESN not compatible with legacy replay_window");
return -EINVAL;
}
return 0;
}
static int verify_newsa_info(struct xfrm_usersa_info *p,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
int err;
......@@ -161,10 +187,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
break;
#else
err = -EAFNOSUPPORT;
NL_SET_ERR_MSG(extack, "IPv6 support disabled");
goto out;
#endif
default:
NL_SET_ERR_MSG(extack, "Invalid address family");
goto out;
}
......@@ -173,65 +201,98 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
break;
case AF_INET:
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32) {
NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 32 for IPv4)");
goto out;
}
break;
case AF_INET6:
#if IS_ENABLED(CONFIG_IPV6)
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128)
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128) {
NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 128 for IPv6)");
goto out;
}
break;
#else
NL_SET_ERR_MSG(extack, "IPv6 support disabled");
err = -EAFNOSUPPORT;
goto out;
#endif
default:
NL_SET_ERR_MSG(extack, "Invalid address family in selector");
goto out;
}
err = -EINVAL;
switch (p->id.proto) {
case IPPROTO_AH:
if ((!attrs[XFRMA_ALG_AUTH] &&
!attrs[XFRMA_ALG_AUTH_TRUNC]) ||
attrs[XFRMA_ALG_AEAD] ||
if (!attrs[XFRMA_ALG_AUTH] &&
!attrs[XFRMA_ALG_AUTH_TRUNC]) {
NL_SET_ERR_MSG(extack, "Missing required attribute for AH: AUTH_TRUNC or AUTH");
goto out;
}
if (attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_TFCPAD])
attrs[XFRMA_TFCPAD]) {
NL_SET_ERR_MSG(extack, "Invalid attributes for AH: AEAD, CRYPT, COMP, TFCPAD");
goto out;
}
break;
case IPPROTO_ESP:
if (attrs[XFRMA_ALG_COMP])
if (attrs[XFRMA_ALG_COMP]) {
NL_SET_ERR_MSG(extack, "Invalid attribute for ESP: COMP");
goto out;
}
if (!attrs[XFRMA_ALG_AUTH] &&
!attrs[XFRMA_ALG_AUTH_TRUNC] &&
!attrs[XFRMA_ALG_CRYPT] &&
!attrs[XFRMA_ALG_AEAD])
!attrs[XFRMA_ALG_AEAD]) {
NL_SET_ERR_MSG(extack, "Missing required attribute for ESP: at least one of AUTH, AUTH_TRUNC, CRYPT, AEAD");
goto out;
}
if ((attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_CRYPT]) &&
attrs[XFRMA_ALG_AEAD])
attrs[XFRMA_ALG_AEAD]) {
NL_SET_ERR_MSG(extack, "Invalid attribute combination for ESP: AEAD can't be used with AUTH, AUTH_TRUNC, CRYPT");
goto out;
}
if (attrs[XFRMA_TFCPAD] &&
p->mode != XFRM_MODE_TUNNEL)
p->mode != XFRM_MODE_TUNNEL) {
NL_SET_ERR_MSG(extack, "TFC padding can only be used in tunnel mode");
goto out;
}
break;
case IPPROTO_COMP:
if (!attrs[XFRMA_ALG_COMP] ||
attrs[XFRMA_ALG_AEAD] ||
if (!attrs[XFRMA_ALG_COMP]) {
NL_SET_ERR_MSG(extack, "Missing required attribute for COMP: COMP");
goto out;
}
if (attrs[XFRMA_ALG_AEAD] ||
attrs[XFRMA_ALG_AUTH] ||
attrs[XFRMA_ALG_AUTH_TRUNC] ||
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_TFCPAD] ||
(ntohl(p->id.spi) >= 0x10000))
attrs[XFRMA_TFCPAD]) {
NL_SET_ERR_MSG(extack, "Invalid attributes for COMP: AEAD, AUTH, AUTH_TRUNC, CRYPT, TFCPAD");
goto out;
}
if (ntohl(p->id.spi) >= 0x10000) {
NL_SET_ERR_MSG(extack, "SPI is too large for COMP (must be < 0x10000)");
goto out;
}
break;
#if IS_ENABLED(CONFIG_IPV6)
......@@ -244,29 +305,36 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
attrs[XFRMA_ALG_CRYPT] ||
attrs[XFRMA_ENCAP] ||
attrs[XFRMA_SEC_CTX] ||
attrs[XFRMA_TFCPAD] ||
!attrs[XFRMA_COADDR])
attrs[XFRMA_TFCPAD]) {
NL_SET_ERR_MSG(extack, "Invalid attributes for DSTOPTS/ROUTING");
goto out;
}
if (!attrs[XFRMA_COADDR]) {
NL_SET_ERR_MSG(extack, "Missing required COADDR attribute for DSTOPTS/ROUTING");
goto out;
}
break;
#endif
default:
NL_SET_ERR_MSG(extack, "Unsupported protocol");
goto out;
}
if ((err = verify_aead(attrs)))
if ((err = verify_aead(attrs, extack)))
goto out;
if ((err = verify_auth_trunc(attrs)))
if ((err = verify_auth_trunc(attrs, extack)))
goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH, extack)))
goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT, extack)))
goto out;
if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP, extack)))
goto out;
if ((err = verify_sec_ctx_len(attrs)))
if ((err = verify_sec_ctx_len(attrs, extack)))
goto out;
if ((err = verify_replay(p, attrs)))
if ((err = verify_replay(p, attrs, extack)))
goto out;
err = -EINVAL;
......@@ -278,14 +346,19 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported mode");
goto out;
}
err = 0;
if (attrs[XFRMA_MTIMER_THRESH])
if (!attrs[XFRMA_ENCAP])
if (attrs[XFRMA_MTIMER_THRESH]) {
if (!attrs[XFRMA_ENCAP]) {
NL_SET_ERR_MSG(extack, "MTIMER_THRESH attribute can only be set on ENCAP states");
err = -EINVAL;
goto out;
}
}
out:
return err;
......@@ -293,7 +366,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
struct xfrm_algo_desc *(*get_byname)(const char *, int),
struct nlattr *rta)
struct nlattr *rta, struct netlink_ext_ack *extack)
{
struct xfrm_algo *p, *ualg;
struct xfrm_algo_desc *algo;
......@@ -304,8 +377,10 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
ualg = nla_data(rta);
algo = get_byname(ualg->alg_name, 1);
if (!algo)
if (!algo) {
NL_SET_ERR_MSG(extack, "Requested COMP algorithm not found");
return -ENOSYS;
}
*props = algo->desc.sadb_alg_id;
p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
......@@ -317,7 +392,8 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
return 0;
}
static int attach_crypt(struct xfrm_state *x, struct nlattr *rta)
static int attach_crypt(struct xfrm_state *x, struct nlattr *rta,
struct netlink_ext_ack *extack)
{
struct xfrm_algo *p, *ualg;
struct xfrm_algo_desc *algo;
......@@ -328,8 +404,10 @@ static int attach_crypt(struct xfrm_state *x, struct nlattr *rta)
ualg = nla_data(rta);
algo = xfrm_ealg_get_byname(ualg->alg_name, 1);
if (!algo)
if (!algo) {
NL_SET_ERR_MSG(extack, "Requested CRYPT algorithm not found");
return -ENOSYS;
}
x->props.ealgo = algo->desc.sadb_alg_id;
p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
......@@ -343,7 +421,7 @@ static int attach_crypt(struct xfrm_state *x, struct nlattr *rta)
}
static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
struct nlattr *rta)
struct nlattr *rta, struct netlink_ext_ack *extack)
{
struct xfrm_algo *ualg;
struct xfrm_algo_auth *p;
......@@ -355,8 +433,10 @@ static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
ualg = nla_data(rta);
algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
if (!algo)
if (!algo) {
NL_SET_ERR_MSG(extack, "Requested AUTH algorithm not found");
return -ENOSYS;
}
*props = algo->desc.sadb_alg_id;
p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL);
......@@ -373,7 +453,7 @@ static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
}
static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
struct nlattr *rta)
struct nlattr *rta, struct netlink_ext_ack *extack)
{
struct xfrm_algo_auth *p, *ualg;
struct xfrm_algo_desc *algo;
......@@ -384,10 +464,14 @@ static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
ualg = nla_data(rta);
algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
if (!algo)
if (!algo) {
NL_SET_ERR_MSG(extack, "Requested AUTH_TRUNC algorithm not found");
return -ENOSYS;
if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
}
if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) {
NL_SET_ERR_MSG(extack, "Invalid length requested for truncated ICV");
return -EINVAL;
}
*props = algo->desc.sadb_alg_id;
p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL);
......@@ -402,7 +486,8 @@ static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
return 0;
}
static int attach_aead(struct xfrm_state *x, struct nlattr *rta)
static int attach_aead(struct xfrm_state *x, struct nlattr *rta,
struct netlink_ext_ack *extack)
{
struct xfrm_algo_aead *p, *ualg;
struct xfrm_algo_desc *algo;
......@@ -413,8 +498,10 @@ static int attach_aead(struct xfrm_state *x, struct nlattr *rta)
ualg = nla_data(rta);
algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
if (!algo)
if (!algo) {
NL_SET_ERR_MSG(extack, "Requested AEAD algorithm not found");
return -ENOSYS;
}
x->props.ealgo = algo->desc.sadb_alg_id;
p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
......@@ -579,7 +666,8 @@ static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m)
static struct xfrm_state *xfrm_state_construct(struct net *net,
struct xfrm_usersa_info *p,
struct nlattr **attrs,
int *errp)
int *errp,
struct netlink_ext_ack *extack)
{
struct xfrm_state *x = xfrm_state_alloc(net);
int err = -ENOMEM;
......@@ -606,21 +694,21 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
if (attrs[XFRMA_SA_EXTRA_FLAGS])
x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD])))
if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD], extack)))
goto error;
if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
attrs[XFRMA_ALG_AUTH_TRUNC])))
attrs[XFRMA_ALG_AUTH_TRUNC], extack)))
goto error;
if (!x->props.aalgo) {
if ((err = attach_auth(&x->aalg, &x->props.aalgo,
attrs[XFRMA_ALG_AUTH])))
attrs[XFRMA_ALG_AUTH], extack)))
goto error;
}
if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT])))
if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT], extack)))
goto error;
if ((err = attach_one_algo(&x->calg, &x->props.calgo,
xfrm_calg_get_byname,
attrs[XFRMA_ALG_COMP])))
attrs[XFRMA_ALG_COMP], extack)))
goto error;
if (attrs[XFRMA_TFCPAD])
......@@ -633,7 +721,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
if (attrs[XFRMA_IF_ID])
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV], extack);
if (err)
goto error;
......@@ -653,7 +741,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
/* sysctl_xfrm_aevent_etime is in 100ms units */
x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
if ((err = xfrm_init_replay(x)))
if ((err = xfrm_init_replay(x, extack)))
goto error;
/* override default values from above */
......@@ -662,7 +750,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
/* configure the hardware if offload is requested */
if (attrs[XFRMA_OFFLOAD_DEV]) {
err = xfrm_dev_state_add(net, x,
nla_data(attrs[XFRMA_OFFLOAD_DEV]));
nla_data(attrs[XFRMA_OFFLOAD_DEV]),
extack);
if (err)
goto error;
}
......@@ -678,7 +767,7 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
}
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_usersa_info *p = nlmsg_data(nlh);
......@@ -686,11 +775,11 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
struct km_event c;
err = verify_newsa_info(p, attrs);
err = verify_newsa_info(p, attrs, extack);
if (err)
return err;
x = xfrm_state_construct(net, p, attrs, &err);
x = xfrm_state_construct(net, p, attrs, &err, extack);
if (!x)
return err;
......@@ -757,7 +846,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_state *x;
......@@ -1254,7 +1343,8 @@ static int build_spdinfo(struct sk_buff *skb, struct net *net,
}
static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrmu_spdhthresh *thresh4 = NULL;
......@@ -1299,7 +1389,8 @@ static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct sk_buff *r_skb;
......@@ -1358,7 +1449,8 @@ static int build_sadinfo(struct sk_buff *skb, struct net *net,
}
static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct sk_buff *r_skb;
......@@ -1378,7 +1470,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_usersa_id *p = nlmsg_data(nlh);
......@@ -1402,7 +1494,8 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_state *x;
......@@ -1477,7 +1570,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
return err;
}
static int verify_policy_dir(u8 dir)
static int verify_policy_dir(u8 dir, struct netlink_ext_ack *extack)
{
switch (dir) {
case XFRM_POLICY_IN:
......@@ -1486,13 +1579,14 @@ static int verify_policy_dir(u8 dir)
break;
default:
NL_SET_ERR_MSG(extack, "Invalid policy direction");
return -EINVAL;
}
return 0;
}
static int verify_policy_type(u8 type)
static int verify_policy_type(u8 type, struct netlink_ext_ack *extack)
{
switch (type) {
case XFRM_POLICY_TYPE_MAIN:
......@@ -1502,13 +1596,15 @@ static int verify_policy_type(u8 type)
break;
default:
NL_SET_ERR_MSG(extack, "Invalid policy type");
return -EINVAL;
}
return 0;
}
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p,
struct netlink_ext_ack *extack)
{
int ret;
......@@ -1520,6 +1616,7 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
break;
default:
NL_SET_ERR_MSG(extack, "Invalid policy share");
return -EINVAL;
}
......@@ -1529,35 +1626,44 @@ static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
break;
default:
NL_SET_ERR_MSG(extack, "Invalid policy action");
return -EINVAL;
}
switch (p->sel.family) {
case AF_INET:
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32) {
NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 32 for IPv4)");
return -EINVAL;
}
break;
case AF_INET6:
#if IS_ENABLED(CONFIG_IPV6)
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128)
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128) {
NL_SET_ERR_MSG(extack, "Invalid prefix length in selector (must be <= 128 for IPv6)");
return -EINVAL;
}
break;
#else
NL_SET_ERR_MSG(extack, "IPv6 support disabled");
return -EAFNOSUPPORT;
#endif
default:
NL_SET_ERR_MSG(extack, "Invalid selector family");
return -EINVAL;
}
ret = verify_policy_dir(p->dir);
ret = verify_policy_dir(p->dir, extack);
if (ret)
return ret;
if (p->index && (xfrm_policy_id2dir(p->index) != p->dir))
if (p->index && (xfrm_policy_id2dir(p->index) != p->dir)) {
NL_SET_ERR_MSG(extack, "Policy index doesn't match direction");
return -EINVAL;
}
return 0;
}
......@@ -1599,13 +1705,16 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
}
}
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
struct netlink_ext_ack *extack)
{
u16 prev_family;
int i;
if (nr > XFRM_MAX_DEPTH)
if (nr > XFRM_MAX_DEPTH) {
NL_SET_ERR_MSG(extack, "Template count must be <= XFRM_MAX_DEPTH (" __stringify(XFRM_MAX_DEPTH) ")");
return -EINVAL;
}
prev_family = family;
......@@ -1625,12 +1734,16 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
case XFRM_MODE_BEET:
break;
default:
if (ut[i].family != prev_family)
if (ut[i].family != prev_family) {
NL_SET_ERR_MSG(extack, "Mode in template doesn't support a family change");
return -EINVAL;
}
break;
}
if (ut[i].mode >= XFRM_MODE_MAX)
if (ut[i].mode >= XFRM_MODE_MAX) {
NL_SET_ERR_MSG(extack, "Mode in template must be < XFRM_MODE_MAX (" __stringify(XFRM_MODE_MAX) ")");
return -EINVAL;
}
prev_family = ut[i].family;
......@@ -1642,17 +1755,21 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
break;
#endif
default:
NL_SET_ERR_MSG(extack, "Invalid family in template");
return -EINVAL;
}
if (!xfrm_id_proto_valid(ut[i].id.proto))
if (!xfrm_id_proto_valid(ut[i].id.proto)) {
NL_SET_ERR_MSG(extack, "Invalid XFRM protocol in template");
return -EINVAL;
}
}
return 0;
}
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_TMPL];
......@@ -1663,7 +1780,7 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
int nr = nla_len(rt) / sizeof(*utmpl);
int err;
err = validate_tmpl(nr, utmpl, pol->family);
err = validate_tmpl(nr, utmpl, pol->family, extack);
if (err)
return err;
......@@ -1672,7 +1789,8 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
return 0;
}
static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];
struct xfrm_userpolicy_type *upt;
......@@ -1684,7 +1802,7 @@ static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
type = upt->type;
}
err = verify_policy_type(type);
err = verify_policy_type(type, extack);
if (err)
return err;
......@@ -1719,7 +1837,11 @@ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_i
p->share = XFRM_SHARE_ANY; /* XXX xp->share */
}
static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
static struct xfrm_policy *xfrm_policy_construct(struct net *net,
struct xfrm_userpolicy_info *p,
struct nlattr **attrs,
int *errp,
struct netlink_ext_ack *extack)
{
struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
int err;
......@@ -1731,11 +1853,11 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
copy_from_user_policy(xp, p);
err = copy_from_user_policy_type(&xp->type, attrs);
err = copy_from_user_policy_type(&xp->type, attrs, extack);
if (err)
goto error;
if (!(err = copy_from_user_tmpl(xp, attrs)))
if (!(err = copy_from_user_tmpl(xp, attrs, extack)))
err = copy_from_user_sec_ctx(xp, attrs);
if (err)
goto error;
......@@ -1754,7 +1876,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
}
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
......@@ -1763,14 +1886,14 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
int excl;
err = verify_newpolicy_info(p);
err = verify_newpolicy_info(p, extack);
if (err)
return err;
err = verify_sec_ctx_len(attrs);
err = verify_sec_ctx_len(attrs, extack);
if (err)
return err;
xp = xfrm_policy_construct(net, p, attrs, &err);
xp = xfrm_policy_construct(net, p, attrs, &err, extack);
if (!xp)
return err;
......@@ -2015,7 +2138,7 @@ static bool xfrm_userpolicy_is_valid(__u8 policy)
}
static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_userpolicy_default *up = nlmsg_data(nlh);
......@@ -2036,7 +2159,7 @@ static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct sk_buff *r_skb;
struct nlmsghdr *r_nlh;
......@@ -2066,7 +2189,8 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_policy *xp;
......@@ -2081,11 +2205,11 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
p = nlmsg_data(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
err = copy_from_user_policy_type(&type, attrs);
err = copy_from_user_policy_type(&type, attrs, extack);
if (err)
return err;
err = verify_policy_dir(p->dir);
err = verify_policy_dir(p->dir, extack);
if (err)
return err;
......@@ -2101,7 +2225,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
struct xfrm_sec_ctx *ctx;
err = verify_sec_ctx_len(attrs);
err = verify_sec_ctx_len(attrs, extack);
if (err)
return err;
......@@ -2149,7 +2273,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct km_event c;
......@@ -2249,7 +2374,7 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
}
static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_state *x;
......@@ -2293,7 +2418,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_state *x;
......@@ -2344,14 +2469,15 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct km_event c;
u8 type = XFRM_POLICY_TYPE_MAIN;
int err;
err = copy_from_user_policy_type(&type, attrs);
err = copy_from_user_policy_type(&type, attrs, extack);
if (err)
return err;
......@@ -2372,7 +2498,8 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_policy *xp;
......@@ -2383,11 +2510,11 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_mark m;
u32 if_id = 0;
err = copy_from_user_policy_type(&type, attrs);
err = copy_from_user_policy_type(&type, attrs, extack);
if (err)
return err;
err = verify_policy_dir(p->dir);
err = verify_policy_dir(p->dir, extack);
if (err)
return err;
......@@ -2403,7 +2530,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
struct xfrm_sec_ctx *ctx;
err = verify_sec_ctx_len(attrs);
err = verify_sec_ctx_len(attrs, extack);
if (err)
return err;
......@@ -2438,7 +2565,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_state *x;
......@@ -2472,7 +2600,8 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct xfrm_policy *xp;
......@@ -2490,15 +2619,15 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
xfrm_mark_get(attrs, &mark);
err = verify_newpolicy_info(&ua->policy);
err = verify_newpolicy_info(&ua->policy, extack);
if (err)
goto free_state;
err = verify_sec_ctx_len(attrs);
err = verify_sec_ctx_len(attrs, extack);
if (err)
goto free_state;
/* build an XP */
xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
xp = xfrm_policy_construct(net, &ua->policy, attrs, &err, extack);
if (!xp)
goto free_state;
......@@ -2577,7 +2706,7 @@ static int copy_from_user_migrate(struct xfrm_migrate *ma,
}
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
struct xfrm_migrate m[XFRM_MAX_DEPTH];
......@@ -2594,7 +2723,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
err = copy_from_user_policy_type(&type, attrs);
err = copy_from_user_policy_type(&type, attrs, extack);
if (err)
return err;
......@@ -2623,7 +2752,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
}
#else
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr **attrs)
struct nlattr **attrs, struct netlink_ext_ack *extack)
{
return -ENOPROTOOPT;
}
......@@ -2819,7 +2948,8 @@ static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
};
static const struct xfrm_link {
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **,
struct netlink_ext_ack *);
int (*start)(struct netlink_callback *);
int (*dump)(struct sk_buff *, struct netlink_callback *);
int (*done)(struct netlink_callback *);
......@@ -2921,7 +3051,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
goto err;
}
err = link->doit(skb, nlh, attrs);
err = link->doit(skb, nlh, attrs, extack);
/* We need to free skb allocated in xfrm_alloc_compat() before
* returning from this function, because consume_skb() won't take
......@@ -3272,11 +3402,11 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
*dir = -EINVAL;
if (len < sizeof(*p) ||
verify_newpolicy_info(p))
verify_newpolicy_info(p, NULL))
return NULL;
nr = ((len - sizeof(*p)) / sizeof(*ut));
if (validate_tmpl(nr, ut, p->sel.family))
if (validate_tmpl(nr, ut, p->sel.family, NULL))
return NULL;
if (p->dir > XFRM_POLICY_OUT)
......
......@@ -58,6 +58,8 @@
#define VETH_FMT "ktst-%d"
#define VETH_LEN 12
#define XFRM_ALGO_NR_KEYS 29
static int nsfd_parent = -1;
static int nsfd_childa = -1;
static int nsfd_childb = -1;
......@@ -75,6 +77,43 @@ const unsigned int ping_timeout = 300;
const unsigned int ping_count = 100;
const unsigned int ping_success = 80;
struct xfrm_key_entry {
char algo_name[35];
int key_len;
};
struct xfrm_key_entry xfrm_key_entries[] = {
{"digest_null", 0},
{"ecb(cipher_null)", 0},
{"cbc(des)", 64},
{"hmac(md5)", 128},
{"cmac(aes)", 128},
{"xcbc(aes)", 128},
{"cbc(cast5)", 128},
{"cbc(serpent)", 128},
{"hmac(sha1)", 160},
{"hmac(rmd160)", 160},
{"cbc(des3_ede)", 192},
{"hmac(sha256)", 256},
{"cbc(aes)", 256},
{"cbc(camellia)", 256},
{"cbc(twofish)", 256},
{"rfc3686(ctr(aes))", 288},
{"hmac(sha384)", 384},
{"cbc(blowfish)", 448},
{"hmac(sha512)", 512},
{"rfc4106(gcm(aes))-128", 160},
{"rfc4543(gcm(aes))-128", 160},
{"rfc4309(ccm(aes))-128", 152},
{"rfc4106(gcm(aes))-192", 224},
{"rfc4543(gcm(aes))-192", 224},
{"rfc4309(ccm(aes))-192", 216},
{"rfc4106(gcm(aes))-256", 288},
{"rfc4543(gcm(aes))-256", 288},
{"rfc4309(ccm(aes))-256", 280},
{"rfc7539(chacha20,poly1305)-128", 0}
};
static void randomize_buffer(void *buf, size_t buflen)
{
int *p = (int *)buf;
......@@ -767,65 +806,12 @@ static int do_ping(int cmd_fd, char *buf, size_t buf_len, struct in_addr from,
static int xfrm_fill_key(char *name, char *buf,
size_t buf_len, unsigned int *key_len)
{
/* TODO: use set/map instead */
if (strncmp(name, "digest_null", ALGO_LEN) == 0)
*key_len = 0;
else if (strncmp(name, "ecb(cipher_null)", ALGO_LEN) == 0)
*key_len = 0;
else if (strncmp(name, "cbc(des)", ALGO_LEN) == 0)
*key_len = 64;
else if (strncmp(name, "hmac(md5)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cmac(aes)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "xcbc(aes)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cbc(cast5)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "cbc(serpent)", ALGO_LEN) == 0)
*key_len = 128;
else if (strncmp(name, "hmac(sha1)", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "hmac(rmd160)", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "cbc(des3_ede)", ALGO_LEN) == 0)
*key_len = 192;
else if (strncmp(name, "hmac(sha256)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(aes)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(camellia)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "cbc(twofish)", ALGO_LEN) == 0)
*key_len = 256;
else if (strncmp(name, "rfc3686(ctr(aes))", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "hmac(sha384)", ALGO_LEN) == 0)
*key_len = 384;
else if (strncmp(name, "cbc(blowfish)", ALGO_LEN) == 0)
*key_len = 448;
else if (strncmp(name, "hmac(sha512)", ALGO_LEN) == 0)
*key_len = 512;
else if (strncmp(name, "rfc4106(gcm(aes))-128", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "rfc4543(gcm(aes))-128", ALGO_LEN) == 0)
*key_len = 160;
else if (strncmp(name, "rfc4309(ccm(aes))-128", ALGO_LEN) == 0)
*key_len = 152;
else if (strncmp(name, "rfc4106(gcm(aes))-192", ALGO_LEN) == 0)
*key_len = 224;
else if (strncmp(name, "rfc4543(gcm(aes))-192", ALGO_LEN) == 0)
*key_len = 224;
else if (strncmp(name, "rfc4309(ccm(aes))-192", ALGO_LEN) == 0)
*key_len = 216;
else if (strncmp(name, "rfc4106(gcm(aes))-256", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "rfc4543(gcm(aes))-256", ALGO_LEN) == 0)
*key_len = 288;
else if (strncmp(name, "rfc4309(ccm(aes))-256", ALGO_LEN) == 0)
*key_len = 280;
else if (strncmp(name, "rfc7539(chacha20,poly1305)-128", ALGO_LEN) == 0)
*key_len = 0;
int i;
for (i = 0; i < XFRM_ALGO_NR_KEYS; i++) {
if (strncmp(name, xfrm_key_entries[i].algo_name, ALGO_LEN) == 0)
*key_len = xfrm_key_entries[i].key_len;
}
if (*key_len > buf_len) {
printk("Can't pack a key - too big for buffer");
......
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