1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

62601 Commits

Author SHA1 Message Date
Tom Lane
724edf9bde Stamp 18.6. REL_18_6 2026-08-11 14:38:31 -04:00
Tom Lane
841d0cb0f9 Release notes for 18.6.
Farewell, 18.5; we hardly knew ye.
2026-08-11 14:37:01 -04:00
Heikki Linnakangas
5f003855e7 Fix pg_strupper/lower/title/fold() functions to work with C locale
Starting with commit 011384ba45, calling to_date() or to_timestamp()
with "TMMonth" or other TM-prefixed format keyword, with the C locale,
would crash.

In REL_19_STABLE and above, pg_strupper(), pg_strlower(),
pg_strtitle(), and pg_strfold() functions have a special case for the
C locale, but that was missing in REL_18_STABLE.  On REL_18_STABLE,
the functions call the libc function even in C locale, even though the
native locale object is NULL.  On Linux, the underlying libc functions
will crash when called with NULL locale.  (On macOS, they reportedly
do not, but even then it's not clear if they will do what you'd
expect.)

This went unnoticed because until commit 011384ba45, we never called
these functions in C locale, all the callers had a special codepath
for C locale.  We could add a special path in the new callers too, but
it's an accident waiting to happen, so let's backport the C
locale-specific handling from REL_19_STABLE to REL_18_STABLE.  Older
versions did not have these functions at all, hence no problem.

This applies to REL_18_STABLE only.

Reported-by: Masashi Kamura <kamura.masashi@fujitsu.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://www.postgresql.org/message-id/OS9PR01MB1317436E07D06281AD1A0452F94DD2%40OS9PR01MB13174.jpnprd01.prod.outlook.com
2026-08-11 21:24:28 +03:00
Tom Lane
17fae4fbdd Stamp 18.5. 2026-08-10 16:52:29 -04:00
Tom Lane
e35db2cd88 Update .abi-compliance-history for security fixes.
Security: CVE-2026-6470, CVE-2026-6471, CVE-2026-6469
2026-08-10 12:35:48 -04:00
Tom Lane
cf6c2adec8 Last-minute updates for release notes.
Security: CVE-2026-6464, CVE-2026-6469, CVE-2026-6470, CVE-2026-6471, CVE-2026-14662, CVE-2026-14663, CVE-2026-14664, CVE-2026-14666, CVE-2026-14668, CVE-2026-14669, CVE-2026-14670, CVE-2026-14671, CVE-2026-14672, CVE-2026-14673, CVE-2026-14676, CVE-2026-14677, CVE-2026-14678, CVE-2026-14679, CVE-2026-14680, CVE-2026-14681, CVE-2026-15741, CVE-2026-15742, CVE-2026-16238, CVE-2026-16239, CVE-2026-16241, CVE-2026-18024, CVE-2026-18408, CVE-2026-19385
2026-08-10 12:15:10 -04:00
Nathan Bossart
71ca694c73 psql: Don't do backquote expansion in \unrestrict.
This oversight in commit 71ea0d6795 allows a malicious server to
inject shell commands into plain-text dump output that are run at
restore time on the machine running psql.  To fix, interpret all
text after \unrestrict until the end of the line as its argument.

Reported-by: Lucas Velgus <velgusgus599@gmail.com>
Reported-by: Filip Janus <fjanus@redhat.com>
Reported-by: Daniel Bakker <daniel@jackds.nl>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Security: CVE-2026-18408
Backpatch-through: 14
2026-08-10 06:38:13 -07:00
Jacob Champion
4c5128ca0b pgcrypto: Add option to revert to prior decryption behavior
The previous commit raises an ERROR during PGP operations if OpenSSL
does not support the cipher in use. However, any existing messages
created with faulty encryption will no longer be accessible via
pgp_[sym|pub]_decrypt().

To help users out of this situation, add a new ignore-cipher-failure
option which reverts to the broken behavior during decryption only. A
faulty encryption wrapper, created by an OpenSSL configuration that does
not support the cipher, can then be stripped back off by that same
OpenSSL in order to safely reencrypt it. (Note that when OpenSSL does
support the cipher, corrupted messages will not be decrypted regardless
of the ignore-cipher-failure setting; this is unchanged.)

The new tests add a corrupted Blowfish message for both public- and
symmetric-key decryption, resulting in the following test matrix:

- Blowfish supported, default behavior:      fails to decrypt
- Blowfish supported, ignore-cipher-failure: fails to decrypt
- Blowfish unsupported, default behavior:    fails to load cipher
- Blowfish unsupported, ignore-cipher-failure: strips faulty encryption

The previous commit's change to the pubkey tests is expanded similarly:
correctly encrypted messages cannot be decrypted by an OpenSSL that does
not support the cipher, regardless of the option's setting, though the
failure mode will change.

Suggested-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Noah Misch <noah@leadboat.com>
Security: CVE-2026-14663
Backpatch-through: 14
2026-08-10 06:38:13 -07:00
Daniel Gustafsson
fe32b10fca Fix errorhandling for PGP encryption
PGP encryption was using px_cipher_encrypt without checking if any
error was returned.  When OpenSSL is running in FIPS mode, or when
the legacy provider hasn't been loaded, not all ciphers which are
supported by the PGP code are available and fail the init step in
px_cipher_encrypt.  Since the PGP encryption failed to notice this
it XORed the non-encrypted block with the plaintext, effectively
disabling the encryption.

This was found due to a report of PGP encryption not respecting
the pgcrypto.builtin_crypto_enabled flag and allowing Blowfish
and DES.  This however turned out to be a false positive, since
the PGP code only use ciphers from OpenSSL and not the built in
ciphers.

Bug: #19457
Reported-by: Shishir Sharma <ansh01072001@gmail.com>
Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com>
Discussion: https://postgr.es/m/19457-4bab15c17aea36c7@postgresql.org
Security: CVE-2026-14663
Backpatch-through: 14
2026-08-10 06:38:13 -07:00
Michael Paquier
08e812c02a Fix out-of-bound reads with ascii() for invalid multibyte characters
This commit addresses two defects in this SQL function, the code
assuming that:
- The user-supplied string was long enough to contain a character of the
length implied by the first byte.  It is possible to provide in input
data that was able to disclose a few bytes of server memory, allowing
out-of-bound reads.
- Specific bytes had values within the expected range, using a set of
assertions to validate them.  The assertions could be triggered on
invalid input.  These are replaced by tests and error reports.

Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Backpatch-through: 14
Security: CVE-2026-18024
2026-08-10 06:38:13 -07:00
Tom Lane
29921259e8 Teach psql to skip in-line COPY ... FROM STDIN data after a failure.
If the COPY command fails before sending PGRES_COPY_IN, psql did
not realize that it ought to consume any in-line data following
the command.  Failing to do so leads to trying to execute that
data as SQL commands, which in the best case is wrong and in the
worst case is a SQL-injection hazard.

To fix:

1. Extend psqlscan.l to recognize COPY ... FROM STDIN.  This can
be done with a pretty simple extension to the logic that already
recognizes nested BEGIN blocks within CREATE FUNCTION et al.
But unlike that case, we need to consider and count multiple COPY
commands within a single query string (separated by "\;").  The
fallout from that is that psql_scan_reset must now always be called
before starting a new query string.  (The comment for it that claimed
we didn't need that because "the scan state must be INITIAL" was
really obsolete already, since it has long reset more state besides
start_state.)

2. Teach handleCopyIn() to read and discard data when passed
NULL for "conn".

3. Add logic to SendQuery() to call handleCopyIn() that way
if the query string contained COPY ... FROM STDIN command(s)
that remain unaccounted-for at the end.

Now that we have this counting logic, we can also detect
if the backend sends an unexpected PGRES_COPY_IN message.
That should never happen, but perhaps a malicious server
could try to extract data that way.

A side-effect of doing this is that we have to adjust a number of test
scripts that thought they needn't write "\." after a COPY FROM STDIN
that they expect to fail.  On the whole this is an improvement, since
there's now a uniform rule "write \. after COPY FROM STDIN, whether
you expect it to work or not".  But it is an annoying amount of test
churn.

A loose end in this patch is that if it has to skip data, it assumes
that that data is text not binary.  It seems unduly difficult to
detect whether the COPY command requested binary (we could handle the
old-style COPY BINARY ... syntax, but not the new style with format
options).  In practice, copying in-line binary data is unsupported
anyway, because there's no way to write an end marker: the textual
terminator sequence "\n\\.\n" could appear in binary data and there's
no provision for escaping it, so neither psql nor the server look for
it when in binary mode.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6464
2026-08-10 06:38:13 -07:00
Tom Lane
900894d35c Save/restore more lexer state when skipping text due to \if.
When we implemented \if ... \endif in psql, we arranged to
save/restore the lexer's parenthesis depth counter across any chunk
of input that we're ignoring.  At the time, that was sufficient,
because no other part of PsqlScanState could need to be restored to
its prior value.  However, commit e717a9a18 and follow-ons added
more state fields that ought to be restored to their prior values.
A problem would only be observed if someone tries to \if out a
portion of a CREATE FUNCTION/PROCEDURE command that is relevant to
BEGIN/END matching, which seems like a pretty unusual usage, so the
lack of field reports isn't surprising.  Nonetheless it's a bug.

To fix, replace the simple counter field in ConditionalStack
entries with a pointer to a struct defined by psqlscan_int.h.
(In the back branches, keep the old field and associated functions
to minimize the risk of API/ABI breakage, even though it seems
unlikely that any third-party code is using this.  Making the
new struct private to psqlscan-related code should prevent API/ABI
issues for future additions of this type.)

In itself this is only a minor bug fix, but it's prerequisite
infrastructure for the fix for CVE-2026-6464, which will add
another such field.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6464
2026-08-10 06:38:13 -07:00
Nathan Bossart
0b12f56bfa Invalidate plan cache after role changes.
Role membership, role attribute, and database ownership changes may
impact the expected behavior of row-level security policies, but
currently the plan cache doesn't take notice.  To fix, register
syscache callbacks on pg_auth_members, pg_authid, and pg_database
that invalidate the role-dependent plans.  Changes to other
databases' pg_database rows are ignored.

Reported-by: Ilya Staroverov <i.staroverov@ftdata.ru>
Reported-by: Shinya Kato <shinya11.kato@gmail.com>
Author: Ilya Staroverov <i.staroverov@ftdata.ru>
Author: Shinya Kato <shinya11.kato@gmail.com>
Co-authored-by: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Security: CVE-2026-14666
Backpatch-through: 14
2026-08-10 06:38:13 -07:00
Nathan Bossart
57f59ca1d9 Check for USAGE privilege on the composite type in ALTER TABLE OF.
This omission allowed roles without USAGE on a type to create
tables that depend on it, which could prevent the owner from
changing the type later.

Reported-by: Nathan Bossart <nathandbossart@gmail.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14
2026-08-10 06:38:12 -07:00
Nathan Bossart
2780538433 Check for USAGE privilege on types used by stored expressions.
This omission allowed roles without USAGE on a type to create
stored expressions that depend on it, which could prevent the owner
from changing the type later.

The checks deliberately live in the command paths rather than the
dependency-recording routines.  Those routines also run whenever
the server re-derives an existing expression, and re-checking there
would break routine maintenance for an owner who has since lost
USAGE on a type its objects already reference.  (Checking in the
dependency-recording routines would also require additional
CommandCounterIncrement() calls to avoid spurious errors.)

The addition of a parameter to AlterDomainAddConstraint() breaks
ABI compatibility, but we are unaware of any impacted third-party
code.

Reported-by: Noah Misch <noah@leadboat.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14
2026-08-10 06:38:12 -07:00
Nathan Bossart
2e91f8548d Check for USAGE privilege on the subtype in CREATE TYPE AS RANGE.
This omission allowed roles without USAGE on a type to create range
types that depend on it, which could prevent the owner from
changing the type later.

Reported-by: Jingzhou Fu <fuboat@outlook.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Security: CVE-2026-6470
Backpatch-through: 14
2026-08-10 06:38:12 -07:00
Nathan Bossart
e88eb4e766 Avoid overflow in Levenshtein distance calculations.
levenshtein() and levenshtein_less_equal() let the caller specify
the insertion, deletion, and substitution costs, and
fuzzystrmatch's corresponding SQL functions accept any 32-bit
integer for each.  Since the distances are calculated with 32-bit
arithmetic, large costs can cause overflows, thereby producing
nonsensical results.  Certain inputs to levenshtein_less_equal()
can even cause out-of-bounds writes.  To fix, use 64-bit arithmetic
instead, and error whenever the final result won't fit in the
returned 32-bit integer.

We may want to teach these functions to reject negative costs, too,
but that didn't seem appropriate for a security fix, and therefore
it is left as a future exercise.

Reported-by: Ben Morris in collaboration with Claude and Anthropic Research
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Security: CVE-2026-15742
Backpatch-through: 14
2026-08-10 06:38:12 -07:00
Robert Haas
37b8f3b0e0 Cross-check the type of a portal running EXECUTE or FETCH.
When an EXECUTE or FETCH statement is executed, there are two portals:
an outer portal that is created for the EXECUTE or FETCH statement itself,
and an inner portal for the statement being executed on its behalf.
Before this commit, nothing checked that these two portals agreed on
the tuple descriptor of the rows being returned. This can be leveraged
to disclose server memory contents and achieve arbitrary code execution.

To prevent that, we can make use of an existing safety mechanism,
added by Tom Lane in commit 2f48ede080,
which allows a tuplestore DestReceiver to be informed of the tupleDesc
required by the caller, and which will cause an ERROR to occur if
that doesn't match the tupleDesc of what emerges from the executor
(modulo dropped columns, which aren't an issue in the case at hand).

Reported-by: Ben Morris in collaboration with Claude and Anthropic Research
Reported-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Security: CVE-2026-16239
2026-08-10 06:38:12 -07:00
Jacob Champion
2a29b607db Add an output_plugin_libraries GUC to bless trusted output plugins
REPLICATION users were not previously subject to restrictions on output
plugin paths, so they were able to bypass LOAD-time protections during
logical decoding. Unfortunately, adding the standard LOAD restrictions
now would retroactively require all third-party output plugins to be
installed under the $libdir/plugins directory. This would prevent the
use of dynamic_library_path, introduce a wire incompatibility for
clients, and require all plugin authors to check that their libraries
are safe for use by any unprivileged user; we want to avoid that.

Instead, introduce an output_plugin_libraries GUC so that DBAs can
specify the output plugins that are trusted for use in logical decoding.
For simplicity, superusers are subject to the restriction as well
(though they're free to modify the GUC at will during a session, so no
power is actually lost).

The default setting is 'pgoutput, test_decoding'. If other third-party
plugins are in use, DBAs will need to modify this parameter after they
update. Some pointers have been added to the documentation to assist
with this.

Author: Jacob Champion <jacob.champion@enterprisedb.com>
Reported-by: Vladimir Tokarev <vladimirelitokarev@gmail.com>
Reported-by: Yu Kunpeng <yu443940816@live.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-6471
2026-08-10 06:38:12 -07:00
Jacob Champion
82fd688012 Move SplitGUCList() to fe_utils
This is needed so that all versions of pg_upgrade that migrate logical
replication slots can parse the new output_plugin_libraries GUC.

Backpatch-through: 17
Security: CVE-2026-6471
2026-08-10 06:38:12 -07:00
Noah Misch
0a61fcde03 Empty search_path in amcheck.
A grantee of amcheck function EXECUTE privilege could execute arbitrary
functions as the owners of expression indexes that depend on the search
path.  An expression like (lower(col)) was not vulnerable, because
lower() is resolved at CREATE INDEX time.  However, an expression
calling an sql-language or plpgsql-language function often was
vulnerable, even if it used search_path only to find objects in
pg_catalog.  The amcheck documentation has been warning about data
disclosure after such a GRANT, not about function execution.

This might cause new amcheck errors when index expressions rely on a
broader search_path.  Such indexes have seen errors during auto-analyze
since CVE-2018-1058 commit 582edc369c, and
v17 amcheck always worked this way.  Hence, the risk is low.

Leave a comment on the one other sandbox entrance that doesn't empty
search_path.  In its case, the choice was valid.

Back-patch to v14 (all supported versions), but v17 was safe already.
Commit 2af07e2f74 (v17) unintentionally
blocked the attack, and commit d70b17636d
(v18) unintentionally removed that protection.  Hence, this adds to v17
just a test and a comment.  While emptying search_path became more
widespread in commit 2af07e2f74 (v17),
none of its other changes blocked an attack available in v16, even when
considering GRANT.  For example, brin_summarize_range() has had an owner
check that GRANT does not override.

Reported-by: 王跃林 <violin0613@tju.edu.cn>
Reported-by: Jacob Brazeal <jacob.brazeal@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14673
2026-08-10 06:38:12 -07:00
Nathan Bossart
822143c4d1 Use value of scram_iterations in mock_scram_secret().
Presently, mock_scram_secret() always uses
SCRAM_SHA_256_DEFAULT_ITERATIONS, which poses an observable
response discrepancy hazard when scram_iterations is set to
something else.  To fix, use the value of the configuration
parameter instead, and document that unauthenticated users can
discover the existence of roles with passwords created with
different iteration counts.

Reported-by: Radim Marek <radim@boringsql.com>
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Jacob Champion <champion.p@gmail.com>
Security: CVE-2026-14672
Backpatch-through: 16
2026-08-10 06:38:12 -07:00
Nathan Bossart
0ddd9098a3 Obstruct EXTRACT() field name deparse injection.
The parser accepts any string as an EXTRACT() field name, but
deparsing does not quote and escape it accordingly.  To fix, quote
and escape the field name during deparsing as needed.  It might be
a good idea to validate the field name during parsing and
deparsing, too, but that is left as a future exercise.

Reported-by: Ben Morris in collaboration with Claude and Anthropic Research
Author: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Security: CVE-2026-15741
Backpatch-through: 14
2026-08-10 06:38:12 -07:00
Michael Paquier
08454e8b2d Fix multirange type handling in pg_restore_attribute_stats()
statatt_get_type() unconditionally converted multirange types to their
underlying range type.  This choice affected all the type information,
like atttypid, atttyptype and operators.

This made the bounds histogram work correctly (range type is required),
but it was wrong for all the other stat kinds.  MCV values for a
multirange column should be parsed as multirange arrays, not range
arrays.  It also made the TYPTYPE_MULTIRANGE check for the range stats
validation as dead code, since atttyptype was always TYPTYPE_RANGE
after the conversion due to the centralized statatt_get_type().

pg_restore_extended_stats() handles the same case correctly: it keeps
the original type and explicitly converts to the range type only at the
point where range_histogram_bounds is built.

The fix of this issue is simple: the multirange-to-range conversion
needs to be moved from the centralized statatt_get_type() up to where
attribute stats build their range_histogram_bounds, matching what is
done for extended statistics restore.

The regression tests for multiranges with attribute stats are extended
to cover this case.

Author: OpenAI Security Research Team
Backpatch-through: 18
Security: CVE-2026-16238
2026-08-10 06:38:12 -07:00
Michael Paquier
8d428c6e67 Add test with multirange type for pg_restore_attribute_stats()
This commit adds a test for pg_restore_attribute_stats() with the
injection of statistics related to a multirange type.  This case is
supported in statatt_get_type() since its introduction in ce207d2a79,
but there was no test in the main regression test suite to check for the
case where attribute stats is restored for a multirange type, as done by
multirange_typanalyze().

Note that this has been originally applied as d4504d6f60 in v19 and
newer branches.  This will be used for the test of a follow-up commit.

Author: Corey Huinker <corey.huinker@gmail.com>
Discussion: https://postgr.es/m/CADkLM=c3JivzHNXLt-X_JicYknRYwLTiOCHOPiKagm2_vdrFUg@mail.gmail.com
Security: CVE-2026-16238
Backpatch-through: 18
2026-08-10 06:38:12 -07:00
Michael Paquier
203a48209a Reject GSSEncRequest after direct SSL connection
When a direct SSL connection was established, ProcessStartupPacket()
still accepted GSSEncRequest messages.  The GSSAPI negotiation would
then use raw writes and reads, bypassing the TLS encryption layer.
After the GSS encryption was established, the connection continued to
use TLS.  This could betray the HBA rules so as the backend does
protocol exchanges inconsistent with the connection policies in place,
with TLS taking priority over GSS in the backend.

The SSL negotiation path already guarded against attempts to request
SSL after a direct SSL request has been processed.  The GSS path is now
guarded the same way when receiving a startup packet.

Reported-by: p4p3r <kbfanta@naver.com>
Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Jacob Champion <champion.p@gmail.com>
Backpatch-through: 17
Security: CVE-2026-14681
2026-08-10 06:38:11 -07:00
Michael Paquier
a14ba29b15 ecpg: Fix out-of-bound writes due to processing of invalid bytea data
ECPG assumes that any bytea data it receives from a backend starts with
'\x' as its first two bytes, but a check was missed to enforce that.  A
rogue server sending some garbage bytea data would be able to crash a
client, resulting in a client-side DoS, in the most common cases.

Reported-by: ylwangtju <ylwangtju@qq.com>
Backpatch-through: 14
Security: CVE-2026-16241
2026-08-10 06:38:11 -07:00
Heikki Linnakangas
028ee716a7 Use palloc_array() in pltcl and plperl to avoid overflow
Some of these could overflow on 32-bit systems with the right input.
Convert all cases where we called palloc() with multiplication to fix
them. Not all of them were bugs, but it's better to be safe than
sorry.

Reported-by: Tulya Project, Team Dhiutsa, Bitecope Technologies Private Ltd
Backpatch-through: 14
Security: CVE-2026-14677
2026-08-10 06:38:11 -07:00
Heikki Linnakangas
849019a50a Fix pg_trgm's picksplit function with all-true datums
The CACHESIGN.sign field is a BITVECP, not a TRGM, so you should not
use GETSIGN() on it. You don't get a compiler warning because the
GETSIGN() macro includes a cast. It resulted in a bogus read beyond
end of buffer, which would cause bad split decisions or a crash if
you're very unlucky.

Reported-by: Mehmet D. INCE <mehmet@mehmetince.net>
Backpatch-through: 14
Security: CVE-2026-14678
2026-08-10 06:38:11 -07:00
Álvaro Herrera
8a31ffc2d4 pg_stat_statements: Fix buffer overflow with query normalization
Since commit 62d712ecfd, pg_stat_statements has been underestimating
the size of the result buffer possible for a normalized query, in cases
where the query includes many squashable lists, causing the normalized
query to write past the allocated area.

The allocated buffer size forgot to account for the comment appended in
a squashable list, "/*, ... */".  Instead of trying to track down
precisely how much space we need, fix by switch to using an expansible
StringInfo.  This not only fixes the bug, but it also makes the code
simpler to follow.

Author: Álvaro Herrera <alvherre@kurilemu.de>
Reported-by: Sajeeb Lohani with TrendAI Zero Day Initiative
Reported-by: Yuelin Wang <3020001251@tju.edu.cn>
Diagnosed-by: Michaël Paquier <michael@paquier.xyz>
Backpatch-through: 18
Security: CVE-2026-14676
Discussion: https://postgr.es/m/19528-7290dd7e6f7dcc22@postgresql.org
2026-08-10 06:38:11 -07:00
Masahiko Sawada
a1fa24127d Preserve the owner of extended statistics rebuilt by ALTER TABLE.
When ALTER TABLE ... ALTER COLUMN TYPE (or any subcommand that rebuilds
them) drops and re-creates the extended statistics objects depending on
the altered column, the re-created objects were owned by the role running
ALTER TABLE rather than by the original owner of the statistics.

Remember each object's owner before dropping it, and restore it on
re-creation.

CreateStatistics()'s signature changes and CreateStatsStmt gains a field,
but no known third-party code calls the former or constructs the latter.

Author: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-6469
2026-08-10 06:38:11 -07:00
Tom Lane
722695db18 Return nulls honestly in aggregate "combine" functions.
numeric_combine() and several other state-combining functions for
aggregates cheated for the case of both inputs being NULL: they
returned a null pointer without bothering to mark it as a SQL NULL.
This was harmless in the expected usage where the result would be
passed to the same combine function or a related aggregate final
function.  But it's bad news from a security standpoint, because
now that value can be passed to an internal-accepting function
even if said function is strict.  While a previous patch prevented
such queries from being issued, it seems like good defense-in-depth
to expend the few additional lines of code needed to do this properly.
Comparable functions such as array_agg_combine() already do so.

Reported-by: Amy Burnett (OpenAI Codex Security)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14680
2026-08-10 06:38:11 -07:00
Tom Lane
54649de65f Reject calls from SQL to functions that take or return type internal.
Allowing that is a security hole, since there are many different
functions with different ideas of what their "internal" argument or
result is.  We already had a defense against the easy case of
"'foo'::internal", but that turns out to be insufficient.  Lock down
both function and operator syntax.  Also disallow attempts to cast to
or from type internal; those would mostly fail anyway, but we have
created some holes with features such as CoerceViaIO.

Reported-by: Amy Burnett (OpenAI Codex Security)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14680
2026-08-10 06:38:11 -07:00
Tom Lane
2a03f21daf Protect some fixed-size arrays that have FUNC_MAX_ARGS elements.
The maximum number of arguments allowed for an aggregate function
is FUNC_MAX_ARGS-1 (since the underlying transfn and/or finalfn
will be called with one more argument).  parse_func.c failed to
enforce this, allowing construction of calls that would try to
pass FUNC_MAX_ARGS+1 to the underlying functions, resulting in
a memory stomp in the executor.  Add correct checking there.

Since it's possible that a bad call has been stored in a view or
SQL function, also add checks in various aggregate-related and
window-function-related code that there are not more than
FUNC_MAX_ARGS arguments.  These will also protect us against the
possibility that we're trying to run a stored view that was made
by a server executable with different FUNC_MAX_ARGS.  (Arguably,
that scenario does not qualify as a security problem.  But let's
just tighten up all of this while we're here, rather than split
hairs over whether an overrun is reachable.)

Likewise check in compute_function_hashkey.  Here the hazard is
directly from a pg_proc row, but the scenario is the same.

PL/Tcl has a similar issue with a fixed-size string buffer.
Let's just replace that buffer with a Tcl_DString, removing the
whole issue and making the code look more like what's around it.

There are a lot of other FUNC_MAX_ARGS-sized arrays, but the rest
have nearby guards already, some with comments explicitly pointing
out the hazard of FUNC_MAX_ARGS changing.

I also used palloc_array() in a few related places in funcapi.c.
Those aren't live hazards AFAICS, but nearby code has been
palloc_array-ified already, so it seemed inconsistent to not use
it here.

Reported-by: Masahiko Sawada <sawada.mshk@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14679
2026-08-10 06:38:11 -07:00
Tom Lane
3392cce5c9 pg_dump: avoid assuming how long pg_proc.protrftypes can be.
The backend doesn't impose any particular limit on the length of this
array, and since there could be entries for both input and output
arguments, it's feasible for the length to exceed FUNC_MAX_ARGS
even without funny business.  This could lead to crashes or worse.

Moreover, pg_dump shouldn't rely on hard-coding FUNC_MAX_ARGS in the
first place: it has no business assuming that the backend it's dumping
from was compiled with the same value of FUNC_MAX_ARGS that it is.
So the stanza in dumpFunc() that allocates exactly FUNC_MAX_ARGS space
for the parsed OID array is fundamentally misguided.  And it's broken
in another way too: if there are exactly FUNC_MAX_ARGS OIDs, then
parseOidArray won't zero-fill any entries, allowing the subsequent
loop to run off the end of the array.  A crash seems unlikely in
this variant, but garbage output is certain.

To fix, redesign parseOidArray's API so that it does the
array-mallocing, which simplifies the callers anyway.  While we're
here, tighten and modernize it a bit; in particular, split it into
separate functions for OIDs and integers, as was foreseen long ago.
This lets us get rid of the confusing type-punning involved in
having IndxInfo.indkeys be declared as "Oid *" when it's really
potentially-signed ints.  Also, most of the callers expect an exact
number of array entries, so make it verify that not just check for
"too many".

I noted while testing that this dumpFunc() stanza isn't even reached
during check-world.  Add a function with transform to the regression
tests to rectify that.

Reported-by: Masahiko Sawada <sawada.mshk@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-19385
2026-08-10 06:38:11 -07:00
Tom Lane
7f0e1aac7a Replace fixed-size, too-short array with a palloc'd one.
MatchNamedCall's arggiven array was declared FUNC_MAX_ARGS long,
but we may actually use up to pronallargs elements, and that can
be more than FUNC_MAX_ARGS if the function has OUT arguments
(cf. ProcedureCreate).  Convert it to a palloc'd array.

Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: ylwangtju <ylwangtju@qq.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14679
2026-08-10 06:38:11 -07:00
Tom Lane
a2cb5a1cfb Be more wary about constant's datatype in scalarineqsel().
The special case here for estimating conditions involving a ctid
column failed to check that the RHS constant is of type tid.
While that'd always be true for the built-in operators that
reference this selectivity estimator, a maliciously constructed
operator could provide a user-controlled Datum value that would
get interpreted as an ItemPointer pointer.  That at least risks
SIGSEGV, and perhaps with a bit of sweat it could be used for
server memory disclosure.

Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Noah Misch <noah@leadboat.com>
Backpatch-through: 14
Security: CVE-2026-14668
2026-08-10 06:38:11 -07:00
Tom Lane
87c4b82197 Harden PL/Perl code against "tied" Perl arrays and hashes.
Tied arrays might report different sizes each time they are inspected.
To avoid generating a corrupt result array, fix plperl_array_to_datum()
to read av_len() of each input array only once.  If the input does
appear to get shorter, we'll fill nulls for the now-missing entries,
which seems fine.  Conversely, if it gets longer, we'll ignore the new
entries.

plperl_to_hstore() assumed that Perl's hv_iterinit() returns the
number of entries in the given Perl hash.  Usually that's true,
but per the Perl docs, "the return value is currently only meaningful
for hashes without tie magic".  That could potentially end in a memory
stomp.  We don't depend on that result value anywhere else, so don't
do so here either.

Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrew Dunstan <andrew@dunslane.net>
Backpatch-through: 14
Security: CVE-2026-14670
2026-08-10 06:38:11 -07:00
Masahiko Sawada
b7e5c3f634 Fix potential buffer overrun in regexp match/split functions.
setup_regexp_matches() sizes the buffer used to convert matched
substrings back from pg_wchar form at the smaller of maxlen*eml and
the original string's byte length, on the assumption that such a
conversion cannot produce more bytes than the string it came
from. That assumption holds only for validly encoded input. But
pg_mb2wchar_with_len() silently accepts bytes that are invalid in the
database encoding, turning each such byte into one pg_wchar, and
converting that back can take more bytes than the input did. A string
made of such bytes therefore overruns the conversion buffer by up to
its own length, corrupting the following memory. regexp_match(),
regexp_matches(), regexp_split_to_table() and regexp_split_to_array()
are all affected.

Fix by dropping the tighter bound and always allocating maxlen*eml + 1
bytes.

Reported-by: Francesco Verardi <frevadiscor89@gmail.com>
Author: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14664
2026-08-10 06:38:10 -07:00
Tom Lane
dddc8a69ff Harden tsquery code against overflows.
The only overflow hazards I could find in tsquery construction
are in QTN2QT(), which builds a flat tsquery datum from the
QTNode tree representation used by tsquery_or, tsquery_rewrite,
and allied functions.  There are two:

1. It seems theoretically possible for the outputs of cntsize() to
overflow an int, so I widened them to size_t.  There's no hazard
certainly in tsquery_or and friends, but tsquery_rewrite could expand
the query tree by large multiples (by replacing many identical
subtrees with a large replacement tree), so in a 64-bit machine
with plenty of available memory it should be possible to build a
QTNode tree large enough to cause that.  If these counters did
overflow then we'd under-allocate the output tsquery and have a heap
overwrite problem.  size_t is sufficient, since it's counting the size
of a subset of an in-memory data structure.  We also have to fix the
TSQUERY_TOO_BIG() macro to not get confused if sumlen exceeds
MaxAllocSize.

2. fillQT() neglects to check that the new "distance" value for a
QI_VAL item fits into the available 20-bit field.  It's quite easy
to reach this, for example by tsquery_or'ing two near-megabyte-sized
tsquerys.  However, the result is only a corrupt tsquery that does
not represent the expected query, so perhaps this doesn't rise to
the level of a security bug.  Nonetheless it should be fixed.

Note: I followed the practice used in other tsquery code of checking
each distance value as it's assigned, which means that the last
operand string could extend past the MAXSTRPOS boundary.  This is a
bit different from the pattern used for tsvectors, which insist that
the total data length not exceed MAXSTRPOS and thereby avoid making
per-item checks.  Perhaps that should be harmonized sometime, but for
now it's okay for the two types to do this differently as long as
each one is self-consistent.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Amit Langote <amitlangote09@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14662
2026-08-10 06:38:10 -07:00
Tom Lane
e251350573 Harden tsvector code against overflows.
The core of this patch is to prevent array_to_tsvector() from
generating invalid tsvectors.  It did not check for overly-long
lexemes (so that WordEntry.len fields could overflow), nor did it
check that the total "datalen" fits within MAXSTRPOS (so that
WordEntry.pos fields could overflow, and the number of entries
in the tsvector could be much more than the normal limit).
While the field overflows couldn't do anything much worse than
produce a corrupted tsvector value, a sufficiently large number
of tsvector entries could cause integer overflows in later
processing, such as tsvectorout.

Another important fix is to prevent tsvectorrecv() from accepting
invalid tsvectors.  The main problem there is that it did not
reject empty-string lexemes.  Hence, even though it did (mostly)
enforce the MAXSTRPOS limit, it could still produce a result
with an unreasonable number of tsvector entries, if they were
primarily empty strings.

Also, fix tsvectorout's calculation of its required output
buffer size: it was multiplying the string lengths by
pg_database_encoding_max_length() for no reason.  That contributed
to the risk of integer overflow there.  With valid tsvector input,
there's no risk, but there's still no reason to make the output
buffer several times bigger than needed.

I also tried to make a couple of related routines more robust,
and spent some effort on improving the comments in ts_type.h.
Also, standardize on a single spelling of the "string is too long
for tsvector" message, using %zu instead of an assortment of formats.
These changes aren't security per se but came out of inspecting the
code for problems.

Reported-by: Yuhang Wu <yuhang@depthfirst.com> and Zhenpeng Lin
Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: Hcamael <baiyjrh@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Amit Langote <amitlangote09@gmail.com>
Backpatch-through: 14
Security: CVE-2026-14662
2026-08-10 06:38:10 -07:00
Tom Lane
4fafe23805 Guard against overlength time zone abbreviations in to_char().
While typical abbreviations are only a few bytes long, a user-supplied
time_zone setting could specify a much longer abbreviation, enough to
overflow to_char's allocation of 12 bytes per format character. If so,
throw an error in the same style as commit 9241c84cb (CVE-2015-0241).

Reported-by: Hcamael <baiyjrh@gmail.com>
Reported-by: Amjad Shahzad <amjadshahzad2000@gmail.com>
Reported-by: Tan Zhen of AntAISecurityLab <TanZhen.AntAI@outlook.com>
Reported-by: Tomer Fichman <tomer@irregular.com>
Reported-by: Zheng Yu <zheng@depthfirst.com>
Reported-by: Amy Burnett (OpenAI Codex Security)
Reported-by: Rick de Jager <rick@v12.sh>
Reported-by: Heewon Song <asteria121@78researchlab.com>
Reported-by: Sylvie Mayer <smayer@cloudflare.com>
Reported-by: Aleksander Alekseev <aleksander@tigerdata.com>
Reported-by: Hillai Ben Sasson <hillai.bensasson@wiz.io>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Backpatch-through: 14
Security: CVE-2026-14669
2026-08-10 06:38:10 -07:00
Peter Eisentraut
3d3462a6d9 Translation updates
Source-Git-URL: https://git.postgresql.org/git/pgtranslation/messages.git
Source-Git-Hash: cebe759464bfe8207fc3d3c2a0c6f79474fb4d1c
2026-08-10 12:14:04 +02:00
Tom Lane
a4c41bbcc7 Release notes for 18.5, 17.11, 16.15, 15.19, 14.24. 2026-08-09 12:52:47 -04:00
Tom Lane
828d602f21 First-draft release notes for 18.5.
As usual, the release notes for other branches will be made by cutting
these down, but put them up for community review first.
2026-08-07 13:11:52 -04:00
Fujii Masao
311e66df9c Fix hot standby accepting connections too early after a crash reset
Commit b53b88109f made the postmaster maintain reachedConsistency in
addition to the startup process.  Since the startup process is forked
from the postmaster, it begins life holding whatever value the
postmaster last set.

On a crash reset the postmaster re-forks the startup process while its
own copy still says true: it clears that copy only on receipt of
PMSIGNAL_RECOVERY_STARTED, which the replacement process cannot send
before it exists.  The replacement therefore starts out believing the
database is already consistent.

CheckRecoveryConsistency() then skips the minRecoveryPoint comparison
altogether, so hot standby is announced at redo start while replay may
be arbitrarily far behind minRecoveryPoint.  Read-only connections are
accepted and answer from heap pages that were flushed ahead of the
replay position, returning wrong results with no error raised.  The
same branch also runs XLogCheckInvalidPages() and
CheckTablespaceDirectory(), which are skipped as well, and
log_invalid_page() treats page references that are normal before
consistency as a PANIC.

Fix by clearing reachedConsistency in InitWalRecovery(), so that a
startup process never depends on the value it inherited.  The
postmaster's own copy is deliberately left alone: forked backends read
it to choose the "not yet accepting connections" errdetail, and it
converges once the new startup process sends PMSIGNAL_RECOVERY_STARTED
and, on reaching minRecoveryPoint, PMSIGNAL_RECOVERY_CONSISTENT.

Successive crash resets alternate.  A startup process that skips the
branch never sends PMSIGNAL_RECOVERY_CONSISTENT, so the postmaster's
copy stays false and the next reset forks a process holding the correct
value; that pass reaches consistency properly, which sets the
postmaster's copy back to true and re-arms the problem for the reset
after it.  Roughly every other crash reset is therefore affected, not
just the first one.  EXEC_BACKEND builds are unaffected, as
reachedConsistency is not carried in BackendParameters.

Backpatch to v18, where commit b53b88109f introduced this issue.

Reported-by: Eric Ridge <eebbrr@planetscale.com>
Author: Nikhil Sontakke <nikhil@planetscale.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CA+UBoq2n2Zg9rKgMfUtUohzGssisF9cDeyjKqPrnRNFprEyX1Q@mail.gmail.com
Backpatch-through: 18
2026-08-08 00:10:06 +09:00
Melanie Plageman
7c25cdb1eb Only clear VACUUM's read stream strategy once in failsafe mode
112c268380 restored failsafe vacuum's abandonment of a buffer
access strategy by clearing the ReadBuffersOperations' strategy
references. But it did so in lazy_scan_heap()'s main loop, meaning it
looped through all the ReadBuffersOperations once per block after
failsafe was engaged. Track it with a local flag and clear the strategy
only once.

Reported-by: Melanie Plageman <melanieplageman@gmail.com>
Discussion: https://postgr.es/m/CAAKRu_Zse14nSNeCgtnE1LUAH8Of7OmYR%2BCc3O_DAzxt3m6T-g%40mail.gmail.com
Backpatch-through: 18
2026-08-07 10:06:41 -04:00
Etsuro Fujita
4ea497a926 Drain pending asynchronous requests during ExecReScanAppend.
The logic for asynchronous Append assumes that pending requests made for
subplans of an Append are drained during ExecReScanAppend.  To ensure
that, commit 9e283fc85 modified postgresReScanForeignScan to drain such
a request if any, but failed to take into account that if such a request
was made for a subplan that is re-scanned with parameter changes or
pruned in the next round by runtime pruning, the postgres_fdw callback
function is called after ExecReScanAppend or never called, respectively.
This would cause such a request to remain even after ExecReScanAppend,
leading to incorrect results, an infinite loop, or an assertion failure.

To fix, modify ExecReScanAppend to, for each of the pending requests,
give the FDW a chance to drain that request using the existing
ForeignAsyncConfigureWait/ForeignAsyncNotify callback functions.  This
makes the change made to postgresReScanForeignScan useless, so remove it
as well.

Back-patch to v14 where asynchronous Append was added.

Reported-by: Alexander Korotkov <aekorotkov@gmail.com>
Co-authored-by: Alexander Korotkov <aekorotkov@gmail.com>
Co-authored-by: Gleb Kashkin <g.kashkin@postgrespro.ru>
Co-authored-by: Etsuro Fujita <etsuro.fujita@gmail.com>
Reviewed-by: Alexander Pyhalov <a.pyhalov@postgrespro.ru>
Reviewed-by: Gleb Kashkin <g.kashkin@postgrespro.ru>
Discussion: https://postgr.es/m/CAPpHfduMOTnV5Zj2KGJ7zanL_10QvccZHtPUaDfJvBhsh9axnQ%40mail.gmail.com
Backpatch-through: 14
2026-08-07 17:30:02 +09:00
Michael Paquier
2fd8d45ecf Fix local pgstat entry leak on OOM during entry creation
When pgstat_init_entry() fails due to an OOM in the DSA allocation,
pgstat_get_entry_ref() cleaned up the shared hashtable but forgot to
remove the local reference that pgstat_get_entry_ref_cached() had
already inserted into pgStatEntryRefHash.

Missing this cleanup would leave a backend with a stale local cache
entry whose entry_ref points to a NULL shared_stats.  If
pgstat_gc_entry_refs() runs with this reference still around, it would
crash due to a pointer dereference.

The local reference is now removed before removing the shared entry,
the order being sensitive to pending interrupts.

Oversight in 8191e0c16a.

Author: Niall Newman <nn@turacolabs.com>
Discussion: https://postgr.es/m/2FDAA194-9CF3-4FD7-A450-F1A4BEB125F6@turacolabs.com
Backpatch-through: 15
2026-08-07 14:23:35 +09:00
Melanie Plageman
585181e077 Restore vacuum failsafe abandonment of buffer access strategy
VACUUM's wraparound failsafe mode exists to reclaim transaction IDs as
quickly as possible. 4830f10243 made the failsafe stop using the
BAS_VACUUM buffer access strategy so that the rest of the vacuum could
make use of all of shared buffers rather than being confined to the
small strategy ring.

However, when 9256822608 made vacuum's first heap pass use the read
stream, this was accidentally disabled. The read stream keeps its own
references to the buffer access strategy, so clearing vacrel->bstrategy
in lazy_check_wraparound_failsafe() no longer had any effect on the
reads issued by the first pass.

Fix this by adding clearing the BufferAccessStrategy reference actually
being used by the ongoing scan -- those in the ReadBuffersOperations
structs themselves.

Two things we accept rather than fix, as neither is worth the added
complexity given how rarely failsafe mode is reached:

- A small amount of read time for IOs that were already in progress when
  the strategy was cleared may be attributed to IOCONTEXT_NORMAL instead
  of IOCONTEXT_VACUUM. WaitReadBuffers() derives the IOContext from the
  (now cleared) strategy, so the wait time of these in-flight IOs is
  misattributed. This is bounded by the stream's look-ahead window and
  happens at most once per vacuum, when the strategy is first cleared.

- The stream's buffer pin limit stays lower than it would have been had
  no strategy been used at all. max_pinned_buffers is capped by the
  strategy's pin limit when the stream is created and is not recomputed
  when the strategy is cleared. Raising it would mean building a new,
  larger ring, which would require first waiting for all in-progress IOs
  to complete. That didn't seem worth it.

Reported-by: Jingtang Zhang <mrdrivingduck@gmail.com>
Discussion: https://postgr.es/m/CAPsk3_APRYVLhAJ5TMwdmpSx8W_%3DPHMm%3DPmKAvnC3gBrfNommQ%40mail.gmail.com
Backpatch-to: 18
2026-08-06 17:31:22 -04:00