diff mbox

[v2,11/11] crypto: skcipher: Remove VLA usage for SKCIPHER_REQUEST_ON_STACK

Message ID 20180625211026.15819-12-keescook@chromium.org (mailing list archive)
State Superseded, archived
Delegated to: Mike Snitzer
Headers show

Commit Message

Kees Cook June 25, 2018, 9:10 p.m. UTC
In the quest to remove all stack VLA usage from the kernel[1], this
caps the skcipher request size similar to other limits and adds a
sanity check at registration. In a manual review of the callers of
crypto_skcipher_set_reqsize(), the largest was 384:

4	sun4i_cipher_req_ctx
6	safexcel_cipher_req
8	cryptd_skcipher_request_ctx
80	cipher_req_ctx
80	skcipher_request
96	crypto_rfc3686_req_ctx
104	nitrox_kcrypt_request
144	mv_cesa_skcipher_std_req
384	rctx

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-crypto@vger.kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 include/crypto/internal/skcipher.h | 1 +
 include/crypto/skcipher.h          | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

Comments

Herbert Xu June 26, 2018, 9:20 a.m. UTC | #1
On Mon, Jun 25, 2018 at 02:10:26PM -0700, Kees Cook wrote:
> In the quest to remove all stack VLA usage from the kernel[1], this
> caps the skcipher request size similar to other limits and adds a
> sanity check at registration. In a manual review of the callers of
> crypto_skcipher_set_reqsize(), the largest was 384:
> 
> 4	sun4i_cipher_req_ctx
> 6	safexcel_cipher_req
> 8	cryptd_skcipher_request_ctx
> 80	cipher_req_ctx
> 80	skcipher_request
> 96	crypto_rfc3686_req_ctx
> 104	nitrox_kcrypt_request
> 144	mv_cesa_skcipher_std_req
> 384	rctx
> 
> [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com
> 
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: linux-crypto@vger.kernel.org
> Signed-off-by: Kees Cook <keescook@chromium.org>

This has the same issue as the ahash reqsize patch.

Cheers,
Kees Cook June 26, 2018, 4:45 p.m. UTC | #2
On Tue, Jun 26, 2018 at 2:20 AM, Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Mon, Jun 25, 2018 at 02:10:26PM -0700, Kees Cook wrote:
>> In the quest to remove all stack VLA usage from the kernel[1], this
>> caps the skcipher request size similar to other limits and adds a
>> sanity check at registration. In a manual review of the callers of
>> crypto_skcipher_set_reqsize(), the largest was 384:
>>
>> 4     sun4i_cipher_req_ctx
>> 6     safexcel_cipher_req
>> 8     cryptd_skcipher_request_ctx
>> 80    cipher_req_ctx
>> 80    skcipher_request
>> 96    crypto_rfc3686_req_ctx
>> 104   nitrox_kcrypt_request
>> 144   mv_cesa_skcipher_std_req
>> 384   rctx
>>
>> [1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com
>>
>> Cc: Herbert Xu <herbert@gondor.apana.org.au>
>> Cc: "David S. Miller" <davem@davemloft.net>
>> Cc: linux-crypto@vger.kernel.org
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>
> This has the same issue as the ahash reqsize patch.

Which are likely to be wrapped together? Should I take this to 512 or
something else?

-Kees
Herbert Xu June 27, 2018, 2:36 p.m. UTC | #3
On Tue, Jun 26, 2018 at 09:45:09AM -0700, Kees Cook wrote:
>
> Which are likely to be wrapped together? Should I take this to 512 or
> something else?

The situation is similar to ahash.  While they're using the same
skcipher interface, the underlying algorithms must all be
synchronous.  In fact, if they're not then they're buggy.

Therefore it makes no sense to use the general skcipher request
size as a threshold.  You should look at synchronous skcipher
algorithms only.

Cheers,
Kees Cook June 27, 2018, 6:31 p.m. UTC | #4
On Wed, Jun 27, 2018 at 7:36 AM, Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Tue, Jun 26, 2018 at 09:45:09AM -0700, Kees Cook wrote:
>>
>> Which are likely to be wrapped together? Should I take this to 512 or
>> something else?
>
> The situation is similar to ahash.  While they're using the same
> skcipher interface, the underlying algorithms must all be
> synchronous.  In fact, if they're not then they're buggy.
>
> Therefore it makes no sense to use the general skcipher request
> size as a threshold.  You should look at synchronous skcipher
> algorithms only.

I might be catching on... so from this list, I should only "count" the
synchronous ones as being wrappable? The skcipher list is actually
pretty short:

crypto/cryptd.c:        crypto_skcipher_set_reqsize(
crypto/cryptd.c-                tfm, sizeof(struct
cryptd_skcipher_request_ctx));

The above is, AIUI, unwrapped, so I only need to count sizeof(struct
cryptd_skcipher_request_ctx)?

These are "simple" wrappers:

crypto/lrw.c:   crypto_skcipher_set_reqsize(tfm,
crypto_skcipher_reqsize(cipher) +
crypto/lrw.c-                                    sizeof(struct rctx));

crypto/simd.c-  reqsize = sizeof(struct skcipher_request);
crypto/simd.c-  reqsize += crypto_skcipher_reqsize(&cryptd_tfm->base);
crypto/simd.c:  crypto_skcipher_set_reqsize(tfm, reqsize);

crypto/xts.c:   crypto_skcipher_set_reqsize(tfm,
crypto_skcipher_reqsize(child) +
crypto/xts.c-                                    sizeof(struct rctx));

But what are the "legitimate" existing crypto_skcipher_reqsize() values here?

These are "complex" wrappers, with cts even adding blocksize to the mix...

crypto/ctr.c-   align = crypto_skcipher_alignmask(tfm);
crypto/ctr.c-   align &= ~(crypto_tfm_ctx_alignment() - 1);
crypto/ctr.c-   reqsize = align + sizeof(struct crypto_rfc3686_req_ctx) +
crypto/ctr.c-             crypto_skcipher_reqsize(cipher);
crypto/ctr.c:   crypto_skcipher_set_reqsize(tfm, reqsize);

crypto/cts.c-   align = crypto_skcipher_alignmask(tfm);
crypto/cts.c-   bsize = crypto_skcipher_blocksize(cipher);
crypto/cts.c-   reqsize = ALIGN(sizeof(struct crypto_cts_reqctx) +
crypto/cts.c-                   crypto_skcipher_reqsize(cipher),
crypto/cts.c-                   crypto_tfm_ctx_alignment()) +
crypto/cts.c-             (align & ~(crypto_tfm_ctx_alignment() - 1)) + bsize;
crypto/cts.c-
crypto/cts.c:   crypto_skcipher_set_reqsize(tfm, reqsize);

What values might be expected here? It seems the entire blocksize
needs to be included as well...

-Kees
Herbert Xu June 27, 2018, 10:27 p.m. UTC | #5
On Wed, Jun 27, 2018 at 11:31:09AM -0700, Kees Cook wrote:
>
> I might be catching on... so from this list, I should only "count" the
> synchronous ones as being wrappable? The skcipher list is actually
> pretty short:
> 
> crypto/cryptd.c:        crypto_skcipher_set_reqsize(
> crypto/cryptd.c-                tfm, sizeof(struct
> cryptd_skcipher_request_ctx));

cryptd is async so you don't have to include it.
 
> These are "simple" wrappers:
> 
> crypto/lrw.c:   crypto_skcipher_set_reqsize(tfm,
> crypto_skcipher_reqsize(cipher) +
> crypto/lrw.c-                                    sizeof(struct rctx));
> 
> crypto/simd.c-  reqsize = sizeof(struct skcipher_request);
> crypto/simd.c-  reqsize += crypto_skcipher_reqsize(&cryptd_tfm->base);
> crypto/simd.c:  crypto_skcipher_set_reqsize(tfm, reqsize);

simd is async.

> crypto/xts.c:   crypto_skcipher_set_reqsize(tfm,
> crypto_skcipher_reqsize(child) +
> crypto/xts.c-                                    sizeof(struct rctx));
> 
> But what are the "legitimate" existing crypto_skcipher_reqsize() values here?
> 
> These are "complex" wrappers, with cts even adding blocksize to the mix...
> 
> crypto/ctr.c-   align = crypto_skcipher_alignmask(tfm);
> crypto/ctr.c-   align &= ~(crypto_tfm_ctx_alignment() - 1);
> crypto/ctr.c-   reqsize = align + sizeof(struct crypto_rfc3686_req_ctx) +
> crypto/ctr.c-             crypto_skcipher_reqsize(cipher);
> crypto/ctr.c:   crypto_skcipher_set_reqsize(tfm, reqsize);
> 
> crypto/cts.c-   align = crypto_skcipher_alignmask(tfm);
> crypto/cts.c-   bsize = crypto_skcipher_blocksize(cipher);
> crypto/cts.c-   reqsize = ALIGN(sizeof(struct crypto_cts_reqctx) +
> crypto/cts.c-                   crypto_skcipher_reqsize(cipher),
> crypto/cts.c-                   crypto_tfm_ctx_alignment()) +
> crypto/cts.c-             (align & ~(crypto_tfm_ctx_alignment() - 1)) + bsize;
> crypto/cts.c-
> crypto/cts.c:   crypto_skcipher_set_reqsize(tfm, reqsize);
> 
> What values might be expected here? It seems the entire blocksize
> needs to be included as well...

But otherwise yes these are the ones that count.

Cheers,
Kees Cook June 28, 2018, 12:10 a.m. UTC | #6
On Wed, Jun 27, 2018 at 3:27 PM, Herbert Xu <herbert@gondor.apana.org.au> wrote:
> On Wed, Jun 27, 2018 at 11:31:09AM -0700, Kees Cook wrote:
>> crypto/lrw.c:   crypto_skcipher_set_reqsize(tfm,
>> crypto_skcipher_reqsize(cipher) +
>> crypto/lrw.c-                                    sizeof(struct rctx));
>> ...
>> crypto/cts.c-   align = crypto_skcipher_alignmask(tfm);
>> crypto/cts.c-   bsize = crypto_skcipher_blocksize(cipher);
>> crypto/cts.c-   reqsize = ALIGN(sizeof(struct crypto_cts_reqctx) +
>> crypto/cts.c-                   crypto_skcipher_reqsize(cipher),
>> crypto/cts.c-                   crypto_tfm_ctx_alignment()) +
>> crypto/cts.c-             (align & ~(crypto_tfm_ctx_alignment() - 1)) + bsize;
>> crypto/cts.c-
>> crypto/cts.c:   crypto_skcipher_set_reqsize(tfm, reqsize);
>>
>> What values might be expected here? It seems the entire blocksize
>> needs to be included as well...
>
> But otherwise yes these are the ones that count.

In both cases here, what is "cipher"? i.e. what ciphers could lrw be
wrapping, and what ciphers could cts be wrapping, so that I can
examine the blocksizes, etc?

FWIW, looking at the non-ASYNC wrappers, I see only:

crypto/ctr.c
crypto/cts.c
crypto/lrw.c
crypto/xts.c
drivers/crypto/sunxi-ss/sun4i-ss-cipher.c

Building in all crypto things and running tcrypt with an instrumented
crypto_skcipher_set_reqsize, I see:

# dmesg | grep skcipher_set_req | cut -c16- | sort -u | sort +1 -n
crypto_skcipher_set_reqsize: 8
crypto_skcipher_set_reqsize: 88
crypto_skcipher_set_reqsize: 184
crypto_skcipher_set_reqsize: 256
crypto_skcipher_set_reqsize: 472

The 472 maps to lrw with its 384 struct rctx:

[  553.843884] tcrypt: testing lrw(twofish)
[  553.844479] crypto_skcipher_set_reqsize: 8
[  553.845076] crypto_skcipher_set_reqsize: 88
[  553.845658] crypto_skcipher_set_reqsize: 472

[  553.860578] tcrypt: testing lrw(serpent)
[  553.861349] crypto_skcipher_set_reqsize: 8
[  553.861960] crypto_skcipher_set_reqsize: 88
[  553.862534] crypto_skcipher_set_reqsize: 472

[  553.871676] tcrypt: testing lrw(aes)
[  553.872398] crypto_skcipher_set_reqsize: 8
[  553.873002] crypto_skcipher_set_reqsize: 88
[  553.873574] crypto_skcipher_set_reqsize: 472

[  553.957282] tcrypt: testing lrw(cast6)
[  553.958098] crypto_skcipher_set_reqsize: 8
[  553.958691] crypto_skcipher_set_reqsize: 88
[  553.959311] crypto_skcipher_set_reqsize: 472

[  553.982514] tcrypt: testing lrw(camellia)
[  553.983308] crypto_skcipher_set_reqsize: 8
[  553.983907] crypto_skcipher_set_reqsize: 88
[  553.984470] crypto_skcipher_set_reqsize: 472

And while I'm using tcrypt, ahash shows:

44
124
336
368
528
536
568
616
648
728
808

The largest seems to be sha512:

[  553.883440] tcrypt: testing sha512
[  553.884179] sha512_mb: crypto_ahash_set_reqsize: 528
[  553.884904] crypto_ahash_set_reqsize: 728
[  553.885449] sha512_mb: crypto_ahash_set_reqsize: 808

So ... should I use 472 for skcipher and 808 for ahash?

-Kees
Herbert Xu July 1, 2018, 6:24 a.m. UTC | #7
On Wed, Jun 27, 2018 at 05:10:05PM -0700, Kees Cook wrote:
>
> In both cases here, what is "cipher"? i.e. what ciphers could lrw be
> wrapping, and what ciphers could cts be wrapping, so that I can
> examine the blocksizes, etc?

A cipher is a simple cipher like aes that operates on a single
block.

Cheers,
diff mbox

Patch

diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
index e42f7063f245..5035482cbe68 100644
--- a/include/crypto/internal/skcipher.h
+++ b/include/crypto/internal/skcipher.h
@@ -130,6 +130,7 @@  static inline struct crypto_skcipher *crypto_spawn_skcipher(
 static inline void crypto_skcipher_set_reqsize(
 	struct crypto_skcipher *skcipher, unsigned int reqsize)
 {
+	BUG_ON(reqsize > SKCIPHER_MAX_REQSIZE);
 	skcipher->reqsize = reqsize;
 }
 
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
index 2f327f090c3e..26eba8304d1d 100644
--- a/include/crypto/skcipher.h
+++ b/include/crypto/skcipher.h
@@ -139,9 +139,11 @@  struct skcipher_alg {
 	struct crypto_alg base;
 };
 
+#define SKCIPHER_MAX_REQSIZE	384
+
 #define SKCIPHER_REQUEST_ON_STACK(name, tfm) \
 	char __##name##_desc[sizeof(struct skcipher_request) + \
-		crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \
+		SKCIPHER_MAX_REQSIZE] CRYPTO_MINALIGN_ATTR; \
 	struct skcipher_request *name = (void *)__##name##_desc
 
 /**