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

54129 Commits

Author SHA1 Message Date
Tom Lane
b4c8afdfaf Harden spell.c against out-of-order FLAG lines in Hunspell files.
The compound flags collected from COMPOUNDFLAG and friends are stored in
either the string or the integer member of a union, according to the
flag mode that the affix file's FLAG line declares.  NIImportOOAffixes()
converted each flag as soon as it read it, using the mode in effect at
that point, and recorded that mode in the entry.  Since FLAG may appear
anywhere in the file, including after the compound flags, entries written
before and after it could disagree about which member of the union holds
the flag.

In assert-enabled builds, this would result in an assertion failure.
Otherwise, cmpcmdflag() takes the mode from its first argument and
applies it to both, so it can read an integer as a char pointer and pass
that to strcmp().  Depending on which way the mismatch goes, the result
is a segfault while sorting the array, a segfault in the bsearch() that
later looks flags up (the lookup key is built with the final mode, so
this happens even when the array itself is consistent), or, when both
members happen to be readable, no crash at all and a compound flag that
is never found, which silently disables compound word splitting.  This
isn't a security bug because we consider dictionary files to be trusted
data, but it's still worth fixing.  (In practice, dictionary files
usually put the FLAG line first, which is why this went unreported for
so long.)

Fix by keeping the flags as strings while the file is read and converting
them once it has been read in full, when the mode is final.  This also
makes the position of the FLAG line irrelevant, which is how the flags on
AF, SFX and PFX lines are already treated: those are parsed in a second
pass and so always use the final mode.  That precedent is reason for
behaving this way rather than throwing an error.

The old ispell file format reaches addCompoundAffixFlagValue() too,
from NIImportAffixes(), and returns without entering NIImportOOAffixes(),
so it needs the conversion step as well.

While we're here, also fix some integer width mismatches: store the
result of strtol() into a "long", and cast to int only after we've done
range checks.  Typically a value too wide for int would fail the range
checks anyway, but in some cases it would be silently accepted after
truncation to int.

Author: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAON2xHN3QmsaySM6DGWa1gttcbJoFh0wjAE-_ZpSPo=LKN1hYw@mail.gmail.com
Backpatch-through: 14
2026-08-29 19:56:49 -04:00
David Rowley
978caef193 Fix incorrect multi-column RANGE partition pruning
When performing partition pruning with a RANGE partitioned table where
the pruning quals are only present for a leading prefix of the partition
key, it was possible that partition pruning would accidentally prune away
some partitions which shouldn't be pruned and include some partitions that
were not needed.

This happened due to an incorrectly coded loop bound which was
terminating the loop when the bound reached the first or last element in
the partition bound array.  This resulted in those end elements not being
checked in cases where they should be checked.  It appears that it might
have been coded this way to avoid stepping off the array, but that was
done incorrectly as it failed to take into account the direction of travel
through the array (the loop can go forwards or backwards).  I.e., it's
valid to loop when 'off' is the last element if we're going backwards
through the array, and valid to loop if 'off' is 0 and we're looping
forward through the array, but the code as it was didn't allow that.

Here we fix this by moving the loop condition check to after we've
calculated the array element to process, and break from the loop if that
element is beyond either end of the array.

Example of accidentally pruned partition:

p: partition by range (a, b);
p1: for values from (1, 4) to (1, 7);
p2: for values from (1, 7) to (3, 8);
p3: for values from (4, 8) to (6, 9);
def: default;

select * from p where a <= 1;

Here p2 was pruned by mistake.

Example of accidentally not pruning a partition:

p: partition by range (a, b);
p1: for values from (7, 2) to (7, 7);
def: default;

select * from p where a > 7;

No partitions would be pruned in this case, despite it being impossible
for matching rows to exist in p1.

Author: David Rowley <dgrowleyml@gmail.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Reviewed-by: Tender Wang <tndrwang@gmail.com>
Discussion: https://postgr.es/m/CAApHDvp5ne9AWaH-tG1Lke-USLz3NwWLWTUdP5NT7ypKtcFqcg@mail.gmail.com
Backpatch-through: 14
2026-08-28 13:13:04 +12:00
Fujii Masao
aec25d6107 Fix temporary WAL receiver slot handling on timeline switches
Previously, when wal_receiver_create_temp_slot was enabled, a timeline
switch could cause the walreceiver to try to create the same temporary
replication slot again on the same connection. The slot had already been
created before the first streaming attempt and still existed, so the
second creation attempt failed with a FATAL error such as
"could not create replication slot ...".

The walreceiver would later be restarted and streaming replication could
continue, so this did not permanently break replication. Nevertheless,
the unexpected failure is a bug and should be fixed.

Fix this by tracking whether the temporary replication slot has already
been created for the lifetime of the walreceiver and skipping subsequent
creation attempts. Also copy the retained slot name to shared memory on
each streaming attempt, since RequestXLogStreaming() clears it when
streaming is restarted without a configured primary slot. This also
keeps pg_stat_wal_receiver.slot_name populated after timeline switches.

Backpatch to all supported versions.

Author: ChangAo Chen <cca5507@qq.com>
Reviewed-by: Quan Zongliang <quanzongliang@yeah.net>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/tencent_628FDAF814231923BC8E8357BBBC50F94207@qq.com
Backpatch-through: 14
2026-08-28 01:17:19 +09:00
Fujii Masao
321ec8ee1c Stabilize 019_replslot_limit
The test assumed that advancing WAL would lead to a checkpoint that
invalidates the obsolete replication slot.  If a checkpoint that started
before the WAL switch completes first, the following checkpoint can be
skipped as idle, so the expected walsender termination is not logged.

Force a CHECKPOINT in a background psql session after advancing WAL, so
the slot invalidation is exercised deterministically.

This has been observed on buildfarm members alligator and partridge:
https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=alligator&dt=2024-12-13%2001%3A24%3A58
https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=partridge&dt=2026-08-06%2018%3A00%3A11

Backpatch to all supported versions.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/0b07ead5-a5da-445e-9698-a7d340708bdf@gmail.com
Backpatch-through: 14
2026-08-27 23:57:47 +09:00
Heikki Linnakangas
ba2ea49b3c Don't create a shell type for function returning an array
Refactor the checks in the function to move all the conditions for
when to attempt creating a shell type into one place.  Add a check for
the array syntax.

In addition to rejecting array syntax, another user-visible effect is
that the error message is now different if the type specified a
typmod.  You now get "type does not exist" instead of the more
specific "type modifier cannot be specified for shell type".  That
seems better; the implicit shell type creation exists only for
backwards compatibility, and it never worked with type modifiers, so
if there's a type modifier it's most likely not because the user tried
to create a shell type,

Add test for the array syntax, the type modifier, and some other cases
for which we don't create shell types.

Discussion: https://www.postgresql.org/message-id/de673feb-41b4-4685-b24b-6408b95e58ab@iki.fi
Backpatch-through: 14
2026-08-27 14:35:12 +03:00
Peter Geoghegan
9a1fa1f36e Export subxip[] for snapshots taken during recovery.
A snapshot taken during recovery stores all of its in-progress XIDs in
subxip, every running top-level XID included, leaving xip empty.  Unlike
with other snapshots, its suboverflowed flag does not mean that subxip
is redundant.  We nevertheless treated it that way during snapshot
export, so an importing session could see in-progress transactions as
aborted.  This misbehavior could also lead to hint bits being
incorrectly set on the standby; affected tuples then wrongly appeared
visible or invisible to sessions that never imported the snapshot.

To fix, teach snapshot export to include the subxip[] array regardless
of the overflow flag when the snapshot is taken during recovery.  This
is in line with how CopySnapshot() and SerializeSnapshot() already
handle the same issue.

Claude Code diagnosed this problem.  The committed TAP test is a
simplified version of the one that it wrote to demonstrate this bug.

Oversight in commit 6c2003f8a, which enabled snapshot export and import
during recovery.

Author: Peter Geoghegan <pg@bowt.ie>
Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Bug: #17846
Discussion: https://postgr.es/m/CAH2-WzmHVeYY%3Dpjz9x8DhhxVjXHX0pvoQ-MdiB1Tt6%3Do2GTiKg%40mail.gmail.com
Discussion: https://postgr.es/m/17846-1a0e5ce976f4c01a@postgresql.org
Backpatch-through: 14
2026-08-26 15:38:04 -04:00
Richard Guo
7e29fcd1ae Don't assume DISTINCT ON implies uniqueness when the tlist has SRFs
query_is_distinct_for() treated a subquery's DISTINCT ON clause as
proof that its output is unique over the DISTINCT ON columns, even if
the targetlist contains set-returning functions.  That's not true:
when the query has an ORDER BY, the planner postpones evaluation of
SRFs that are not DISTINCT ON or ORDER BY columns until after the
Unique step, so the subquery can produce duplicates of the DISTINCT ON
columns.  Relying on this bogus uniqueness proof allowed join removal
and unique-inner joins to produce wrong results.

Plain DISTINCT is not affected, since all tlist columns are DISTINCT
columns there, and so any SRFs get expanded before the Unique step.

To fix, make query_supports_distinctness() and query_is_distinct_for()
refuse to prove distinctness via DISTINCT ON if the targetlist
contains any SRFs.  This is more conservative than necessary, since
the SRFs are only postponed when there is an ORDER BY and none of them
appear in a sort/group column, but it doesn't seem worth the trouble
to check that precisely.

Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAMbWs4-hfd1Pyy_zBejsVUSy-3dx16rz2hgUakkKnAg3qg2q=Q@mail.gmail.com
Backpatch-through: 14
2026-08-25 10:23:02 +09:00
Peter Geoghegan
bbe7aca31d Fix GIN posting tree page deletion with incomplete splits.
GIN posting tree page deletion failed to consider whether the target
page's left sibling page, or the deletion target itself, was marked as
incompletely split.  Page deletion finds the target page's left sibling
by walking the parent's downlinks, but an incompletely split page's new
right half is part of the sibling chain despite having no downlink.
Deletion could therefore overwrite the rightlink of the wrong page,
disconnecting the split's still-live right half from the sibling chain.
Scans would then silently miss tuples from that page.

To fix, teach the relevant page deletion path to avoid deleting a
posting tree page whose left sibling is marked incompletely split (and
to avoid doing so when the target page itself is so marked).  This is
essentially the same approach used by nbtree page deletion.

Claude Code found this problem.  The committed test case is a simplified
version of the one that it wrote to demonstrate this bug.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-Wz=sKJcn+OtfVN9rdg+Ps9e4cuQWNP-9t12UE2d8nEG90Q@mail.gmail.com
Backpatch-through: 14
2026-08-22 14:50:28 -04:00
David Rowley
e8c6d114ea Doc: fix typo
Author: Jochen Bandhauer <jb@jbitc.de>
Discussion: https://postgr.es/m/69ecfa04-9177-42fd-8d5d-9f375669fc5b@jbitc.de
Backpatch-through: 14
2026-08-22 12:51:22 +12:00
David Rowley
7f1054b51b Attempt to stabilize plan of self-join test in tidscan.sql
The test that checks the expected plan for this self-join test has been
known to have failed in the past due to badly timed VACUUMs causing
small variations in row estimates on one of the tables, resulting in a
swapped join order.  Currently, failures have only been seen in v14, and
seemingly due to 74388a1ac and 4496020e6 the failures have not been seen
in more recent versions.

Here we shrink down the number of matching rows on one side of the join
to make the alternative join order's costs more expensive relative to
the cheapest join order.  Previously the alternative order had the same
cost.

We do this in all supported versions to reduce the chances of future
changes reintroducing stability issues with these queries.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/f5d1f4c2-6224-4797-be17-c86e77f96c9c@gmail.com
Backpatch-through: 14
2026-08-21 12:28:43 +12:00
Peter Geoghegan
e94ba903bc Fix snapshot import xmin ProcArrayLock bug.
ProcArrayInstallImportedXmin verifies that the source transaction (the
transaction whose snapshot we're importing) is still running, and then
installs the caller's imported xmin.  These steps have to be atomic.
But it was just about possible for VACUUM to fail to observe the
imported xmin in either the source proc or the importing one.  This
could result in VACUUM pruning away deleted tuples that were still
visible to the imported snapshot.

To fix, take ProcArrayLock in exclusive mode while importing an exported
snapshot's xmin within ProcArrayInstallImportedXmin.  That guarantees
that a concurrent VACUUM's OldestXmin cannot advance past the xmin (one
proc or the other always advertises an xmin that holds it back).

Author: Chee Wooson <chee.wooson@gmail.com>
Reviewed-by: Peter Geoghegan <pg@bowt.ie>
Discussion: https://postgr.es/m/20260730042128.714201-1-chee.wooson@gmail.com
Backpatch-through: 14
2026-08-20 19:47:21 -04:00
Michael Paquier
4434340b57 Reject too many arguments in CREATE TRIGGER
The number of trigger arguments is stored as a smallint, but there was
no check that the number of arguments fits with the catalog data type.
This could result in an invalid negative value being stored once one
defined more than INT16_MAX arguments, with an overflowed value stored
in the catalogs.

Looking at other catalogs that store a number of arguments, we have
similar protections already in place (aggregates, functions, etc.).

Reported-by: Xingwang Xiang <v3rdant.xiang@gmail.com>
Author: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://postgr.es/m/19627-5b72a57e332e2b3f@postgresql.org
Backpatch-through: 14
2026-08-20 09:38:36 +09:00
Peter Geoghegan
9628f4de6c GiST: Invalidate killed items consistently.
GiST neglected to invalidate its killedItems[] array on a rescan.  As a
result, it was just about possible for the wrong tuples from the wrong
index page to be LP_DEAD-marked on a rescan.  The scan mistakenly
believed that the previous rescan's killedItems[] were for this rescan's
curBlkno, causing index corruption.

To fix, bring GiST in line with nbtree and hash: call gistkillitems from
both gistrescan and gistendscan (the existing gistgettuple caller still
handles the common case where we need to LP_DEAD-mark before moving on
to the next page).  That way the scan's pending killedItems[] are passed
to gistkillitems while they still describe items from curBlkno.  When
gistkillitems runs, it'll invalidate the array in passing (and won't
needlessly miss out on an opportunity to LP_DEAD-mark eligible index
tuples).  Back branches just get minimal hardening: we invalidate
killedItems[] at the places where the master branch gets new calls to
gistkillitems (and we invalidate curBlkno and curPageLSN on a rescan).

The test that proved corruption on master didn't result in corruption on
any stable branch, though only because, without commit 9c9ddf109, we'd
clobber curPageLSN without also updating curBlkno -- which accidentally
prevented it.  Relying on gistkillitems to not LP_DEAD-mark by passing
it a curBlkno whose curPageLSN was taken from an entirely different page
seems like a very bad idea, which is why this issue is being treated as
a bug affecting all stable branches.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-WzmwEThnQf17Ju+t0N9_KJLsEQSXzYrFnaS2=s4KnGGrqw@mail.gmail.com
Backpatch-through: 14
2026-08-19 15:45:43 -04:00
Peter Geoghegan
0bace7af3d Fix GIN multiple-VACUUM-scans pending list bug.
ginbulkdelete performs pending list cleanup before it searches the entry
tree (and any posting trees) for dead TIDs.  This is necessary to avoid
leaving behind dangling TID references that index vacuuming is required
to remove; nothing prevents recently inserted pending list tuples from
containing TIDs that VACUUM already considers dead.

However, ginbulkdelete neglected to perform pending list cleanup on
VACUUM's second or subsequent call.  It was therefore possible for a
VACUUM that requires multiple rounds of index vacuuming to leave behind
dangling references.

To fix, teach ginbulkdelete to perform pending list cleanup during every
call.  In passing, tweak some related comments in the pending list
cleanup path to make it clear why it's safe for VACUUM to not _fully_
empty an index's pending list.

This was arguably an oversight in commit e2c79e14, which fixed a similar
issue where pending list cleanup by VACUUM could end early, but missed
this closely related problem.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-Wzmsa-RPA2Ko8A5LaGOnmbpimJ--71xkiBqwgjk3Fq8YEg@mail.gmail.com
Backpatch-through: 14
2026-08-19 13:46:34 -04:00
Peter Geoghegan
fbf889de95 Fix GIN VACUUM posting tree root split bug.
ginVacuumPostingTreeLeaves swaps a shared buffer lock for an exclusive
one when it encounters a leaf page.  It neglected to re-verify whether a
page that was initially a leaf root page became an internal page due to
a concurrent root page split (during the window when no lock was held).
It was therefore possible for GIN VACUUM to spuriously treat an internal
page as a leaf page, leading to data corruption.  VACUUM could miss dead
TIDs that it was required to remove, leaving behind dangling references
in the index.

To fix, re-verify that a leaf page is still a leaf page after an
exclusive lock is acquired.  If it isn't, drop our exclusive lock and
acquire a shared lock so that the non-leaf root page gets processed in
the usual way.

Oversight in commit fd83c83d, which fixed a deadlock bug in GIN posting
tree vacuuming.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Discussion: https://postgr.es/m/CAH2-Wz=RBpJTQgvOxr6C=J04dExmFSt1E3F-r+cRTQ56hEotkg@mail.gmail.com
Backpatch-through: 14
2026-08-19 12:30:56 -04:00
Fujii Masao
e8bc40d290 psql: Fix psql slash option leaks
psql_scan_slash_option() returns a malloc'd string, but \getresults,
\gset in pipeline mode, \restrict, and \unrestrict did not free it
after consuming or copying the value.

Free these option strings after use.

Backpatch to all supported versions. In v17 and older, only \restrict
and \unrestrict are affected, so those branches need only that part of
the fix.

Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14
2026-08-19 12:39:30 +09:00
Fujii Masao
de38e72a19 psql: Avoid returning oom_buffer from psql slash option scanner
psql_scan_slash_option() builds option text in a local PQExpBufferData
and returns the buffer's data pointer to its caller. If either the initial
allocation or a later enlargement failed, that data pointer could be
the static PQExpBuffer OOM buffer rather than malloc-owned storage.
The callers could then eventually pass it to free(), causing undefined
behavior.

Detect a broken option buffer before returning it, report OOM, and return
NULL instead. Also avoid evaluating a backtick substitution when the option
buffer is already broken, since doing so could otherwise touch the static
OOM buffer.

This keeps the existing NULL-return convention for slash options. Callers
are not generally changed to distinguish OOM from no option.

Backpatch to all supported versions.

Reported-by: Junwang Zhao <zhjwpku@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14
2026-08-19 12:36:31 +09:00
Fujii Masao
e6c200f9a3 psql: Avoid returning oom_buffer from psql slash command scanner
psql_scan_slash_command() builds the command name in a local
PQExpBufferData and returns the buffer's data pointer to its caller. If
either the initial allocation or a later enlargement failed, that data
pointer could be the static PQExpBuffer OOM buffer rather than malloc-owned
storage. HandleSlashCmds() could then eventually pass it to free(), causing
undefined behavior.

Detect a broken command-name buffer before returning it, report OOM, and
return NULL instead. Teach HandleSlashCmds() to treat a NULL command name
as a command error before trying to compare or dispatch it.

Backpatch to all supported versions.

Reported-by: Junwang Zhao <zhjwpku@gmail.com>
Author: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Junwang Zhao <zhjwpku@gmail.com>
Discussion: https://postgr.es/m/CAHGQGwEh3R3=1tx_a5=fTDJ+ycuwxWMEn6bG_Yt4B5P+hE7AVw@mail.gmail.com
Backpatch-through: 14
2026-08-19 12:34:04 +09:00
Michael Paquier
29b52d2b47 Fix relcache reference leak when decoding TRUNCATE
ReorderBufferProcessTXN() opens every relation referenced by a
TRUNCATE change.  When RelationIsLogicallyLogged() returns false,
it skips the relation without releasing the reference acquired
by RelationIdGetRelation().

Looking at the in-core code paths building XLOG_HEAP_TRUNCATE records,
no relation OIDs would be included if they do not satisfy
RelationIsLogicallyLogged().  One pattern that could go through is if a
table is switched to SET UNLOGGED, but that would not be reachable in
practice as the decoding happens after a historical snapshot is taken,
so the relation should still be valid.

This is a defense-in-depth measure in practice, and we tend to be
careful about how Relations are handled when sending changes to output
plugins, so backpatch all the way down.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com>
Discussion: https://postgr.es/m/7DD65D03-3B5A-43B2-99AD-8E6AF5372BAB@gmail.com
Backpatch-through: 14
2026-08-19 11:32:58 +09:00
Michael Paquier
19d900358f Report single-page checksum failures in pg_stat_database
Base backups reported checksum failures to pg_stat_database only for
files with more than one failing page.  Commit 6b9e875f72 placed the
report inside the block emitting the per-file summary WARNING, which
was skipped for a single failure.  As a result, a backup failing on
files with one corrupted page each left checksum_failures untouched.

To fix, emit the per-file summary and the pgstat report for any
non-zero failure count.  The end-of-backup total WARNING had the same
off-by-one and is now also emitted for a single failure.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/CAN4CZFN+Bi6XmaH8zOdMWjoycYFx9nKtOr+dzQf0o-UQ+Rdqmw@mail.gmail.com
Backpatch-through: 14
2026-08-19 09:52:01 +09:00
Tom Lane
ec24237a40 Defend against null "SV *" pointers in plperl modules.
Tied hashes, and probably tied arrays, are capable of returning Perl
value pointers that are actually NULL, not the usual pointer to an
undef SV.  We were not defending against that everywhere, leading
to possible SIGSEGV.  Fix the code to consistently treat a null
pointer returned from hv_iternext or av_fetch like a !SvOK one.
(Note that the large diff in SV_to_JsonbValue is actually quite
trivial, but it required reindenting a chunk of existing code.)

Claude Code found the instance in hstore_plperl, and I found the
others by code auditing.  Perhaps the other instances aren't
actually reachable, but I see little reason to assume that.

The known test cases for these errors require perl's Tie modules,
which may not be present, so it doesn't seem worth the trouble
to create regression test cases that would cover them.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us
Backpatch-through: 14
2026-08-18 17:33:44 -04:00
Tom Lane
cce1fa9dbc Doc: clean up documentation about text search datatype limits.
textsearch.sgml neglected to mention that the MAXSTRPOS total-length
limit applies to tsquery as well as tsvector.  It also claims that
there is a 32K limit on the total number of nodes in a tsquery, which
is wrong.  (I suspect that QueryOperator.left may once have been
int16, which would give rise to such a limit.  But it's uint32 now,
so you'd hit the 1GB varlena limit well before overflowing that.)

While at it, re-order the bullet points into an order that makes
more sense, to me anyway.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/455079.1786897319@sss.pgh.pa.us
Backpatch-through: 14
2026-08-17 18:17:51 -04:00
Tom Lane
05556bdf93 Tighten up tsqueryrecv().
tsqueryrecv() accepted zero-length lexemes, which tsqueryin() doesn't.
It also accepted phrase distance values larger than MAXENTRYPOS,
which tsqueryin() doesn't.  While neither of these omissions are
very harmful in themselves, they do allow accepting tsquery values
that will fail in a subsequent textual dump/reload.

Commit 23d9ad771 performed similar tightening of tsvectorrecv(),
but I left off these changes at the time because they didn't seem
to have security implications.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/455079.1786897319@sss.pgh.pa.us
Backpatch-through: 14
2026-08-17 18:09:07 -04:00
Peter Geoghegan
9d2d3bd079 GiST: Deprecate F_TUPLES_DELETED opaque area flag.
This flag hasn't been useful since the removal of old-style VACUUM FULL,
so remove it now (this includes removing vestigial code that
unnecessarily set the flag).

Also add test coverage of gistprunepage().  Had that test case been
available before now, the issue fixed by this commit would have been
detected by wal_consistency_checking buildfarm animals.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Michael Paquiër <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAH2-WznbTsQCrjmd=eSawfPqcxCjSFUkk6Qzd3z+gpNte5i03Q@mail.gmail.com
Backpatch-through: 14
2026-08-17 17:31:01 -04:00
Tom Lane
ede3188e11 Make plperl's handling of Perl arrays safer and more consistent.
plperl_func_handler()'s stanza for handling an arrayref result in
a SETOF function could loop forever (or at least till OOM) when
given a tied array, since av_fetch won't necessarily ever return
a null pointer in that case.  Be consistent with the other places
where we traverse a perl array: call av_len() once and use len+1
as the loop limit, silently ignoring any null pointers we get back
from that range of subscripts.

But actually, Perl's preferred locution for this seems to be to
use av_count() not av_len()+1.  av_count() seems better since
there's less risk of forgetting to add 1.  Also, both of those
functions return Size_t (or SSize_t) not int, creating at least
a theoretical overflow hazard.  While we're modernizing this,
let's use the correct variable type where we can, and include an
overflow check where we can't.

Reported-by: Claude Code (via Noah Misch)
Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Discussion: https://postgr.es/m/569769.1786901901@sss.pgh.pa.us
Backpatch-through: 14
2026-08-17 15:06:02 -04:00
Nathan Bossart
a92fbdfb83 doc: Clarify the logging collector's guarantees.
Presently, the documentation for logging_collector says that the
collector "is designed to never lose messages," which reads as a
stronger promise than we actually make.  The collector does not
fsync the log file or retry failed writes, so log messages can go
missing after an operating system crash, power loss, or a write
error.  Reword that sentence and add a note about what is not
guaranteed.

Author: Daniel Bauman <danielbaniel@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Zhenwei Shang <a934172442@gmail.com>
Reviewed-by: Robert Treat <rob@xzilla.net>
Discussion: https://postgr.es/m/CAMtj0_a86DdDKkW-ReVpQpqjndVS6GMrwXVpQY4G3-SGY7saMQ%40mail.gmail.com
Backpatch-through: 14
2026-08-14 15:27:16 -05:00
Nathan Bossart
bcc9d9ffe6 Add missing PGDLLIMPORT marker.
Oversight in commit ffca23839c.

Reported-by: Anton Voloshin <a.voloshin@postgrespro.ru>
Author: Anton Voloshin <a.voloshin@postgrespro.ru>
Backpatch-through: 14
2026-08-14 13:41:32 -05:00
Tom Lane
f1204c1a79 psql: count every COPY FROM STDIN when scanning a query string.
When SendQuery() is not told how many COPY FROM STDIN commands the
query string contains (as for -c, \gexec, and \watch), it scans the
string to count them itself.  But it called psql_scan() only once,
which stops at the first semicolon, so any COPY FROM STDIN past the
first sub-command was not counted, causing failure of cases that used
to work.  Oversight in commit 3045a25ba.

Author: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAN4CZFPqa6c+u4uX5jJ8LANHTQ4dxM3m4_8G9WmX_A4-2wuv2A@mail.gmail.com
Backpatch-through: 14
2026-08-14 12:14:24 -04:00
Tom Lane
39cad0de4a Consistently enforce tsvector/tsquery maximum lengths.
Some places rejected individual tokens longer than MAXSTRLEN, while
others rejected ones longer than MAXSTRLEN-1.  The data structure is
perfectly capable of handling MAXSTRLEN, so there's nothing wrong
with using the looser bound.  Moreover, as things stand there is a
dump/reload hazard: some code paths permit construction of a tsvector
or tsquery that would later be rejected by tsvectorin or tsqueryin.
So standardize on using MAXSTRLEN.

Identical remarks apply to MAXSTRPOS (the total data length),
so fix that too.

Back-patch, in hopes of avoiding cases where a value acceptable to
one supported release is not acceptable to another.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFNYQo4zfbRR435uD0vSfuy5y7dnFOXDfKr9zYoL1JnAxA@mail.gmail.com
Backpatch-through: 14
2026-08-13 11:20:27 -04:00
Michael Paquier
d47336e5f6 Fix poll_query_until() timeout handling with an undefined query in Cluster.pm
On timeout, poll_query_until() would fail to print its report when
"$query" was undefined.  Instead of the expected report, this prevented
the contents of stdout and stderr from being shown.

Note that some of the in-core tests use an undefined query for
connection-only polls.

Author: Bryan Green <dbryan.green@gmail.com>
Reviewed-by: Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>
Discussion: https://postgr.es/m/0f515c6d-6032-4c5f-80ac-5c78faae9522@gmail.com
Backpatch-through: 14
2026-08-12 16:23:21 +09:00
Tom Lane
2e29cb3b81 Tweak allocation rule for tzload()'s "union local_storage" variable.
By default, allocate this via malloc, as we've been doing since commit
62c8421e8.  Commit aeb07c55f adopted upstream tzdb's default of
allocating it on the stack, but that still doesn't seem like a good
idea for the reasons given in 62c8421e8 (and now memorialized in a
comment, in hopes that we don't make the same mistake again).

However, under USE_VALGRIND, put it on the stack as upstream does.
This accidentally prevents a crash when Python 3.14 is used under
Valgrind.  The reasons for that are obscure, and it's most likely
not our bug, and even if we figured it out it'd be nice to have a fix
for buildfarm member skink now rather than after persuading the guilty
party to fix it.

In the normal non-USE_VALGRIND case, this has no effect on the logic
in released branches, and it reverts master to match them.

Reported-by: Alexander Lakhin <exclusion@gmail.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/f071e691-5930-4738-9dbd-43ed2da367fe@gmail.com
Backpatch-through: 14
2026-08-11 18:17:48 -04:00
Tom Lane
6b3806732b Stamp 14.24. REL_14_24 2026-08-10 16:59:18 -04:00
Tom Lane
18ec528b8c Update .abi-compliance-history for security fixes.
Security: CVE-2026-6470, CVE-2026-6471, CVE-2026-6469
2026-08-10 12:35:49 -04:00
Tom Lane
fa01ab7477 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
2006fca401 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:37 -07:00
Jacob Champion
e2c48c81fc 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:37 -07:00
Daniel Gustafsson
7e29eb6f4a 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:37 -07:00
Michael Paquier
42d333a782 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:36 -07:00
Tom Lane
5c51ae4556 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:36 -07:00
Tom Lane
7215c7e964 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:36 -07:00
Nathan Bossart
f4174aa84a 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:36 -07:00
Nathan Bossart
b6e45b4f82 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:36 -07:00
Nathan Bossart
1a358b8f2a 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:36 -07:00
Nathan Bossart
323af0a4ee 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:36 -07:00
Nathan Bossart
9505175f2a 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:36 -07:00
Robert Haas
1f49beef27 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:36 -07:00
Jacob Champion
bf3842a64f 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:36 -07:00
Noah Misch
39d792040c 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:36 -07:00
Nathan Bossart
967acab87f 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:35 -07:00
Michael Paquier
74c59d062a 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:35 -07:00