From ced0f1911830eceae26c737e93b44136828f2f13 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 13 Jan 2019 20:00:53 +0000 Subject: [PATCH] Ensure our aes_ni_context is 16-byte aligned. The 32-bit x86 Windows build can crash with an alignment fault the first time it tries to write into the key schedule array, because it turns out that the x86 VS C library's malloc doesn't guarantee 16-byte alignment on the returned block even though there is a machine type that needs it. To avoid having to faff with non-portable library APIs, I solve the problem locally in aes_hw_new, by over-allocating enough to guarantee that an aligned block of the right size must exist somewhere in the region. --- sshaes.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/sshaes.c b/sshaes.c index 346e4805..f79ed6b1 100644 --- a/sshaes.c +++ b/sshaes.c @@ -1330,6 +1330,7 @@ typedef struct aes_ni_context aes_ni_context; struct aes_ni_context { __m128i keysched_e[MAXROUNDKEYS], keysched_d[MAXROUNDKEYS], iv; + void *pointer_to_free; ssh2_cipher ciph; }; @@ -1338,16 +1339,30 @@ static ssh2_cipher *aes_hw_new(const ssh2_cipheralg *alg) if (!aes_hw_available_cached()) return NULL; - aes_ni_context *ctx = snew(aes_ni_context); + /* + * The __m128i variables in the context structure need to be + * 16-byte aligned, but not all malloc implementations that this + * code has to work with will guarantee to return a 16-byte + * aligned pointer. So we over-allocate, manually realign the + * pointer ourselves, and store the original one inside the + * context so we know how to free it later. + */ + void *allocation = smalloc(sizeof(aes_ni_context) + 15); + uintptr_t alloc_address = (uintptr_t)allocation; + uintptr_t aligned_address = (alloc_address + 15) & ~15; + aes_ni_context *ctx = (aes_ni_context *)aligned_address; + ctx->ciph.vt = alg; + ctx->pointer_to_free = allocation; return &ctx->ciph; } static void aes_hw_free(ssh2_cipher *ciph) { aes_ni_context *ctx = container_of(ciph, aes_ni_context, ciph); + void *allocation = ctx->pointer_to_free; smemclr(ctx, sizeof(*ctx)); - sfree(ctx); + sfree(allocation); } static void aes_hw_setkey(ssh2_cipher *ciph, const void *vkey)