[PATCH] Fix use-after-free after failed pg_checksum_init

Started by Grigorev Jurij7 days ago1 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253437
psql -h localhost -U postgres

Built from patchset v1 (message #1), August 23, 2026 at 07:06 AM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t253437_1 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t253437_1 && git checkout t253437_1

Patchset v1 (message #1) is on t253437_1

Jump to latest
#1Grigorev Jurij
ju.grigorev@ftdata.ru

Hi there, hackers!

pg_checksum_init() is documented to return -1 on failure. For the SHA types it first stores the requested type in the checksum context, then calls pg_cryptohash_create() / pg_cryptohash_init(). If create succeeds and init fails, it frees the SHA context but does not clear context->raw_context.c_sha2.

basebackup and pg_verifybackup check that return value. pg_combinebackup does not: write_backup_label(), create_manifest_writer(), reconstruct, and the copy path in pg_combinebackup.c all ignore a failed pg_checksum_init() and later call pg_checksum_update() or pg_checksum_final() with the dangling pointer.

create_manifest_writer() always uses CHECKSUM_TYPE_SHA256 for the manifest itself, so this is not limited to --manifest-checksums=sha256.
The use-after-free is reachable in a frontend OpenSSL build when EVP_DigestInit_ex() fails after a successful create. The in-core cryptohash implementation does not fail after create, so a non-OpenSSL build does not hit this path.

A related issue in pg_checksum_final(): if pg_cryptohash_final() fails, the function returns -1 without freeing the SHA context, and there is no separate cleanup API.

The attached patch is against master. It NULLs the pointer after free on init failure, always frees the SHA context in pg_checksum_final(), and checks pg_checksum_init() / pg_checksum_final() in pg_combinebackup. I also think it should be back-patched to 17, where pg_combinebackup was added.

We found this with Clang Static Analyzer. No new regression test is included, injecting a post-create cryptohash init failure would need a
mock that we do not have today. There is no performance or user-visible behavior change on the success path.

Regards,
Yuriy Grigoryev
Kanatbek Kanybekov

Attachments:

t253437_1
v1-0001-Fix-UAF-after-failed-pg_checksum_init.patchapplication/octet-stream; name=v1-0001-Fix-UAF-after-failed-pg_checksum_init.patchDownload+47-12