linuxkm/lkcapi_sha_glue.c: fix sha.W lifecycle management to prevent leaks:

* separate WC_LINUXKM_SHA_IMPLEMENT() into WC_LINUXKM_SHA1_IMPLEMENT() (no fixes
  needed) and WC_LINUXKM_SHA2_IMPLEMENT() (with associated new helpers
  WC_LINUXKM_SHA2_FREE_W(), WC_LINUXKM_SHA2_DECL_W(), WC_LINUXKM_SHA2_PUSH_W(),
  and WC_LINUXKM_SHA2_POP_W(), that move .W to a stack buffer).

* Reimplement SHA-2 one-shot digest callback to use only direct wolfCrypt calls
  rather than proxy to other callbacks.
This commit is contained in:
Daniel Pouzzner
2026-07-24 16:39:54 -05:00
parent 51c5df3a25
commit dc16169cd3
5 changed files with 208 additions and 27 deletions
+180 -6
View File
@@ -486,7 +486,7 @@ WC_MAYBE_UNUSED static int sha3_test_once(void) {
}
#endif
#define WC_LINUXKM_SHA_IMPLEMENT(name, digest_size, block_size, \
#define WC_LINUXKM_SHA1_IMPLEMENT(name, digest_size, block_size, \
this_cra_name, this_cra_driver_name, \
init_f, update_f, final_f, \
free_f, test_routine) \
@@ -588,6 +588,169 @@ static int linuxkm_test_ ## name(void) { \
\
struct wc_swallow_the_semicolon
#ifdef WOLFSSL_SMALL_STACK_CACHE
/* The glue layer needs to take ownership of the .W working buffer to assure
* it can't leak on abandoned descs, or double-free on export-import cycled
* descs. It's small enough to fit comfortably on the stack, so there's
* almost no overhead associated with this.
*
* Eager allocation of .W in SHA-2 init is to assure no heap operations in
* SHA-2 after init, mitigating an infinite recursion: The wolfCrypt DRBG
* sits atop SHA-2, and when LINUXKM_DRBG_GET_RANDOM_BYTES &&
* WOLFSSL_LINUXKM_HAVE_GET_RANDOM_CALLBACKS && CONFIG_SLAB_FREELIST_RANDOM,
* it sits _under_ the kernel heap.
*/
#define WC_LINUXKM_SHA2_FREE_W(s) do { free((s)->W); (s)->W = NULL; } while (0)
#define WC_LINUXKM_SHA2_DECL_W(s, l) wc_static_assert((l) % sizeof (s)->W[0] == 0); \
typeof((s)->W[0]) w_buf[(l) / sizeof (s)->W[0]]
#define WC_LINUXKM_SHA2_PUSH_W(s) { (s)->W = w_buf
#define WC_LINUXKM_SHA2_POP_W(s) ForceZero(w_buf, sizeof w_buf); (s)->W = NULL; } WC_DO_NOTHING
#else
#define WC_LINUXKM_SHA2_FREE_W(s) WC_DO_NOTHING
#define WC_LINUXKM_SHA2_DECL_W(s, l) struct wc_swallow_the_semicolon
#define WC_LINUXKM_SHA2_PUSH_W(s) { WC_DO_NOTHING
#define WC_LINUXKM_SHA2_POP_W(s) } WC_DO_NOTHING
#endif
#define WC_LINUXKM_SHA2_IMPLEMENT(name, digest_size, block_size, W_size, \
this_cra_name, this_cra_driver_name, \
init_f, update_f, final_f, \
free_f, test_routine) \
\
\
static int km_ ## name ## _init(struct shash_desc *desc) { \
struct km_sha_state *ctx = (struct km_sha_state *)shash_desc_ctx(desc);\
\
int ret = init_f(&ctx-> name ## _state); \
if (ret == 0) { \
WC_LINUXKM_SHA2_FREE_W(&ctx-> name ## _state); \
return 0; \
} \
else \
return -EINVAL; \
} \
\
static int km_ ## name ## _update(struct shash_desc *desc, const u8 *data, \
unsigned int len) \
{ \
struct km_sha_state *ctx = (struct km_sha_state *)shash_desc_ctx(desc);\
int ret; \
WC_LINUXKM_SHA2_DECL_W(&ctx-> name ## _state, W_size); \
\
WC_LINUXKM_SHA2_PUSH_W(&ctx-> name ## _state); \
ret = update_f(&ctx-> name ## _state, data, len); \
WC_LINUXKM_SHA2_POP_W(&ctx-> name ## _state); \
\
if (ret == 0) \
return 0; \
else { \
free_f(&ctx-> name ## _state); \
return -EINVAL; \
} \
} \
\
static int km_ ## name ## _final(struct shash_desc *desc, u8 *out) { \
struct km_sha_state *ctx = (struct km_sha_state *)shash_desc_ctx(desc);\
int ret; \
WC_LINUXKM_SHA2_DECL_W(&ctx-> name ## _state, W_size); \
\
WC_LINUXKM_SHA2_PUSH_W(&ctx-> name ## _state); \
ret = final_f(&ctx-> name ## _state, out); \
WC_LINUXKM_SHA2_POP_W(&ctx-> name ## _state); \
\
free_f(&ctx-> name ## _state); \
\
if (ret == 0) \
return 0; \
else \
return -EINVAL; \
} \
\
static int km_ ## name ## _finup(struct shash_desc *desc, const u8 *data, \
unsigned int len, u8 *out) \
{ \
struct km_sha_state *ctx = (struct km_sha_state *)shash_desc_ctx(desc);\
int ret; \
WC_LINUXKM_SHA2_DECL_W(&ctx-> name ## _state, W_size); \
\
WC_LINUXKM_SHA2_PUSH_W(&ctx-> name ## _state); \
ret = update_f(&ctx-> name ## _state, data, len); \
WC_LINUXKM_SHA2_POP_W(&ctx-> name ## _state); \
\
if (ret != 0) { \
free_f(&ctx-> name ## _state); \
return -EINVAL; \
} \
\
WC_LINUXKM_SHA2_PUSH_W(&ctx-> name ## _state); \
ret = final_f(&ctx-> name ## _state, out); \
WC_LINUXKM_SHA2_POP_W(&ctx-> name ## _state); \
\
free_f(&ctx-> name ## _state); \
\
if (ret == 0) \
return 0; \
else \
return -EINVAL; \
} \
\
static int km_ ## name ## _digest(struct shash_desc *desc, const u8 *data, \
unsigned int len, u8 *out) \
{ \
struct km_sha_state *ctx = (struct km_sha_state *)shash_desc_ctx(desc);\
int ret; \
\
ret = init_f(&ctx-> name ## _state); \
if (ret != 0) \
return -EINVAL; \
\
ret = update_f(&ctx-> name ## _state, data, len); \
\
if (ret == 0) \
ret = final_f(&ctx-> name ## _state, out); \
\
free_f(&ctx-> name ## _state); \
\
if (ret == 0) \
return 0; \
else \
return -EINVAL; \
} \
\
\
static struct shash_alg name ## _alg = \
{ \
.digestsize = (digest_size), \
.init = km_ ## name ## _init, \
.update = km_ ## name ## _update, \
.final = km_ ## name ## _final, \
.finup = km_ ## name ## _finup, \
.digest = km_ ## name ## _digest, \
.descsize = sizeof(struct km_sha_state), \
.base = { \
.cra_name = (this_cra_name), \
.cra_driver_name = (this_cra_driver_name), \
.cra_priority = WOLFSSL_LINUXKM_LKCAPI_PRIORITY, \
.cra_blocksize = (block_size), \
.cra_module = THIS_MODULE \
} \
}; \
static int name ## _alg_loaded = 0; \
\
static int linuxkm_test_ ## name(void) { \
wc_test_ret_t ret = test_routine(); \
if (ret >= 0) \
return check_shash_driver_masking(NULL /* tfm */, this_cra_name, \
this_cra_driver_name); \
else { \
wc_test_render_error_message("linuxkm_test_" #name " failed: ", \
ret); \
return WC_TEST_RET_DEC_EC(ret); \
} \
} \
\
struct wc_swallow_the_semicolon
#define WC_LINUXKM_SHA3_IMPLEMENT(name, digest_size, block_size, \
this_cra_name, this_cra_driver_name, \
init_f, update_f, final_f, \
@@ -699,35 +862,46 @@ static int linuxkm_test_ ## name(void) { \
struct wc_swallow_the_semicolon
#ifdef LINUXKM_LKCAPI_REGISTER_SHA1
WC_LINUXKM_SHA_IMPLEMENT(sha1, WC_SHA_DIGEST_SIZE, WC_SHA_BLOCK_SIZE,
WC_LINUXKM_SHA1_IMPLEMENT(sha1, WC_SHA_DIGEST_SIZE, WC_SHA_BLOCK_SIZE,
WOLFKM_SHA1_NAME, WOLFKM_SHA1_DRIVER,
wc_InitSha, wc_ShaUpdate, wc_ShaFinal,
wc_ShaFree, sha_test);
#endif
#ifndef WC_SHA256_W_SIZE
#define WC_SHA256_W_SIZE (sizeof(word32) * WC_SHA256_BLOCK_SIZE)
#endif
#ifndef WC_SHA512_W_SIZE
#define WC_SHA512_W_SIZE ((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE)
#endif
#ifdef LINUXKM_LKCAPI_REGISTER_SHA2_224
WC_LINUXKM_SHA_IMPLEMENT(sha2_224, WC_SHA224_DIGEST_SIZE, WC_SHA224_BLOCK_SIZE,
WC_LINUXKM_SHA2_IMPLEMENT(sha2_224, WC_SHA224_DIGEST_SIZE, WC_SHA224_BLOCK_SIZE,
WC_SHA256_W_SIZE,
WOLFKM_SHA2_224_NAME, WOLFKM_SHA2_224_DRIVER,
wc_InitSha224, wc_Sha224Update, wc_Sha224Final,
wc_Sha224Free, sha224_test);
#endif
#ifdef LINUXKM_LKCAPI_REGISTER_SHA2_256
WC_LINUXKM_SHA_IMPLEMENT(sha2_256, WC_SHA256_DIGEST_SIZE, WC_SHA256_BLOCK_SIZE,
WC_LINUXKM_SHA2_IMPLEMENT(sha2_256, WC_SHA256_DIGEST_SIZE, WC_SHA256_BLOCK_SIZE,
WC_SHA256_W_SIZE,
WOLFKM_SHA2_256_NAME, WOLFKM_SHA2_256_DRIVER,
wc_InitSha256, wc_Sha256Update, wc_Sha256Final,
wc_Sha256Free, sha256_test);
#endif
#ifdef LINUXKM_LKCAPI_REGISTER_SHA2_384
WC_LINUXKM_SHA_IMPLEMENT(sha2_384, WC_SHA384_DIGEST_SIZE, WC_SHA384_BLOCK_SIZE,
WC_LINUXKM_SHA2_IMPLEMENT(sha2_384, WC_SHA384_DIGEST_SIZE, WC_SHA384_BLOCK_SIZE,
WC_SHA512_W_SIZE,
WOLFKM_SHA2_384_NAME, WOLFKM_SHA2_384_DRIVER,
wc_InitSha384, wc_Sha384Update, wc_Sha384Final,
wc_Sha384Free, sha384_test);
#endif
#ifdef LINUXKM_LKCAPI_REGISTER_SHA2_512
WC_LINUXKM_SHA_IMPLEMENT(sha2_512, WC_SHA512_DIGEST_SIZE, WC_SHA512_BLOCK_SIZE,
WC_LINUXKM_SHA2_IMPLEMENT(sha2_512, WC_SHA512_DIGEST_SIZE, WC_SHA512_BLOCK_SIZE,
WC_SHA512_W_SIZE,
WOLFKM_SHA2_512_NAME, WOLFKM_SHA2_512_DRIVER,
wc_InitSha512, wc_Sha512Update, wc_Sha512Final,
wc_Sha512Free, sha512_test);
+11 -11
View File
@@ -747,7 +747,7 @@ static int InitSha256(wc_Sha256* sha256)
sha256->devCtx = NULL;
#endif
#ifdef WOLFSSL_SMALL_STACK_CACHE
sha256->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
sha256->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
sha256->heap, DYNAMIC_TYPE_DIGEST);
if (sha256->W == NULL)
return MEMORY_E;
@@ -1329,7 +1329,7 @@ int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId)
#endif
#ifdef WOLFSSL_SMALL_STACK_CACHE
sha256->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
sha256->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
sha256->heap, DYNAMIC_TYPE_DIGEST);
if (sha256->W == NULL)
return MEMORY_E;
@@ -1482,7 +1482,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
sha256->devCtx = NULL;
#endif
#ifdef WOLFSSL_SMALL_STACK_CACHE
sha256->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
sha256->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
sha256->heap, DYNAMIC_TYPE_DIGEST);
if (sha256->W == NULL)
return MEMORY_E;
@@ -1570,12 +1570,12 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
return BAD_FUNC_ARG;
#elif defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
word32* W;
W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
sha256->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (W == NULL)
return MEMORY_E;
#else
word32 W[WC_SHA256_BLOCK_SIZE];
word32 W[WC_SHA256_W_SIZE / sizeof(word32)];
#endif
/* Copy context->state[] to working vars */
@@ -1616,7 +1616,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
#endif
return 0;
}
#else
#else /* SHA256_MANY_REGISTERS */
/* SHA256 version that keeps all data in registers */
#define SCHED1(j) (W[j] = *((word32*)&data[j*sizeof(word32)]))
#define SCHED(j) ( \
@@ -1644,7 +1644,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
#ifdef USE_SLOW_SHA256
int j;
#endif
word32 W[WC_SHA256_BLOCK_SIZE/sizeof(word32)];
word32 W[WC_SHA256_W_SIZE / sizeof(word32)];
/* Copy digest to working vars */
S[0] = sha256->digest[0];
@@ -1693,7 +1693,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
return 0;
}
#endif /* SHA256_MANY_REGISTERS */
#endif
#endif /* NEED_SOFT_SHA256 */
/* End wc_ software implementation */
#ifdef XTRANSFORM
@@ -2484,7 +2484,7 @@ static WC_INLINE int Transform_Sha256_Len(wc_Sha256* sha256, const byte* data,
#ifdef WOLFSSL_SMALL_STACK_CACHE
if (sha224->W == NULL) {
sha224->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
sha224->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
sha224->heap, DYNAMIC_TYPE_DIGEST);
if (sha224->W == NULL)
return MEMORY_E;
@@ -3054,7 +3054,7 @@ int wc_Sha224_Grow(wc_Sha224* sha224, const byte* in, int inSz)
XMEMCPY(dst, src, sizeof(wc_Sha224));
#ifdef WOLFSSL_SMALL_STACK_CACHE
dst->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
dst->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
dst->heap, DYNAMIC_TYPE_DIGEST);
if (dst->W == NULL) {
XMEMSET(dst, 0, sizeof(wc_Sha224));
@@ -3208,7 +3208,7 @@ int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst)
#ifdef WOLFSSL_SMALL_STACK_CACHE
dst->W = (word32*)XMALLOC(sizeof(word32) * WC_SHA256_BLOCK_SIZE,
dst->W = (word32*)XMALLOC(WC_SHA256_W_SIZE,
dst->heap, DYNAMIC_TYPE_DIGEST);
if (dst->W == NULL) {
XMEMSET(dst, 0, sizeof(wc_Sha256));
+6 -6
View File
@@ -1714,7 +1714,7 @@ static int InitSha512_Family(wc_Sha512* sha512, void* heap, int devId,
* _Transform_Sha512() with additional buffer space used by
* wc_Sha512Transform().
*/
sha512->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE,
sha512->W = (word64 *)XMALLOC(WC_SHA512_W_SIZE,
sha512->heap, DYNAMIC_TYPE_DIGEST);
if (sha512->W == NULL)
return MEMORY_E;
@@ -1890,11 +1890,11 @@ static int _Transform_Sha512(wc_Sha512* sha512)
return BAD_FUNC_ARG;
#elif defined(WOLFSSL_SMALL_STACK)
word64* W;
W = (word64*) XMALLOC(sizeof(word64) * 16, sha512->heap, DYNAMIC_TYPE_TMP_BUFFER);
W = (word64*)XMALLOC(WC_SHA512_W_SIZE, sha512->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (W == NULL)
return MEMORY_E;
#else
word64 W[16];
word64 W[WC_SHA512_W_SIZE / sizeof(word64)];
#endif
/* Copy digest to working vars */
@@ -2759,7 +2759,7 @@ static int InitSha384(wc_Sha384* sha384)
* _Transform_Sha512() with additional buffer space used by
* wc_Sha512Transform().
*/
sha384->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE,
sha384->W = (word64 *)XMALLOC(WC_SHA512_W_SIZE,
sha384->heap, DYNAMIC_TYPE_DIGEST);
if (sha384->W == NULL)
return MEMORY_E;
@@ -3117,7 +3117,7 @@ int wc_Sha512Copy(wc_Sha512* src, wc_Sha512* dst)
* _Transform_Sha512() with additional buffer space used by
* wc_Sha512Transform().
*/
dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE,
dst->W = (word64 *)XMALLOC(WC_SHA512_W_SIZE,
dst->heap, DYNAMIC_TYPE_DIGEST);
if (dst->W == NULL) {
XMEMSET(dst, 0, sizeof(wc_Sha512));
@@ -3559,7 +3559,7 @@ int wc_Sha384Copy(wc_Sha384* src, wc_Sha384* dst)
* _Transform_Sha512() with additional buffer space used by
* wc_Sha512Transform().
*/
dst->W = (word64 *)XMALLOC((sizeof(word64) * 16) + WC_SHA384_BLOCK_SIZE,
dst->W = (word64 *)XMALLOC(WC_SHA512_W_SIZE,
dst->heap, DYNAMIC_TYPE_DIGEST);
if (dst->W == NULL) {
XMEMSET(dst, 0, sizeof(wc_Sha384));
+7 -2
View File
@@ -199,7 +199,7 @@ struct wc_Sha256 {
int sha_method;
#endif
#endif
#endif /* !FREESCALE_LTC_SHA etc. */
void* heap;
#ifdef WOLFSSL_PIC32MZ_HASH
hashUpdCache cache; /* cache for updates */
@@ -207,9 +207,14 @@ struct wc_Sha256 {
#ifdef WOLFSSL_ASYNC_CRYPT
WC_ASYNC_DEV asyncDev;
#endif /* WOLFSSL_ASYNC_CRYPT */
#ifdef SHA256_MANY_REGISTERS
#define WC_SHA256_W_SIZE WC_SHA256_BLOCK_SIZE
#else /* !SHA256_MANY_REGISTERS */
#define WC_SHA256_W_SIZE (sizeof(word32) * WC_SHA256_BLOCK_SIZE)
#endif /* !SHA256_MANY_REGISTERS */
#ifdef WOLFSSL_SMALL_STACK_CACHE
word32* W;
#endif /* !FREESCALE_LTC_SHA && !STM32_HASH_SHA2 */
#endif /* WOLFSSL_SMALL_STACK_CACHE */
#ifdef WOLFSSL_DEVCRYPTO_HASH
WC_CRYPTODEV ctx;
#endif
+4 -2
View File
@@ -166,9 +166,11 @@ struct wc_Sha512 {
WC_ASYNC_DEV asyncDev;
#endif /* WOLFSSL_ASYNC_CRYPT */
#ifdef WOLFSSL_SMALL_STACK_CACHE
#define WC_SHA512_W_SIZE ((sizeof(word64) * 16) + WC_SHA512_BLOCK_SIZE)
word64* W;
#endif
#else /* !WOLFSSL_SMALL_STACK_CACHE */
#define WC_SHA512_W_SIZE (sizeof(word64) * 16)
#endif /* !WOLFSSL_SMALL_STACK_CACHE */
#if defined(WOLFSSL_ESP32_CRYPT) && \
!defined(NO_WOLFSSL_ESP32_CRYPT_HASH) && \
(!defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512) || \