From: Collin Funk Date: Sat, 6 Sep 2025 17:55:40 +0000 (-0700) Subject: crypto/sha3, crypto/sha3-buffer: Don't leak memory when using OpenSSL. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=745cf7d95dbe64bcea7d4eed9c81369e1898bb70;p=thirdparty%2Fgnulib.git crypto/sha3, crypto/sha3-buffer: Don't leak memory when using OpenSSL. Reported by Pádraig Brady in: . * lib/sha3.c (DEFINE_SHA3_INIT_CTX) [!HAVE_OPENSSL_SHA3]: Always return true. [HAVE_OPENSSL_SHA3]: Call EVP_MD_CTX_create to allocate an EVP_MD_CTX. (DEFINE_SHA3_BUFFER, sha3_process_bytes, sha3_process_block) [!HAVE_OPENSSL_SHA3]: Always return true. [HAVE_OPENSSL_SHA3]: Return NULL if any function calls fail. (sha3_finish_ctx) [HAVE_OPENSSL_SHA3]: Free memory allocated by EV_MD_CTX_create. (sha3_free_ctx): New function. * lib/sha3.h (struct sha3_ctx): Use a heap allocated EVP_MD_CTX. (sha3_224_init_ctx, sha3_256_init_ctx, sha3_384_init_ctx) (sha3_512_init_ctx, sha3_process_block, sha3_process_bytes): Change prototype to return a bool. Mention that they return false if an OpenSSL function fails. (sha3_finish_ctx, sha3_read_ctx, sha3_224_buffer, sha3_256_buffer) (sha3_384_buffer, sha3_512_buffer): Mention that these functions return NULL if an OpenSSL function fails. (sha3_free_ctx): New function. * lib/sha3-stream.c (sha3_xxx_stream): Expect a function parameter that returns bool. Check the return values of the sha3 functions, cleaning up memory on failure. * modules/crypto/sha3-buffer: Add bool. --- diff --git a/ChangeLog b/ChangeLog index 423cdd5be9..b8a4ced928 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2025-09-06 Collin Funk + + crypto/sha3, crypto/sha3-buffer: Don't leak memory when using OpenSSL. + Reported by Pádraig Brady in: + . + * lib/sha3.c (DEFINE_SHA3_INIT_CTX) [!HAVE_OPENSSL_SHA3]: Always return + true. + [HAVE_OPENSSL_SHA3]: Call EVP_MD_CTX_create to allocate an EVP_MD_CTX. + (DEFINE_SHA3_BUFFER, sha3_process_bytes, sha3_process_block) + [!HAVE_OPENSSL_SHA3]: Always return true. + [HAVE_OPENSSL_SHA3]: Return NULL if any function calls fail. + (sha3_finish_ctx) [HAVE_OPENSSL_SHA3]: Free memory allocated by + EV_MD_CTX_create. + (sha3_free_ctx): New function. + * lib/sha3.h (struct sha3_ctx): Use a heap allocated EVP_MD_CTX. + (sha3_224_init_ctx, sha3_256_init_ctx, sha3_384_init_ctx) + (sha3_512_init_ctx, sha3_process_block, sha3_process_bytes): Change + prototype to return a bool. Mention that they return false if an OpenSSL + function fails. + (sha3_finish_ctx, sha3_read_ctx, sha3_224_buffer, sha3_256_buffer) + (sha3_384_buffer, sha3_512_buffer): Mention that these functions return + NULL if an OpenSSL function fails. + (sha3_free_ctx): New function. + * lib/sha3-stream.c (sha3_xxx_stream): Expect a function parameter that + returns bool. Check the return values of the sha3 functions, cleaning up + memory on failure. + * modules/crypto/sha3-buffer: Add bool. + 2025-09-06 Bruno Haible gitsub.sh: Support URL redirections also for subcheckouts. diff --git a/lib/sha3-stream.c b/lib/sha3-stream.c index 708dafa7dc..43c056e22a 100644 --- a/lib/sha3-stream.c +++ b/lib/sha3-stream.c @@ -41,7 +41,7 @@ successful. */ static int sha3_xxx_stream (FILE *stream, char const *alg, void *resblock, - ssize_t hashlen, void (*init_ctx) (struct sha3_ctx *)) + ssize_t hashlen, bool (*init_ctx) (struct sha3_ctx *)) { switch (afalg_stream (stream, alg, resblock, hashlen)) { @@ -54,7 +54,11 @@ sha3_xxx_stream (FILE *stream, char const *alg, void *resblock, return 1; struct sha3_ctx ctx; - init_ctx (&ctx); + if (! init_ctx (&ctx)) + { + free (buffer); + return 1; + } size_t sum; /* Iterate over full file contents. */ @@ -92,6 +96,7 @@ sha3_xxx_stream (FILE *stream, char const *alg, void *resblock, if (ferror (stream)) { free (buffer); + sha3_free_ctx (&ctx); return 1; } goto process_partial_block; @@ -101,18 +106,35 @@ sha3_xxx_stream (FILE *stream, char const *alg, void *resblock, /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % ctx.blocklen == 0 */ - sha3_process_block (buffer, BLOCKSIZE, &ctx); + if (! sha3_process_block (buffer, BLOCKSIZE, &ctx)) + { + free (buffer); + sha3_free_ctx (&ctx); + return 1; + } } process_partial_block:; /* Process any remaining bytes. */ if (sum > 0) - sha3_process_bytes (buffer, sum, &ctx); + { + if (! sha3_process_bytes (buffer, sum, &ctx)) + { + free (buffer); + sha3_free_ctx (&ctx); + return 1; + } + } - /* Construct result in desired memory. */ - sha3_finish_ctx (&ctx, resblock); free (buffer); + + /* Construct result in desired memory. */ + if (sha3_finish_ctx (&ctx, resblock) == NULL) + { + sha3_free_ctx (&ctx); + return 1; + } return 0; } diff --git a/lib/sha3.c b/lib/sha3.c index e30210fb3e..e7b3b9c7c6 100644 --- a/lib/sha3.c +++ b/lib/sha3.c @@ -50,13 +50,14 @@ static const u64 rc[] = { }; #define DEFINE_SHA3_INIT_CTX(SIZE) \ - void \ + bool \ sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \ { \ memset (&ctx->state, '\0', sizeof ctx->state); \ ctx->buflen = 0; \ ctx->digestlen = SHA3_##SIZE##_DIGEST_SIZE; \ ctx->blocklen = SHA3_##SIZE##_BLOCK_SIZE; \ + return true; \ } DEFINE_SHA3_INIT_CTX (224) @@ -64,6 +65,12 @@ DEFINE_SHA3_INIT_CTX (256) DEFINE_SHA3_INIT_CTX (384) DEFINE_SHA3_INIT_CTX (512) +void +sha3_free_ctx (_GL_UNUSED struct sha3_ctx *ctx) +{ + /* Do nothing. */ +} + /* Copy the value from V into the memory location pointed to by *CP, If your architecture allows unaligned access, this is equivalent to * (__typeof__ (v) *) cp = v */ @@ -127,7 +134,7 @@ DEFINE_SHA3_BUFFER (256) DEFINE_SHA3_BUFFER (384) DEFINE_SHA3_BUFFER (512) -void +bool sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx) { if (0 < ctx->buflen) @@ -138,7 +145,7 @@ sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx) /* Not enough to fill a full block. */ memcpy (ctx->buffer + ctx->buflen, buffer, len); ctx->buflen += len; - return; + return true; } /* Process the block that already had bytes buffered. */ memcpy (ctx->buffer + ctx->buflen, buffer, left); @@ -156,9 +163,10 @@ sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx) memcpy (ctx->buffer, buffer, len); ctx->buflen = len; } + return true; } -void +bool sha3_process_block (const void *buffer, size_t len, struct sha3_ctx *ctx) { u64 *a = ctx->state; @@ -315,21 +323,27 @@ sha3_process_block (const void *buffer, size_t len, struct sha3_ctx *ctx) a[0] = u64xor (a[0], rc[i]); } } + return true; } #else /* OpenSSL implementation. */ #define DEFINE_SHA3_INIT_CTX(SIZE) \ - void \ + bool \ sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \ { \ - /* EVP_DigestInit_ex expects all bytes to be zero. */ \ - memset (ctx, 0, sizeof *ctx); \ - EVP_MD_CTX *evp_ctx = (EVP_MD_CTX *) ctx->evp_ctx_buffer; \ - int rc = EVP_DigestInit_ex (evp_ctx, EVP_sha3_##SIZE (), NULL); \ - /* This should never fail. */ \ - if (rc == 0) \ - abort (); \ + int result; \ + ctx->evp_ctx = EVP_MD_CTX_create (); \ + if (ctx->evp_ctx == NULL) \ + return false; \ + result = EVP_DigestInit_ex (ctx->evp_ctx, EVP_sha3_##SIZE (), \ + NULL); \ + if (result == 0) \ + { \ + sha3_free_ctx (ctx); \ + return false; \ + } \ + return true; \ } DEFINE_SHA3_INIT_CTX (224) @@ -337,6 +351,12 @@ DEFINE_SHA3_INIT_CTX (256) DEFINE_SHA3_INIT_CTX (384) DEFINE_SHA3_INIT_CTX (512) +void +sha3_free_ctx (struct sha3_ctx *ctx) +{ + EVP_MD_CTX_free (ctx->evp_ctx); +} + void * sha3_read_ctx (const struct sha3_ctx *ctx, void *resbuf) { @@ -347,11 +367,10 @@ sha3_read_ctx (const struct sha3_ctx *ctx, void *resbuf) void * sha3_finish_ctx (struct sha3_ctx *ctx, void *resbuf) { - EVP_MD_CTX *evp_ctx = (EVP_MD_CTX *) ctx->evp_ctx_buffer; - /* This should never fail. */ - int result = EVP_DigestFinal_ex (evp_ctx, resbuf, NULL); + int result = EVP_DigestFinal_ex (ctx->evp_ctx, resbuf, NULL); + sha3_free_ctx (ctx); if (result == 0) - abort (); + return NULL; return resbuf; } @@ -360,8 +379,10 @@ sha3_finish_ctx (struct sha3_ctx *ctx, void *resbuf) sha3_##SIZE##_buffer (const char *buffer, size_t len, void *resblock) \ { \ struct sha3_ctx ctx; \ - sha3_##SIZE##_init_ctx (&ctx); \ - sha3_process_bytes (buffer, len, &ctx); \ + if (! sha3_##SIZE##_init_ctx (&ctx)) \ + return NULL; \ + if (! sha3_process_bytes (buffer, len, &ctx)) \ + return NULL; \ return sha3_finish_ctx (&ctx, resblock); \ } @@ -370,19 +391,22 @@ DEFINE_SHA3_BUFFER (256) DEFINE_SHA3_BUFFER (384) DEFINE_SHA3_BUFFER (512) -void +bool sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx) { - EVP_MD_CTX *evp_ctx = (EVP_MD_CTX *) ctx->evp_ctx_buffer; - int result = EVP_DigestUpdate (evp_ctx, buffer, len); + int result = EVP_DigestUpdate (ctx->evp_ctx, buffer, len); if (result == 0) - abort (); + { + sha3_free_ctx (ctx); + return false; + } + return true; } -void +bool sha3_process_block (const void *buffer, size_t len, struct sha3_ctx *ctx) { - sha3_process_bytes (buffer, len, ctx); + return sha3_process_bytes (buffer, len, ctx); } #endif diff --git a/lib/sha3.h b/lib/sha3.h index adce43eac7..259f0d1f56 100644 --- a/lib/sha3.h +++ b/lib/sha3.h @@ -51,9 +51,8 @@ enum { SHA3_512_BLOCK_SIZE = 576 / 8 }; struct sha3_ctx { # if HAVE_OPENSSL_SHA3 - /* EVP_MD_CTX is an incomplete type. EVP_MD_CTX_create allocates 72 bytes of - memory as of 2025-09-02. */ - max_align_t evp_ctx_buffer[256 / sizeof (max_align_t)]; + /* EVP_MD_CTX is an incomplete type. It cannot be placed on the stack. */ + EVP_MD_CTX *evp_ctx; # else u64 state[25]; uint8_t buffer[144]; /* Up to BLOCKLEN in use. */ @@ -64,40 +63,49 @@ struct sha3_ctx }; /* Initialize structure containing state of computation. */ -extern void sha3_224_init_ctx (struct sha3_ctx *ctx); -extern void sha3_256_init_ctx (struct sha3_ctx *ctx); -extern void sha3_384_init_ctx (struct sha3_ctx *ctx); -extern void sha3_512_init_ctx (struct sha3_ctx *ctx); +extern bool sha3_224_init_ctx (struct sha3_ctx *ctx); +extern bool sha3_256_init_ctx (struct sha3_ctx *ctx); +extern bool sha3_384_init_ctx (struct sha3_ctx *ctx); +extern bool sha3_512_init_ctx (struct sha3_ctx *ctx); + +/* Free memory allocated by the init_structure. This is only required if + OpenSSL is used. */ +extern void sha3_free_ctx (struct sha3_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. - It is necessary that LEN is a multiple of the BLOCKLEN member of CTX!!! */ -extern void sha3_process_block (const void *buffer, size_t len, + It is necessary that LEN is a multiple of the BLOCKLEN member of CTX!!! + Return false if an OpenSSL function fails. */ +extern bool sha3_process_block (const void *buffer, size_t len, struct sha3_ctx *ctx); /* Starting with the result of former calls of this function (or the initialization function update the context for the next LEN bytes starting at BUFFER. - It is NOT required that LEN is a multiple of the BLOCKLEN member of CTX. */ -extern void sha3_process_bytes (const void *buffer, size_t len, + It is NOT required that LEN is a multiple of the BLOCKLEN member of CTX. + Return false if an OpenSSL function fails. */ +extern bool sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx); /* Process the remaining bytes in the buffer and put result from CTX in RESBUF. The result is always in little endian byte order, so that a byte-wise output - yields to the wanted ASCII representation of the message digest. */ + yields to the wanted ASCII representation of the message digest. + Return NULL if an OpenSSL function fails. */ extern void *sha3_finish_ctx (struct sha3_ctx *ctx, void *restrict resbuf); /* Put result from CTX in RESBUF. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation - of the message digest. */ + of the message digest. + Return NULL if an OpenSSL function fails. */ extern void *sha3_read_ctx (const struct sha3_ctx *ctx, void *restrict resbuf); /* Compute a SHA-3 message digest for LEN bytes beginning at BUFFER. The result is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII representation of the message - digest. */ + digest. + Return NULL if an OpenSSL function fails. */ extern void *sha3_224_buffer (const char *buffer, size_t len, void *restrict resblock); extern void *sha3_256_buffer (const char *buffer, size_t len, diff --git a/modules/crypto/sha3-buffer b/modules/crypto/sha3-buffer index e0e654e563..7ab61dea30 100644 --- a/modules/crypto/sha3-buffer +++ b/modules/crypto/sha3-buffer @@ -8,6 +8,7 @@ m4/gl-openssl.m4 m4/sha3.m4 Depends-on: +bool byteswap c99 stddef-h