Thread
Commits
-
pgcrypto: avoid recursive ResourceOwnerForget().
- 80bb0ebcc11f 19 (unreleased) landed
- 2aa6be6e6481 17 (unreleased) landed
- 020426268ff6 18 (unreleased) landed
-
BUG #19527: Double-Abort Crash in `ResOwnerReleaseOSSLCipher` via `encrypt_iv` with Oversized Input
The Post Office <noreply@postgresql.org> — 2026-06-18T18:17:12Z
The following bug has been logged on the website: Bug reference: 19527 Logged by: Yuelin Wang Email address: 3020001251@tju.edu.cn PostgreSQL version: 19beta1 Operating system: Linux (Ubuntu 24.04, x86_64) Description: **Component**: `contrib/pgcrypto/openssl.c`, `ResOwnerReleaseOSSLCipher` (line 833), `free_openssl_cipher` (line 291) Any role with `EXECUTE` on `encrypt_iv` (granted by default when pgcrypto is installed) can crash the backend with a single statement: ```sql CREATE EXTENSION IF NOT EXISTS pgcrypto; SELECT encrypt_iv( repeat('A', 1073741308)::bytea, decode('00112233445566778899aabbccddeeff', 'hex'), decode('000102030405060708090a0b0c0d0e0f', 'hex'), 'aes' ); ``` Expected vs actual output: | Step | Expected | Actual | |---|---|---| | `encrypt_iv(...)` | `ERROR: invalid memory alloc request size ...` then clean abort | `WARNING: AbortTransaction while in ABORT state` followed by `ERROR: ResourceOwnerForget called for pgcrypto OpenSSL cipher handle after release started` then backend crash | | Server state after | Normal | `FATAL: the database system is in recovery mode` (postmaster restarted) | `1073741308 + 512 + 4 = 1073741824 = 0x40000000 > MaxAllocSize (0x3FFFFFFF)`, so `palloc` throws `ERROR` and longjmps past `px_combo_free`, leaving the `OSSLCipher` registered with the current `ResourceOwner`. When `AbortTransaction` calls `ResourceOwnerRelease`, `ResOwnerReleaseOSSLCipher` calls `free_openssl_cipher` with `od->owner` still set. `free_openssl_cipher` then calls `ResourceOwnerForgetOSSLCipher`, which checks `owner->releasing == true` and throws `elog(ERROR, ...)`. An ERROR thrown inside `AbortTransaction` re-enters `AbortCurrentTransaction`, calling `ResourceOwnerRelease` a second time on the already-released owner. The second call invokes `EVP_CIPHER_CTX_free` on the already-freed EVP context, producing a null pointer dereference (ASan: `SEGV in EVP_CIPHER_CTX_reset`). Server output: ``` WARNING: AbortTransaction while in ABORT state ERROR: ResourceOwnerForget called for pgcrypto OpenSSL cipher handle after release started server closed the connection unexpectedly ``` ASan confirmation: ``` ==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000659 #0 EVP_CIPHER_CTX_reset (libcrypto.so.3) #1 EVP_CIPHER_CTX_free (libcrypto.so.3) #2 free_openssl_cipher openssl.c:294 #3 ResOwnerReleaseOSSLCipher openssl.c:835 #4 ResourceOwnerReleaseAll resowner.c:395 #5 AbortTransaction xact.c:3016 SUMMARY: AddressSanitizer: SEGV (EVP_CIPHER_CTX_reset) ``` The fix is to clear `od->owner` before calling `free_openssl_cipher` in `ResOwnerReleaseOSSLCipher`: ```c static void ResOwnerReleaseOSSLCipher(Datum res) { OSSLCipher *od = (OSSLCipher *) DatumGetPointer(res); od->owner = NULL; free_openssl_cipher(od); } ``` -
Re: BUG #19527: Double-Abort Crash in `ResOwnerReleaseOSSLCipher` via `encrypt_iv` with Oversized Input
Tom Lane <tgl@sss.pgh.pa.us> — 2026-06-22T16:37:33Z
PG Bug reporting form <noreply@postgresql.org> writes: > Any role with `EXECUTE` on `encrypt_iv` (granted by default when pgcrypto is > installed) can crash the backend with a single statement: > ```sql > CREATE EXTENSION IF NOT EXISTS pgcrypto; > SELECT encrypt_iv( > repeat('A', 1073741308)::bytea, > decode('00112233445566778899aabbccddeeff', 'hex'), > decode('000102030405060708090a0b0c0d0e0f', 'hex'), > 'aes' > ); > ``` > The fix is to clear `od->owner` before calling `free_openssl_cipher` in > `ResOwnerReleaseOSSLCipher`: Good catch, thanks for the report! regards, tom lane