Re: [PATCH v3] mac80211: move struct aead_req off the stack

2016-10-17 Thread Ard Biesheuvel
On 17 October 2016 at 09:03, Johannes Berg  wrote:
> From: Johannes Berg 
>
> Some crypto implementations (such as the generic CCM wrapper in crypto/)
> use scatterlists to map fields of private data in their struct aead_req.
> This means these data structures cannot live in the vmalloc area, which
> means that they cannot live on the stack (with CONFIG_VMAP_STACK.)
>
> This currently occurs only with the generic software implementation, but
> the private data and usage is implementation specific, so move the whole
> data structures off the stack into heap by allocating every time we need
> to use them.
>
> This pattern already exists in the IPsec ESP driver, but in the future,
> we may want/need to improve upon this, e.g. by using a slab cache.
>
> (Based on Ard's patch, but that was missing error handling and GCM/GMAC)
>
> Signed-off-by: Ard Biesheuvel 
> Signed-off-by: Johannes Berg 
> ---
> v3: remove superfluous aead_request_set_tfm() calls

Reviewed-by: Ard Biesheuvel 

> ---
>  net/mac80211/aes_ccm.c  | 36 +++-
>  net/mac80211/aes_ccm.h  |  6 +++---
>  net/mac80211/aes_gcm.c  | 33 +
>  net/mac80211/aes_gcm.h  |  4 ++--
>  net/mac80211/aes_gmac.c | 11 +--
>  net/mac80211/wpa.c  | 12 
>  6 files changed, 50 insertions(+), 52 deletions(-)
>
> diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
> index 7663c28ba353..8e898a6e8de8 100644
> --- a/net/mac80211/aes_ccm.c
> +++ b/net/mac80211/aes_ccm.c
> @@ -18,29 +18,29 @@
>  #include "key.h"
>  #include "aes_ccm.h"
>
> -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
> -  u8 *data, size_t data_len, u8 *mic,
> -  size_t mic_len)
> +int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
> + u8 *data, size_t data_len, u8 *mic,
> + size_t mic_len)
>  {
> struct scatterlist sg[3];
> +   struct aead_request *aead_req;
>
> -   char aead_req_data[sizeof(struct aead_request) +
> -  crypto_aead_reqsize(tfm)]
> -   __aligned(__alignof__(struct aead_request));
> -   struct aead_request *aead_req = (void *) aead_req_data;
> -
> -   memset(aead_req, 0, sizeof(aead_req_data));
> +   aead_req = aead_request_alloc(tfm, GFP_ATOMIC);
> +   if (!aead_req)
> +   return -ENOMEM;
>
> sg_init_table(sg, 3);
> sg_set_buf([0], [2], be16_to_cpup((__be16 *)aad));
> sg_set_buf([1], data, data_len);
> sg_set_buf([2], mic, mic_len);
>
> -   aead_request_set_tfm(aead_req, tfm);
> aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
> aead_request_set_ad(aead_req, sg[0].length);
>
> crypto_aead_encrypt(aead_req);
> +   aead_request_free(aead_req);
> +
> +   return 0;
>  }
>
>  int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
> @@ -48,26 +48,28 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 
> *b_0, u8 *aad,
>   size_t mic_len)
>  {
> struct scatterlist sg[3];
> -   char aead_req_data[sizeof(struct aead_request) +
> -  crypto_aead_reqsize(tfm)]
> -   __aligned(__alignof__(struct aead_request));
> -   struct aead_request *aead_req = (void *) aead_req_data;
> +   struct aead_request *aead_req;
> +   int err;
>
> if (data_len == 0)
> return -EINVAL;
>
> -   memset(aead_req, 0, sizeof(aead_req_data));
> +   aead_req = aead_request_alloc(tfm, GFP_ATOMIC);
> +   if (!aead_req)
> +   return -ENOMEM;
>
> sg_init_table(sg, 3);
> sg_set_buf([0], [2], be16_to_cpup((__be16 *)aad));
> sg_set_buf([1], data, data_len);
> sg_set_buf([2], mic, mic_len);
>
> -   aead_request_set_tfm(aead_req, tfm);
> aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
> aead_request_set_ad(aead_req, sg[0].length);
>
> -   return crypto_aead_decrypt(aead_req);
> +   err = crypto_aead_decrypt(aead_req);
> +   aead_request_free(aead_req);
> +
> +   return err;
>  }
>
>  struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
> diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
> index 6a73d1e4d186..03e21b0995e3 100644
> --- a/net/mac80211/aes_ccm.h
> +++ b/net/mac80211/aes_ccm.h
> @@ -15,9 +15,9 @@
>  struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
> size_t key_len,
> size_t mic_len);
> -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
> -  u8 *data, 

[PATCH v3] mac80211: move struct aead_req off the stack

2016-10-17 Thread Johannes Berg
From: Johannes Berg 

Some crypto implementations (such as the generic CCM wrapper in crypto/)
use scatterlists to map fields of private data in their struct aead_req.
This means these data structures cannot live in the vmalloc area, which
means that they cannot live on the stack (with CONFIG_VMAP_STACK.)

This currently occurs only with the generic software implementation, but
the private data and usage is implementation specific, so move the whole
data structures off the stack into heap by allocating every time we need
to use them.

This pattern already exists in the IPsec ESP driver, but in the future,
we may want/need to improve upon this, e.g. by using a slab cache.

(Based on Ard's patch, but that was missing error handling and GCM/GMAC)

Signed-off-by: Ard Biesheuvel 
Signed-off-by: Johannes Berg 
---
v3: remove superfluous aead_request_set_tfm() calls
---
 net/mac80211/aes_ccm.c  | 36 +++-
 net/mac80211/aes_ccm.h  |  6 +++---
 net/mac80211/aes_gcm.c  | 33 +
 net/mac80211/aes_gcm.h  |  4 ++--
 net/mac80211/aes_gmac.c | 11 +--
 net/mac80211/wpa.c  | 12 
 6 files changed, 50 insertions(+), 52 deletions(-)

diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 7663c28ba353..8e898a6e8de8 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -18,29 +18,29 @@
 #include "key.h"
 #include "aes_ccm.h"
 
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-  u8 *data, size_t data_len, u8 *mic,
-  size_t mic_len)
+int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+ u8 *data, size_t data_len, u8 *mic,
+ size_t mic_len)
 {
struct scatterlist sg[3];
+   struct aead_request *aead_req;
 
-   char aead_req_data[sizeof(struct aead_request) +
-  crypto_aead_reqsize(tfm)]
-   __aligned(__alignof__(struct aead_request));
-   struct aead_request *aead_req = (void *) aead_req_data;
-
-   memset(aead_req, 0, sizeof(aead_req_data));
+   aead_req = aead_request_alloc(tfm, GFP_ATOMIC);
+   if (!aead_req)
+   return -ENOMEM;
 
sg_init_table(sg, 3);
sg_set_buf([0], [2], be16_to_cpup((__be16 *)aad));
sg_set_buf([1], data, data_len);
sg_set_buf([2], mic, mic_len);
 
-   aead_request_set_tfm(aead_req, tfm);
aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
aead_request_set_ad(aead_req, sg[0].length);
 
crypto_aead_encrypt(aead_req);
+   aead_request_free(aead_req);
+
+   return 0;
 }
 
 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
@@ -48,26 +48,28 @@ int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 
*b_0, u8 *aad,
  size_t mic_len)
 {
struct scatterlist sg[3];
-   char aead_req_data[sizeof(struct aead_request) +
-  crypto_aead_reqsize(tfm)]
-   __aligned(__alignof__(struct aead_request));
-   struct aead_request *aead_req = (void *) aead_req_data;
+   struct aead_request *aead_req;
+   int err;
 
if (data_len == 0)
return -EINVAL;
 
-   memset(aead_req, 0, sizeof(aead_req_data));
+   aead_req = aead_request_alloc(tfm, GFP_ATOMIC);
+   if (!aead_req)
+   return -ENOMEM;
 
sg_init_table(sg, 3);
sg_set_buf([0], [2], be16_to_cpup((__be16 *)aad));
sg_set_buf([1], data, data_len);
sg_set_buf([2], mic, mic_len);
 
-   aead_request_set_tfm(aead_req, tfm);
aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
aead_request_set_ad(aead_req, sg[0].length);
 
-   return crypto_aead_decrypt(aead_req);
+   err = crypto_aead_decrypt(aead_req);
+   aead_request_free(aead_req);
+
+   return err;
 }
 
 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
index 6a73d1e4d186..03e21b0995e3 100644
--- a/net/mac80211/aes_ccm.h
+++ b/net/mac80211/aes_ccm.h
@@ -15,9 +15,9 @@
 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
size_t key_len,
size_t mic_len);
-void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
-  u8 *data, size_t data_len, u8 *mic,
-  size_t mic_len);
+int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
+ u8 *data, size_t data_len, u8 *mic,
+ size_t mic_len);
 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,