February 11, 2021·4 min read·engineeringpostgresqlsecuritypermissions

PostgreSQL 13.2 repairs column permissions and stored view metadata

February's security update fixes two ways to expose protected column values. One fix also requires reparsing existing views where column permissions provide security.

Replacing a database executable cannot repair every security decision already recorded in its catalog. PostgreSQL 13.2 fixes a parser error that omitted columns from the information used to check access permissions. A stored view can retain the incomplete information after the updated server starts. The release therefore includes a repair instruction for existing views, alongside the new binaries.

The February 11 announcement covers PostgreSQL 13.2, 12.6, 11.11, 10.16, 9.6.21 and 9.5.25. It identifies two security vulnerabilities. CVE-2021-20229 affects version 13, while CVE-2021-3393 affects versions 11 through 13. The announcement compares the latter with CVE-2014-8161, an earlier issue with a related information-leak mechanism.

I value PostgreSQL's ability to express access rules inside the database. That makes a column-permission failure particularly relevant. An application that delegates restricted reads to database privileges needs the database to account for every column that a query actually reads.

The missing columns were permission metadata

The 13.2 release notes describe CVE-2021-20229 as a failure to record all columns read by certain join queries. PostgreSQL uses column-usage bitmaps for permission checks. The parser could construct an incomplete bitmap even though the query still referred to additional columns.

The executor continued to require some SELECT privilege. That limited the attack to a user with an existing grant, but it did not preserve the intended restriction. Permission to read a single column could become sufficient to read every column through a specially constructed query. The distinction matters for roles whose access is intentionally narrower than the entire table.

A permission check can only evaluate the objects its input describes. Here, the access-checking code received an incomplete description of the query. Adding a check elsewhere in an application would not repair that database metadata. The parser needed to record the complete set of columns so the existing permissions machinery could make the right decision.

The release credits Tom Lane with the fix and Sven Klemm with reporting the issue. Its description also explains why existing views need separate attention. A stored view subject to the problem contains the incomplete column-usage bitmaps. Updating PostgreSQL prevents the parser from creating the same bad information, but the already-stored definition still needs reparsing.

For installations that rely on column-level permissions, the project recommends applying CREATE OR REPLACE to all user-defined views. That instruction is broader than finding a single known exploit query. It addresses stored definitions that may already contain the bad metadata, including definitions whose security problem has not been observed.

The operational consequence is a deployment with two relevant completion conditions. The running server must contain the fixed parser, and affected stored definitions must have been rebuilt through it. Treating a successful server restart as the entire security repair leaves the second condition unresolved.

Error messages can disclose protected values

CVE-2021-3393 involves another path to column contents. A user with UPDATE permission on a partitioned table can encounter an error while moving a row to a different partition. If a constraint rejects the row in the destination partition, the resulting diagnostic can reveal values the user lacks permission to select.

The release notes identify a specific structural condition. Columns in the destination partition have different physical positions from the columns in the parent table. That mismatch matters when the error-reporting code decides which values it can display. A diagnostic about a failed write must still obey the reader's column permissions.

The reported privilege combination is legitimate. A role can have authority to update a table without having SELECT permission on every column. A failed operation must not silently expand that role's ability to inspect data. The database's error path is therefore part of its information-access policy.

Heikki Linnakangas receives credit for reporting this issue and for the release-note fix. The announcement describes the exploit conditions as rarer than those of the earlier CVE-2014-8161. That comparison does not make the older identifier a newly fixed vulnerability in this release. February's announcement explicitly counts two security issues.

Persistent index state also needs attention

The same update contains correctness fixes that can require work on existing indexes. They have a similar operational shape to the stored-view repair, although their mechanisms differ. Fixed code stops producing the defective state, while an existing database object may retain the consequences of earlier execution.

Concurrent insertions into a GiST index could incorrectly handle concurrent page splits. The result could be index entries on the wrong pages. The release notes recommend reindexing GiST indexes that have experienced concurrent insertions. An index can remain present and usable enough to avoid an obvious startup failure while still requiring reconstruction.

A separate fix changes CREATE INDEX CONCURRENTLY to wait for prepared transactions. The index-building operation must account for rows those transactions inserted. Failing to wait could omit rows from the new index, allowing later queries that depend on it to miss them.

The recommendation applies to installations with prepared transactions enabled, identified in the notes by max_prepared_transactions greater than zero. Their concurrently built indexes are candidates for reindexing. This qualification makes the recommendation more specific than rebuilding every index in every installation.

I prefer release notes that explain the retained state as well as the changed code. These instructions identify why particular catalog definitions and indexes deserve attention. They also keep the security repair separate from the index-correctness work, which has different exposure conditions.

The update also ends the 9.5 branch

The announcement identifies 9.5.25 as PostgreSQL 9.5's final release. Applying it does not provide that branch with continuing maintenance. Operators on 9.5 therefore have a separate major-version upgrade to plan after receiving this last update.

For an existing 13.x installation, 13.2 requires no dump and restore. The project describes the ordinary minor-update procedure as stopping PostgreSQL and replacing its binaries. It also tells operators who skipped updates to review earlier release notes for additional steps. In this release, the stored-view and index instructions explain why the binary replacement and the database's resulting state need separate records.