Thread

Commits

  1. pgcrypto: avoid recursive ResourceOwnerForget().

  1. 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);
    }
    ```
    
    
    
    
    
    
  2. 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