diff --git a/crypto/authenc.c b/crypto/authenc.c index 3f0ed9402..17ce66bba 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -449,6 +449,8 @@ static int crypto_authenc_create(struct crypto_template *tmpl, inst->alg.base.cra_flags = (auth_base->cra_flags | enc->base.cra_flags) & CRYPTO_ALG_ASYNC; + inst->alg.base.cra_flags |= (auth_base->cra_flags | + enc->base.cra_flags) & CRYPTO_ALG_NOSUPP_SG; inst->alg.base.cra_priority = enc->base.cra_priority * 10 + auth_base->cra_priority; inst->alg.base.cra_blocksize = enc->base.cra_blocksize; diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 19ea3a371..1463e824c 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -104,6 +104,11 @@ */ #define CRYPTO_NOLOAD 0x00008000 +/* + * Set this flag if algorithm does not support SG list transforms + */ +#define CRYPTO_ALG_NOSUPP_SG 0x0000c000 + /* * Transform masks and values (for crt_flags). */ diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 5c9677640..23b3a9e91 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -488,6 +488,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) struct ip_esp_hdr *esph; struct crypto_aead *aead; struct esp_info esp; + bool nosupp_sg; esp.inplace = true; @@ -499,6 +500,11 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) aead = x->data; alen = crypto_aead_authsize(aead); + nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; + if (nosupp_sg && skb_linearize(skb)) { + return -ENOMEM; + } + esp.tfclen = 0; if (x->tfcpad) { struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); @@ -708,6 +714,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) u8 *iv; struct scatterlist *sg; int err = -EINVAL; + bool nosupp_sg; if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) goto out; @@ -715,6 +722,12 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) if (elen <= 0) goto out; + nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; + if (nosupp_sg && skb_linearize(skb)) { + err = -ENOMEM; + goto out; + } + assoclen = sizeof(struct ip_esp_hdr); seqhilen = 0; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index a3b403ba8..019bea284 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -429,6 +429,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) struct ip_esp_hdr *esph; struct crypto_aead *aead; struct esp_info esp; + bool nosupp_sg; esp.inplace = true; @@ -440,6 +441,11 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) aead = x->data; alen = crypto_aead_authsize(aead); + nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; + if (nosupp_sg && skb_linearize(skb)) { + return -ENOMEM; + } + esp.tfclen = 0; if (x->tfcpad) { struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); @@ -603,6 +609,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) __be32 *seqhi; u8 *iv; struct scatterlist *sg; + bool nosupp_sg; if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) { ret = -EINVAL; @@ -614,6 +621,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) goto out; } + nosupp_sg = crypto_tfm_alg_type(&aead->base) & CRYPTO_ALG_NOSUPP_SG; + if (nosupp_sg && skb_linearize(skb)) { + ret = -ENOMEM; + goto out; + } + assoclen = sizeof(struct ip_esp_hdr); seqhilen = 0;