From: Remi Tricot-Le Breton Date: Thu, 6 Aug 2026 07:35:00 +0000 (+0200) Subject: BUG/MINOR: ssl: don't pass the address of a size_t as an int* to OpenSSL X-Git-Tag: v3.5-dev7~47 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=3fb37e82618c08e36fb9e40de1d186e7de8b8b6b;p=haproxy.git BUG/MINOR: ssl: don't pass the address of a size_t as an int* to OpenSSL aes_process() passes &out->data, which is a size_t, to the EVP update and final routines through an (int*) cast. OpenSSL writes an int there, so on a 64-bit big-endian platform (s390x, ppc64) the resulting length lands in the high half of the size_t, and the buffer's data count becomes the real length shifted left by 32 bits. The subsequent write at out->area + out->data then targets a wild address. Concretely, on such builds the "aes_gcm_dec" / "aes_cbc_dec" converters and the JWE decryption paths corrupt memory as soon as they process any input, so any client able to submit a token to them can crash the worker. Little-endian builds, which are the vast majority, happen to work by chance since the count starts at zero and only the low half is written. Let's use a proper local int for the OpenSSL output length and assign it back to the buffer's data count. The shared helper comes from commit f0e64de75 ("MINOR: ssl: Factorize AES GCM data processing") in 3.4 but the same cast existed in the AES converters before that. It must be backported to all stable versions. Reported-by: Claude (ANT-2026-74N8W6SJ) --- diff --git a/src/ssl_sample.c b/src/ssl_sample.c index 4f4070b50..2725b67eb 100644 --- a/src/ssl_sample.c +++ b/src/ssl_sample.c @@ -328,6 +328,7 @@ int aes_process(struct buffer *data, struct buffer *nonce, struct buffer *key, i EVP_CIPHER_CTX *ctx = NULL; int size; int ret; + int outlen = 0; size_t blksize; ctx = EVP_CIPHER_CTX_new(); @@ -395,15 +396,16 @@ int aes_process(struct buffer *data, struct buffer *nonce, struct buffer *key, i goto err; if (aad && b_data(aad)) { - if (!sample_conv_aes_update(decrypt, ctx, NULL, (int*)&out->data, + if (!sample_conv_aes_update(decrypt, ctx, NULL, &outlen, (unsigned char*)b_orig(aad), (int)b_data(aad))) goto err; } if (!sample_conv_aes_update(decrypt, ctx, (unsigned char*)b_orig(out), - (int*)&out->data, (unsigned char*)b_orig(data), (int)b_data(data))) + &outlen, (unsigned char*)b_orig(data), (int)b_data(data))) goto err; + out->data = outlen; size = out->data; if (decrypt && gcm) { @@ -418,11 +420,11 @@ int aes_process(struct buffer *data, struct buffer *nonce, struct buffer *key, i } ret = sample_conv_aes_final(decrypt, ctx, (unsigned char*)out->area + out->data, - (int *)&out->data); + &outlen); if (ret <= 0) goto err; - out->data += size; + out->data = (size_t)outlen + size; if (!decrypt && gcm) { if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, b_orig(aead_tag)))