Skip to content

Import CVE-2026-2006 fixes from REL_15_STABLE - #30

Open
abhinab-yb wants to merge 11 commits into
yugabyte:yb-pg15from
abhinab-yb:import-cve-2026-2006
Open

Import CVE-2026-2006 fixes from REL_15_STABLE#30
abhinab-yb wants to merge 11 commits into
yugabyte:yb-pg15from
abhinab-yb:import-cve-2026-2006

Conversation

@abhinab-yb

Copy link
Copy Markdown

Import the upstream REL_15_STABLE fixes for CVE-2026-2006 (missing validation of multibyte character length in text manipulation allows a database user to cause a buffer overrun and execute arbitrary code as the OS user running the database; CVSS 8.8), together with upstream's post-release follow-up fixes.

Imported commits (in branch order):

CVE-tagged fixes (Security: CVE-2026-2006):

  • b2c81ac867 Fix encoding length for EUC_CN.
  • 50863be0b7 Fix mb2wchar functions on short input.
  • fd82ddb679 Replace pg_mblen() with bounds-checked versions. (the main fix)
  • 757bf8145e Code coverage for most pg_mblen* calls.
  • 8f8b1ffac0 Require PGP-decrypted text to pass encoding validation.
  • 6f741bcb6a Fix test "NUL byte in text decrypt" for --without-zlib builds.

Post-release follow-ups (fix regressions introduced by the batch above):

  • 5b305ebcc9 pg_mblen_range, pg_mblen_with_len: Valgrind after encoding ereport.
  • a20eb248c5 Fix SUBSTRING() for toasted multibyte characters. (fixes spurious SUBSTRING() encoding errors introduced by the main fix)
  • ec86152e02 Suppress new "may be used uninitialized" warning.
  • e3bfa4f589 Fix test_valid_server_encoding helper function.
  • 44d29f5c6c EUC_CN, EUC_JP, EUC_KR, EUC_TW: Skip U+00A0 tests instead of failing.

Conflicts resolved:

  • src/test/regress/parallel_schedule (while cherry-picking 757bf81)
    • the parallel test group line test: geometry horology ... database:
      • Upstream appends its two new tests, encoding euc_kr, to the end of this group line.
      • YB f885e22 ([#26335] YSQL: Import SetStats functions from upstream PG) appended stats_import to the end of the same line, so the two single-line edits overlap.
      • Keep both: the line now ends in ... database stats_import encoding euc_kr.
  • src/backend/utils/adt/arrayfuncs.c (while cherry-picking 757bf81)
    • construct_array_builtin():
      • Upstream backpatches construct_array_builtin() to REL_15 for the new test code, with a case list omitting FLOAT8OID and XIDOID.
      • YB f885e22 already imported construct_array_builtin() with FLOAT8OID and XIDOID cases, so git pairs the two function bodies and conflicts on those two extra cases.
      • Keep YB's superset: all upstream cases plus FLOAT8OID and XIDOID.

The other ten cherry-picks applied cleanly; every commit's added/removed lines are byte-identical to upstream.

Test Plan:

Built on Linux (AlmaLinux 8, gcc) with --without-icu --without-readline --without-zlib (pgcrypto rerun with --with-openssl, which PG 15 pgcrypto requires):

  • make check: all 216 tests passed (includes the new encoding and euc_kr tests)
  • make -C contrib/pgcrypto check: all 23 tests passed
  • make -C contrib/pg_trgm check: all 4 tests passed (includes the new pg_utf8_trgm test)
  • make -C contrib/ltree check: 1 test passed
  • make -C contrib/hstore check: 2 tests passed
  • make -C contrib/pageinspect check: 8 tests passed
  • make -C src/test/modules/test_regex check: 2 tests passed

TAP tests were not run (IPC::Run unavailable on the build host); this import does not touch pg_dump or other TAP-only areas.

macdice and others added 11 commits August 27, 2026 12:47
While EUC_CN supports only 1- and 2-byte sequences (CS0, CS1), the
mb<->wchar conversion functions allow 3-byte sequences beginning SS2,
SS3.

Change pg_encoding_max_length() to return 3, not 2, to close a
hypothesized buffer overrun if a corrupted string is converted to wchar
and back again in a newly allocated buffer.  We might reconsider that in
master (ie harmonizing in a different direction), but this change seems
better for the back-branches.

Also change pg_euccn_mblen() to report SS2 and SS3 characters as having
length 3 (following the example of EUC_KR).  Even though such characters
would not pass verification, it's remotely possible that invalid bytes
could be used to compute a buffer size for use in wchar conversion.

Security: CVE-2026-2006
Backpatch-through: 14
Author: Thomas Munro <thomas.munro@gmail.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
(cherry picked from commit b2c81ac)
When converting multibyte to pg_wchar, the UTF-8 implementation would
silently ignore an incomplete final character, while the other
implementations would cast a single byte to pg_wchar, and then repeat
for the remaining byte sequence.  While it didn't overrun the buffer, it
was surely garbage output.

Make all encodings behave like the UTF-8 implementation.  A later change
for master only will convert this to an error, but we choose not to
back-patch that behavior change on the off-chance that someone is
relying on the existing UTF-8 behavior.

Security: CVE-2026-2006
Backpatch-through: 14
Author: Thomas Munro <thomas.munro@gmail.com>
Reported-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
(cherry picked from commit 50863be)
A corrupted string could cause code that iterates with pg_mblen() to
overrun its buffer.  Fix, by converting all callers to one of the
following:

1. Callers with a null-terminated string now use pg_mblen_cstr(), which
raises an "illegal byte sequence" error if it finds a terminator in the
middle of the sequence.

2. Callers with a length or end pointer now use either
pg_mblen_with_len() or pg_mblen_range(), for the same effect, depending
on which of the two seems more convenient at each site.

3. A small number of cases pre-validate a string, and can use
pg_mblen_unbounded().

The traditional pg_mblen() function and COPYCHAR macro still exist for
backward compatibility, but are no longer used by core code and are
hereby deprecated.  The same applies to the t_isXXX() functions.

Security: CVE-2026-2006
Backpatch-through: 14
Co-authored-by: Thomas Munro <thomas.munro@gmail.com>
Co-authored-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reported-by: Paul Gerste (as part of zeroday.cloud)
Reported-by: Moritz Sanft (as part of zeroday.cloud)
(cherry picked from commit fd82ddb)
A security patch changed them today, so close the coverage gap now.
Test that buffer overrun is avoided when pg_mblen*() requires more
than the number of bytes remaining.

This does not cover the calls in dict_thesaurus.c or in dict_synonym.c.
That code is straightforward.  To change that code's input, one must
have access to modify installed OS files, so low-privilege users are not
a threat.  Testing this would likewise require changing installed
share/postgresql/tsearch_data, which was enough of an obstacle to not
bother.

Security: CVE-2026-2006
Backpatch-through: 14
Co-authored-by: Thomas Munro <thomas.munro@gmail.com>
Co-authored-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
(cherry picked from commit 757bf81)

Conflicts resolved:

- src/test/regress/parallel_schedule
  - parallel test group line "test: geometry horology ... database":
    - Upstream appends its two new tests, "encoding euc_kr", to the end
      of this group line.
    - YB f885e22 ([#26335] YSQL: Import SetStats functions from
      upstream PG) appended "stats_import" to the end of the same line,
      so the two single-line edits overlap.
    - Keep both: the line now ends in "... database stats_import
      encoding euc_kr".
- src/backend/utils/adt/arrayfuncs.c
  - construct_array_builtin():
    - Upstream backpatches construct_array_builtin() to REL_15 for the
      new test code, with a case list omitting FLOAT8OID and XIDOID.
    - YB f885e22 already imported construct_array_builtin() with
      FLOAT8OID and XIDOID cases, so git pairs the two function bodies
      and conflicts on those two extra cases.
    - Keep YB's superset: all upstream cases plus FLOAT8OID and XIDOID.
pgp_sym_decrypt() and pgp_pub_decrypt() will raise such errors, while
bytea variants will not.  The existing "dat3" test decrypted to non-UTF8
text, so switch that query to bytea.

The long-term intent is for type "text" to always be valid in the
database encoding.  pgcrypto has long been known as a source of
exceptions to that intent, but a report about exploiting invalid values
of type "text" brought this module to the forefront.  This particular
exception is straightforward to fix, with reasonable effect on user
queries.  Back-patch to v14 (all supported versions).

Reported-by: Paul Gerste (as part of zeroday.cloud)
Reported-by: Moritz Sanft (as part of zeroday.cloud)
Author: shihao zhong <zhong950419@gmail.com>
Reviewed-by: cary huang <hcary328@gmail.com>
Discussion: https://postgr.es/m/CAGRkXqRZyo0gLxPJqUsDqtWYBbgM14betsHiLRPj9mo2=z9VvA@mail.gmail.com
Backpatch-through: 14
Security: CVE-2026-2006
(cherry picked from commit 8f8b1ff)
Backpatch-through: 14
Security: CVE-2026-2006
(cherry picked from commit 6f741bc)
The prior order caused spurious Valgrind errors.  They're spurious
because the ereport(ERROR) non-local exit discards the pointer in
question.  pg_mblen_cstr() ordered the checks correctly, but these other
two did not.  Back-patch to v14, like commit
1e7fe06.

Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Discussion: https://postgr.es/m/20260214053821.fa.noahmisch@microsoft.com
Backpatch-through: 14
(cherry picked from commit 5b305eb)
Commit 1e7fe06 changed
pg_mbstrlen_with_len() to ereport(ERROR) if the input ends in an
incomplete character.  Most callers want that.  text_substring() does
not.  It detoasts the most bytes it could possibly need to get the
requested number of characters.  For example, to extract up to 2 chars
from UTF8, it needs to detoast 8 bytes.  In a string of 3-byte UTF8
chars, 8 bytes spans 2 complete chars and 1 partial char.

Fix this by replacing this pg_mbstrlen_with_len() call with a string
traversal that differs by stopping upon finding as many chars as the
substring could need.  This also makes SUBSTRING() stop raising an
encoding error if the incomplete char is past the end of the substring.
This is consistent with the general philosophy of the above commit,
which was to raise errors on a just-in-time basis.  Before the above
commit, SUBSTRING() never raised an encoding error.

SUBSTRING() has long been detoasting enough for one more char than
needed, because it did not distinguish exclusive and inclusive end
position.  For avoidance of doubt, stop detoasting extra.

Back-patch to v14, like the above commit.  For applications using
SUBSTRING() on non-ASCII column values, consider applying this to your
copy of any of the February 12, 2026 releases.

Reported-by: SATŌ Kentarō <ranvis@gmail.com>
Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Bug: #19406
Discussion: https://postgr.es/m/19406-9867fddddd724fca@postgresql.org
Backpatch-through: 14
(cherry picked from commit a20eb24)
Various buildfarm members, having compilers like gcc 8.5 and 6.3, fail
to deduce that text_substring() variable "E" is initialized if
slice_size!=-1.  This suppression approach quiets gcc 8.5; I did not
reproduce the warning elsewhere.  Back-patch to v14, like commit
9f4fd11.

Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1157953.1771266105@sss.pgh.pa.us
Backpatch-through: 14
(cherry picked from commit ec86152)
Commit c67bef3 introduced this test helper function for use by
src/test/regress/sql/encoding.sql, but its logic was incorrect.  It
confused an encoding ID for a boolean so it gave the wrong results for
some inputs, and also forgot the usual return macro.  The mistake didn't
affect values actually used in the test, so there is no change in
behavior.

Also drop it and another missed function at the end of the test, for
consistency.

Backpatch-through: 14
Author: Zsolt Parragi <zsolt.parragi@percona.com>
(cherry picked from commit e3bfa4f)
Settings that ran the new test euc_kr.sql to completion would fail these
older src/pl tests.  Use alternative expected outputs, for which psql
\gset and \if have reduced the maintenance burden.  This fixes
"LANG=ko_KR.euckr LC_MESSAGES=C make check-world".  (LC_MESSAGES=C fixes
IO::Pty usage in tests 010_tab_completion and 001_password.)  That file
is new in commit c67bef3.  Back-patch
to v14, like that commit.

Discussion: https://postgr.es/m/20260217184758.da.noahmisch@microsoft.com
Backpatch-through: 14
(cherry picked from commit 44d29f5)
@jasonyb

jasonyb commented Aug 28, 2026

Copy link
Copy Markdown

approved, but either this or #28 needs to rebase on top of the other

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants