Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: move struct aead_req off the stack

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.

In addition, take care not to put any of our own stack allocations into
scatterlists. This involves reserving some extra room when allocating the
aead_request structures, and referring to those allocations in the scatter-
lists (while copying the data from the stack before the crypto operation)

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ard Biesheuvel and committed by
Johannes Berg
f4a067f9 1d4de2e2

+93 -62
+30 -16
net/mac80211/aes_ccm.c
··· 18 18 #include "key.h" 19 19 #include "aes_ccm.h" 20 20 21 - void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 22 - u8 *data, size_t data_len, u8 *mic, 23 - size_t mic_len) 21 + int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 22 + u8 *data, size_t data_len, u8 *mic, 23 + size_t mic_len) 24 24 { 25 25 struct scatterlist sg[3]; 26 + struct aead_request *aead_req; 27 + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 28 + u8 *__aad; 26 29 27 - char aead_req_data[sizeof(struct aead_request) + 28 - crypto_aead_reqsize(tfm)] 29 - __aligned(__alignof__(struct aead_request)); 30 - struct aead_request *aead_req = (void *) aead_req_data; 30 + aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC); 31 + if (!aead_req) 32 + return -ENOMEM; 31 33 32 - memset(aead_req, 0, sizeof(aead_req_data)); 34 + __aad = (u8 *)aead_req + reqsize; 35 + memcpy(__aad, aad, CCM_AAD_LEN); 33 36 34 37 sg_init_table(sg, 3); 35 - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); 38 + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); 36 39 sg_set_buf(&sg[1], data, data_len); 37 40 sg_set_buf(&sg[2], mic, mic_len); 38 41 ··· 44 41 aead_request_set_ad(aead_req, sg[0].length); 45 42 46 43 crypto_aead_encrypt(aead_req); 44 + kzfree(aead_req); 45 + 46 + return 0; 47 47 } 48 48 49 49 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, ··· 54 48 size_t mic_len) 55 49 { 56 50 struct scatterlist sg[3]; 57 - char aead_req_data[sizeof(struct aead_request) + 58 - crypto_aead_reqsize(tfm)] 59 - __aligned(__alignof__(struct aead_request)); 60 - struct aead_request *aead_req = (void *) aead_req_data; 51 + struct aead_request *aead_req; 52 + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 53 + u8 *__aad; 54 + int err; 61 55 62 56 if (data_len == 0) 63 57 return -EINVAL; 64 58 65 - memset(aead_req, 0, sizeof(aead_req_data)); 59 + aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC); 60 + if (!aead_req) 61 + return -ENOMEM; 62 + 63 + __aad = (u8 *)aead_req + reqsize; 64 + memcpy(__aad, aad, CCM_AAD_LEN); 66 65 67 66 sg_init_table(sg, 3); 68 - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); 67 + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); 69 68 sg_set_buf(&sg[1], data, data_len); 70 69 sg_set_buf(&sg[2], mic, mic_len); 71 70 ··· 78 67 aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); 79 68 aead_request_set_ad(aead_req, sg[0].length); 80 69 81 - return crypto_aead_decrypt(aead_req); 70 + err = crypto_aead_decrypt(aead_req); 71 + kzfree(aead_req); 72 + 73 + return err; 82 74 } 83 75 84 76 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
+5 -3
net/mac80211/aes_ccm.h
··· 12 12 13 13 #include <linux/crypto.h> 14 14 15 + #define CCM_AAD_LEN 32 16 + 15 17 struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], 16 18 size_t key_len, 17 19 size_t mic_len); 18 - void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 19 - u8 *data, size_t data_len, u8 *mic, 20 - size_t mic_len); 20 + int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 21 + u8 *data, size_t data_len, u8 *mic, 22 + size_t mic_len); 21 23 int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, 22 24 u8 *data, size_t data_len, u8 *mic, 23 25 size_t mic_len);
+28 -15
net/mac80211/aes_gcm.c
··· 15 15 #include "key.h" 16 16 #include "aes_gcm.h" 17 17 18 - void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 19 - u8 *data, size_t data_len, u8 *mic) 18 + int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 19 + u8 *data, size_t data_len, u8 *mic) 20 20 { 21 21 struct scatterlist sg[3]; 22 + struct aead_request *aead_req; 23 + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 24 + u8 *__aad; 22 25 23 - char aead_req_data[sizeof(struct aead_request) + 24 - crypto_aead_reqsize(tfm)] 25 - __aligned(__alignof__(struct aead_request)); 26 - struct aead_request *aead_req = (void *)aead_req_data; 26 + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); 27 + if (!aead_req) 28 + return -ENOMEM; 27 29 28 - memset(aead_req, 0, sizeof(aead_req_data)); 30 + __aad = (u8 *)aead_req + reqsize; 31 + memcpy(__aad, aad, GCM_AAD_LEN); 29 32 30 33 sg_init_table(sg, 3); 31 - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); 34 + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); 32 35 sg_set_buf(&sg[1], data, data_len); 33 36 sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); 34 37 ··· 40 37 aead_request_set_ad(aead_req, sg[0].length); 41 38 42 39 crypto_aead_encrypt(aead_req); 40 + kzfree(aead_req); 41 + return 0; 43 42 } 44 43 45 44 int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 46 45 u8 *data, size_t data_len, u8 *mic) 47 46 { 48 47 struct scatterlist sg[3]; 49 - char aead_req_data[sizeof(struct aead_request) + 50 - crypto_aead_reqsize(tfm)] 51 - __aligned(__alignof__(struct aead_request)); 52 - struct aead_request *aead_req = (void *)aead_req_data; 48 + struct aead_request *aead_req; 49 + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 50 + u8 *__aad; 51 + int err; 53 52 54 53 if (data_len == 0) 55 54 return -EINVAL; 56 55 57 - memset(aead_req, 0, sizeof(aead_req_data)); 56 + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); 57 + if (!aead_req) 58 + return -ENOMEM; 59 + 60 + __aad = (u8 *)aead_req + reqsize; 61 + memcpy(__aad, aad, GCM_AAD_LEN); 58 62 59 63 sg_init_table(sg, 3); 60 - sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); 64 + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); 61 65 sg_set_buf(&sg[1], data, data_len); 62 66 sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); 63 67 ··· 73 63 data_len + IEEE80211_GCMP_MIC_LEN, j_0); 74 64 aead_request_set_ad(aead_req, sg[0].length); 75 65 76 - return crypto_aead_decrypt(aead_req); 66 + err = crypto_aead_decrypt(aead_req); 67 + kzfree(aead_req); 68 + 69 + return err; 77 70 } 78 71 79 72 struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
+4 -2
net/mac80211/aes_gcm.h
··· 11 11 12 12 #include <linux/crypto.h> 13 13 14 - void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 15 - u8 *data, size_t data_len, u8 *mic); 14 + #define GCM_AAD_LEN 32 15 + 16 + int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 17 + u8 *data, size_t data_len, u8 *mic); 16 18 int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, 17 19 u8 *data, size_t data_len, u8 *mic); 18 20 struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
+13 -13
net/mac80211/aes_gmac.c
··· 17 17 #include "key.h" 18 18 #include "aes_gmac.h" 19 19 20 - #define GMAC_MIC_LEN 16 21 - #define GMAC_NONCE_LEN 12 22 - #define AAD_LEN 20 23 - 24 20 int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, 25 21 const u8 *data, size_t data_len, u8 *mic) 26 22 { 27 23 struct scatterlist sg[4]; 28 - char aead_req_data[sizeof(struct aead_request) + 29 - crypto_aead_reqsize(tfm)] 30 - __aligned(__alignof__(struct aead_request)); 31 - struct aead_request *aead_req = (void *)aead_req_data; 32 - u8 zero[GMAC_MIC_LEN], iv[AES_BLOCK_SIZE]; 24 + u8 *zero, *__aad, iv[AES_BLOCK_SIZE]; 25 + struct aead_request *aead_req; 26 + int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); 33 27 34 28 if (data_len < GMAC_MIC_LEN) 35 29 return -EINVAL; 36 30 37 - memset(aead_req, 0, sizeof(aead_req_data)); 31 + aead_req = kzalloc(reqsize + GMAC_MIC_LEN + GMAC_AAD_LEN, GFP_ATOMIC); 32 + if (!aead_req) 33 + return -ENOMEM; 38 34 39 - memset(zero, 0, GMAC_MIC_LEN); 35 + zero = (u8 *)aead_req + reqsize; 36 + __aad = zero + GMAC_MIC_LEN; 37 + memcpy(__aad, aad, GMAC_AAD_LEN); 38 + 40 39 sg_init_table(sg, 4); 41 - sg_set_buf(&sg[0], aad, AAD_LEN); 40 + sg_set_buf(&sg[0], __aad, GMAC_AAD_LEN); 42 41 sg_set_buf(&sg[1], data, data_len - GMAC_MIC_LEN); 43 42 sg_set_buf(&sg[2], zero, GMAC_MIC_LEN); 44 43 sg_set_buf(&sg[3], mic, GMAC_MIC_LEN); ··· 48 49 49 50 aead_request_set_tfm(aead_req, tfm); 50 51 aead_request_set_crypt(aead_req, sg, sg, 0, iv); 51 - aead_request_set_ad(aead_req, AAD_LEN + data_len); 52 + aead_request_set_ad(aead_req, GMAC_AAD_LEN + data_len); 52 53 53 54 crypto_aead_encrypt(aead_req); 55 + kzfree(aead_req); 54 56 55 57 return 0; 56 58 }
+4
net/mac80211/aes_gmac.h
··· 11 11 12 12 #include <linux/crypto.h> 13 13 14 + #define GMAC_AAD_LEN 20 15 + #define GMAC_MIC_LEN 16 16 + #define GMAC_NONCE_LEN 12 17 + 14 18 struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], 15 19 size_t key_len); 16 20 int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
+9 -13
net/mac80211/wpa.c
··· 405 405 u8 *pos; 406 406 u8 pn[6]; 407 407 u64 pn64; 408 - u8 aad[2 * AES_BLOCK_SIZE]; 408 + u8 aad[CCM_AAD_LEN]; 409 409 u8 b_0[AES_BLOCK_SIZE]; 410 410 411 411 if (info->control.hw_key && ··· 461 461 462 462 pos += IEEE80211_CCMP_HDR_LEN; 463 463 ccmp_special_blocks(skb, pn, b_0, aad); 464 - ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, 465 - skb_put(skb, mic_len), mic_len); 466 - 467 - return 0; 464 + return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, 465 + skb_put(skb, mic_len), mic_len); 468 466 } 469 467 470 468 ··· 637 639 u8 *pos; 638 640 u8 pn[6]; 639 641 u64 pn64; 640 - u8 aad[2 * AES_BLOCK_SIZE]; 642 + u8 aad[GCM_AAD_LEN]; 641 643 u8 j_0[AES_BLOCK_SIZE]; 642 644 643 645 if (info->control.hw_key && ··· 694 696 695 697 pos += IEEE80211_GCMP_HDR_LEN; 696 698 gcmp_special_blocks(skb, pn, j_0, aad); 697 - ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, 698 - skb_put(skb, IEEE80211_GCMP_MIC_LEN)); 699 - 700 - return 0; 699 + return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len, 700 + skb_put(skb, IEEE80211_GCMP_MIC_LEN)); 701 701 } 702 702 703 703 ieee80211_tx_result ··· 1119 1123 struct ieee80211_key *key = tx->key; 1120 1124 struct ieee80211_mmie_16 *mmie; 1121 1125 struct ieee80211_hdr *hdr; 1122 - u8 aad[20]; 1126 + u8 aad[GMAC_AAD_LEN]; 1123 1127 u64 pn64; 1124 - u8 nonce[12]; 1128 + u8 nonce[GMAC_NONCE_LEN]; 1125 1129 1126 1130 if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) 1127 1131 return TX_DROP; ··· 1167 1171 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 1168 1172 struct ieee80211_key *key = rx->key; 1169 1173 struct ieee80211_mmie_16 *mmie; 1170 - u8 aad[20], mic[16], ipn[6], nonce[12]; 1174 + u8 aad[GMAC_AAD_LEN], mic[GMAC_MIC_LEN], ipn[6], nonce[GMAC_NONCE_LEN]; 1171 1175 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 1172 1176 1173 1177 if (!ieee80211_is_mgmt(hdr->frame_control))