Commit c30f66b4 authored by David S. Miller's avatar David S. Miller

[IPSEC/CRYPTO]: Allocate work buffers instead of using kstack.

parent 63ba5a82
...@@ -108,6 +108,8 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ...@@ -108,6 +108,8 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
if (tfm == NULL) if (tfm == NULL)
goto out_put; goto out_put;
memset(tfm, 0, sizeof(*tfm));
if (alg->cra_ctxsize) { if (alg->cra_ctxsize) {
tfm->crt_ctx = kmalloc(alg->cra_ctxsize, GFP_KERNEL); tfm->crt_ctx = kmalloc(alg->cra_ctxsize, GFP_KERNEL);
if (tfm->crt_ctx == NULL) if (tfm->crt_ctx == NULL)
...@@ -116,13 +118,24 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) ...@@ -116,13 +118,24 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
tfm->__crt_alg = alg; tfm->__crt_alg = alg;
if (alg->cra_blocksize) {
tfm->crt_work_block = kmalloc(alg->cra_blocksize + 1,
GFP_KERNEL);
if (tfm->crt_work_block == NULL)
goto out_free_ctx;
}
if (crypto_init_flags(tfm, flags)) if (crypto_init_flags(tfm, flags))
goto out_free_ctx; goto out_free_work_block;
crypto_init_ops(tfm); crypto_init_ops(tfm);
goto out; goto out;
out_free_work_block:
if (tfm->__crt_alg->cra_blocksize)
kfree(tfm->crt_work_block);
out_free_ctx: out_free_ctx:
if (tfm->__crt_alg->cra_ctxsize) if (tfm->__crt_alg->cra_ctxsize)
kfree(tfm->crt_ctx); kfree(tfm->crt_ctx);
...@@ -140,6 +153,9 @@ void crypto_free_tfm(struct crypto_tfm *tfm) ...@@ -140,6 +153,9 @@ void crypto_free_tfm(struct crypto_tfm *tfm)
if (tfm->__crt_alg->cra_ctxsize) if (tfm->__crt_alg->cra_ctxsize)
kfree(tfm->crt_ctx); kfree(tfm->crt_ctx);
if (tfm->__crt_alg->cra_blocksize)
kfree(tfm->crt_work_block);
if (crypto_tfm_alg_type(tfm) == CRYPTO_ALG_TYPE_CIPHER) if (crypto_tfm_alg_type(tfm) == CRYPTO_ALG_TYPE_CIPHER)
if (tfm->crt_cipher.cit_iv) if (tfm->crt_cipher.cit_iv)
kfree(tfm->crt_cipher.cit_iv); kfree(tfm->crt_cipher.cit_iv);
......
...@@ -35,14 +35,14 @@ void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen) ...@@ -35,14 +35,14 @@ void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
{ {
unsigned int i; unsigned int i;
struct scatterlist tmp; struct scatterlist tmp;
char ipad[crypto_tfm_alg_blocksize(tfm) + 1]; char *ipad = tfm->crt_work_block;
if (*keylen > crypto_tfm_alg_blocksize(tfm)) { if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen); hash_key(tfm, key, *keylen);
*keylen = crypto_tfm_alg_digestsize(tfm); *keylen = crypto_tfm_alg_digestsize(tfm);
} }
memset(ipad, 0, sizeof(ipad)); memset(ipad, 0, crypto_tfm_alg_blocksize(tfm) + 1);
memcpy(ipad, key, *keylen); memcpy(ipad, key, *keylen);
for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
...@@ -67,7 +67,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ...@@ -67,7 +67,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
{ {
unsigned int i; unsigned int i;
struct scatterlist tmp; struct scatterlist tmp;
char opad[crypto_tfm_alg_blocksize(tfm) + 1]; char *opad = tfm->crt_work_block;
if (*keylen > crypto_tfm_alg_blocksize(tfm)) { if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen); hash_key(tfm, key, *keylen);
...@@ -76,7 +76,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key, ...@@ -76,7 +76,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
crypto_digest_final(tfm, out); crypto_digest_final(tfm, out);
memset(opad, 0, sizeof(opad)); memset(opad, 0, crypto_tfm_alg_blocksize(tfm) + 1);
memcpy(opad, key, *keylen); memcpy(opad, key, *keylen);
for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
......
...@@ -157,6 +157,7 @@ struct compress_tfm { ...@@ -157,6 +157,7 @@ struct compress_tfm {
struct crypto_tfm { struct crypto_tfm {
void *crt_ctx; void *crt_ctx;
void *crt_work_block;
u32 crt_flags; u32 crt_flags;
union { union {
......
...@@ -11,6 +11,7 @@ struct ah_data ...@@ -11,6 +11,7 @@ struct ah_data
{ {
u8 *key; u8 *key;
int key_len; int key_len;
u8 *work_digest;
int digest_len; int digest_len;
void (*digest)(struct ah_data*, void (*digest)(struct ah_data*,
...@@ -142,13 +143,12 @@ static void ...@@ -142,13 +143,12 @@ static void
ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data) ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
{ {
struct crypto_tfm *tfm = ahp->tfm; struct crypto_tfm *tfm = ahp->tfm;
char digest[crypto_tfm_alg_digestsize(tfm)];
memset(auth_data, 0, ahp->digest_len); memset(auth_data, 0, ahp->digest_len);
crypto_hmac_init(tfm, ahp->key, &ahp->key_len); crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
skb_ah_walk(skb, tfm); skb_ah_walk(skb, tfm);
crypto_hmac_final(tfm, ahp->key, &ahp->key_len, digest); crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_digest);
memcpy(auth_data, digest, ahp->digest_len); memcpy(auth_data, ahp->work_digest, ahp->digest_len);
} }
int ah_output(struct sk_buff *skb) int ah_output(struct sk_buff *skb)
...@@ -335,11 +335,19 @@ int ah_init_state(struct xfrm_state *x, void *args) ...@@ -335,11 +335,19 @@ int ah_init_state(struct xfrm_state *x, void *args)
if (ahp == NULL) if (ahp == NULL)
return -ENOMEM; return -ENOMEM;
memset(ahp, 0, sizeof(*ahp));
ahp->key = x->aalg->alg_key; ahp->key = x->aalg->alg_key;
ahp->key_len = (x->aalg->alg_key_len+7)/8; ahp->key_len = (x->aalg->alg_key_len+7)/8;
ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
if (!ahp->tfm)
goto error;
ahp->digest = ah_hmac_digest; ahp->digest = ah_hmac_digest;
ahp->digest_len = 12; ahp->digest_len = 12;
ahp->work_digest = kmalloc(crypto_tfm_alg_digestsize(ahp->tfm),
GFP_KERNEL);
if (!ahp->work_digest)
goto error;
x->props.header_len = (12 + ahp->digest_len + 7)&~7; x->props.header_len = (12 + ahp->digest_len + 7)&~7;
if (x->props.mode) if (x->props.mode)
x->props.header_len += 20; x->props.header_len += 20;
...@@ -349,6 +357,8 @@ int ah_init_state(struct xfrm_state *x, void *args) ...@@ -349,6 +357,8 @@ int ah_init_state(struct xfrm_state *x, void *args)
error: error:
if (ahp) { if (ahp) {
if (ahp->work_digest)
kfree(ahp->work_digest);
if (ahp->tfm) if (ahp->tfm)
crypto_free_tfm(ahp->tfm); crypto_free_tfm(ahp->tfm);
kfree(ahp); kfree(ahp);
...@@ -360,6 +370,10 @@ void ah_destroy(struct xfrm_state *x) ...@@ -360,6 +370,10 @@ void ah_destroy(struct xfrm_state *x)
{ {
struct ah_data *ahp = x->data; struct ah_data *ahp = x->data;
if (ahp->work_digest) {
kfree(ahp->work_digest);
ahp->work_digest = NULL;
}
if (ahp->tfm) { if (ahp->tfm) {
crypto_free_tfm(ahp->tfm); crypto_free_tfm(ahp->tfm);
ahp->tfm = NULL; ahp->tfm = NULL;
......
...@@ -34,6 +34,7 @@ struct esp_data ...@@ -34,6 +34,7 @@ struct esp_data
struct { struct {
u8 *key; /* Key */ u8 *key; /* Key */
int key_len; /* Length of the key */ int key_len; /* Length of the key */
u8 *work_digest;
/* authlen is length of trailer containing auth token. /* authlen is length of trailer containing auth token.
* If it is not zero it is assumed to be * If it is not zero it is assumed to be
* >= crypto_tfm_alg_digestsize(atfm) */ * >= crypto_tfm_alg_digestsize(atfm) */
...@@ -187,7 +188,7 @@ esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset, ...@@ -187,7 +188,7 @@ esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
int len, u8 *auth_data) int len, u8 *auth_data)
{ {
struct crypto_tfm *tfm = esp->auth.tfm; struct crypto_tfm *tfm = esp->auth.tfm;
char digest[crypto_tfm_alg_digestsize(tfm)]; char *digest = esp->auth.work_digest;
memset(auth_data, 0, esp->auth.authlen); memset(auth_data, 0, esp->auth.authlen);
crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len); crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
...@@ -579,6 +580,10 @@ void esp_destroy(struct xfrm_state *x) ...@@ -579,6 +580,10 @@ void esp_destroy(struct xfrm_state *x)
crypto_free_tfm(esp->auth.tfm); crypto_free_tfm(esp->auth.tfm);
esp->auth.tfm = NULL; esp->auth.tfm = NULL;
} }
if (esp->auth.work_digest) {
kfree(esp->auth.work_digest);
esp->auth.work_digest = NULL;
}
} }
int esp_init_state(struct xfrm_state *x, void *args) int esp_init_state(struct xfrm_state *x, void *args)
...@@ -596,6 +601,8 @@ int esp_init_state(struct xfrm_state *x, void *args) ...@@ -596,6 +601,8 @@ int esp_init_state(struct xfrm_state *x, void *args)
if (esp == NULL) if (esp == NULL)
return -ENOMEM; return -ENOMEM;
memset(esp, 0, sizeof(*esp));
if (x->aalg) { if (x->aalg) {
esp->auth.key = x->aalg->alg_key; esp->auth.key = x->aalg->alg_key;
esp->auth.key_len = (x->aalg->alg_key_len+7)/8; esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
...@@ -604,6 +611,9 @@ int esp_init_state(struct xfrm_state *x, void *args) ...@@ -604,6 +611,9 @@ int esp_init_state(struct xfrm_state *x, void *args)
goto error; goto error;
esp->auth.digest = esp_hmac_digest; esp->auth.digest = esp_hmac_digest;
esp->auth.authlen = crypto_tfm_alg_digestsize(esp->auth.tfm); esp->auth.authlen = crypto_tfm_alg_digestsize(esp->auth.tfm);
esp->auth.work_digest = kmalloc(esp->auth.authlen, GFP_KERNEL);
if (!esp->auth.work_digest)
goto error;
} }
esp->conf.key = x->ealg->alg_key; esp->conf.key = x->ealg->alg_key;
esp->conf.key_len = (x->ealg->alg_key_len+7)/8; esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
...@@ -628,6 +638,8 @@ int esp_init_state(struct xfrm_state *x, void *args) ...@@ -628,6 +638,8 @@ int esp_init_state(struct xfrm_state *x, void *args)
if (esp) { if (esp) {
if (esp->auth.tfm) if (esp->auth.tfm)
crypto_free_tfm(esp->auth.tfm); crypto_free_tfm(esp->auth.tfm);
if (esp->auth.work_digest)
kfree(esp->auth.work_digest);
if (esp->conf.tfm) if (esp->conf.tfm)
crypto_free_tfm(esp->conf.tfm); crypto_free_tfm(esp->conf.tfm);
kfree(esp); kfree(esp);
......
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