2026-02-22 Paul Eggert <eggert@cs.ucla.edu>
+ crypto/sha3: Don’t leak if init fails and no free
+ If the init_ctx functions fail, it’s natural for callers to
+ immediately fail too. Change the init_ctx functions to not leak
+ when failing. This doesn’t invalidate any callers that free
+ if the init functions fail, as that free now becomes a no-op.
+ * lib/sha3.c (sha3_##SIZE##_init_ctx): Before failing,
+ free any storage that was allocated before failure was discovered.
+ * tests/test-sha3-224-buffer.c:
+ * tests/test-sha3-256-buffer.c:
+ * tests/test-sha3-384-buffer.c:
+ * tests/test-sha3-512-buffer.c:
+ (check, main): Test more cases of multiple frees.
+ Also, fix a memory leak.
+
crypto/sha3: fix sha3_read_ctx reset bug
* lib/sha3.c (sha3_read_ctx): When using OpenSSL, don’t update the
internal context; we’re supposed to read it, not write it.
bool \
sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \
{ \
- int result; \
- ctx->evp_ctx = EVP_MD_CTX_new (); \
- if (ctx->evp_ctx == NULL) \
+ EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new (); \
+ if (evp_ctx && ! EVP_DigestInit_ex (evp_ctx, EVP_sha3_##SIZE (), NULL)) \
{ \
- errno = ENOMEM; \
- return false; \
+ EVP_MD_CTX_free (evp_ctx); \
+ evp_ctx = NULL; \
} \
- result = EVP_DigestInit_ex (ctx->evp_ctx, EVP_sha3_##SIZE (), \
- NULL); \
- if (result == 0) \
- { \
- errno = ENOMEM; \
- return false; \
- } \
- return true; \
+ ctx->evp_ctx = evp_ctx; \
+ errno = ENOMEM; /* OK to set errno even if successful. */ \
+ return !!evp_ctx; \
}
DEFINE_SHA3_INIT_CTX (224)
sha3_process_bytes (message + part, SHA3_224_BLOCK_SIZE - part, &ctx);
char buf2[SHA3_224_DIGEST_SIZE];
sha3_finish_ctx (&ctx, buf2);
+ sha3_free_ctx (&ctx);
if (mismatch (sha3_224_buffer (message, SHA3_224_BLOCK_SIZE, buf), buf2))
{
failed = 1;
crashing. */
{
struct sha3_ctx ctx;
- if (sha3_224_init_ctx (&ctx))
- {
- sha3_free_ctx (&ctx);
- sha3_free_ctx (&ctx);
- }
+ sha3_224_init_ctx (&ctx);
+ sha3_free_ctx (&ctx);
+ sha3_free_ctx (&ctx);
}
return 0;
sha3_process_bytes (message + part, SHA3_256_BLOCK_SIZE - part, &ctx);
char buf2[SHA3_256_DIGEST_SIZE];
sha3_finish_ctx (&ctx, buf2);
+ sha3_free_ctx (&ctx);
if (mismatch (sha3_256_buffer (message, SHA3_256_BLOCK_SIZE, buf), buf2))
{
failed = 1;
crashing. */
{
struct sha3_ctx ctx;
- if (sha3_256_init_ctx (&ctx))
- {
- sha3_free_ctx (&ctx);
- sha3_free_ctx (&ctx);
- }
+ sha3_224_init_ctx (&ctx);
+ sha3_free_ctx (&ctx);
+ sha3_free_ctx (&ctx);
}
return 0;
sha3_process_bytes (message + part, SHA3_384_BLOCK_SIZE - part, &ctx);
char buf2[SHA3_384_DIGEST_SIZE];
sha3_finish_ctx (&ctx, buf2);
+ sha3_free_ctx (&ctx);
if (mismatch (sha3_384_buffer (message, SHA3_384_BLOCK_SIZE, buf), buf2))
{
failed = 1;
crashing. */
{
struct sha3_ctx ctx;
- if (sha3_384_init_ctx (&ctx))
- {
- sha3_free_ctx (&ctx);
- sha3_free_ctx (&ctx);
- }
+ sha3_224_init_ctx (&ctx);
+ sha3_free_ctx (&ctx);
+ sha3_free_ctx (&ctx);
}
return 0;
sha3_process_bytes (message + part, SHA3_512_BLOCK_SIZE - part, &ctx);
char buf2[SHA3_512_DIGEST_SIZE];
sha3_finish_ctx (&ctx, buf2);
+ sha3_free_ctx (&ctx);
if (mismatch (sha3_512_buffer (message, SHA3_512_BLOCK_SIZE, buf), buf2))
{
failed = 1;
crashing. */
{
struct sha3_ctx ctx;
- if (sha3_512_init_ctx (&ctx))
- {
- sha3_free_ctx (&ctx);
- sha3_free_ctx (&ctx);
- }
+ sha3_224_init_ctx (&ctx);
+ sha3_free_ctx (&ctx);
+ sha3_free_ctx (&ctx);
}
return 0;