May 13, 2021·5 min read·engineeringpostgresqlsecuritymemory

PostgreSQL 13.3 fixes memory errors behind ordinary SQL operations

May's update repairs array-bound arithmetic and two paths through update processing. The security effects depend on how SQL values become internal row representations.

An SQL array can have a lower bound and a length that are individually representable while their sum overflows an integer. PostgreSQL's array code previously accepted that combination. Some elements then had no usable integer subscript, and later assignments could overwrite server memory. The defect illustrates how a declarative SQL operation still depends on correct arithmetic in the engine.

The May 13 update fixes that issue as CVE-2021-32027. PostgreSQL 13.3 arrives with corresponding updates 12.7, 11.12, 10.17 and 9.6.22. The announcement identifies three security vulnerabilities, including two memory-disclosure paths through update processing.

I continue to prefer PostgreSQL for relational work, including its ability to keep substantial behavior in the database. These fixes concern the implementation underneath that behavior. An authenticated user's authority to submit SQL must not become authority to read unrelated server memory or overwrite it.

Validating the whole array range

The 13.3 release notes explain that the array implementation failed to reject a lower bound plus length that overflowed an integer. The invalid range first made later array entries inaccessible. More seriously, it confused assignment operations that depended on the array's bounds.

The announcement describes authenticated users writing arbitrary bytes over a wide area of server memory while modifying certain array values. The release notes name crashes and unwanted data changes as consequences of the overwrite. These descriptions connect the user-visible operation to the internal memory error without requiring an attacker to control the server's executable code.

The defect also demonstrates why checking each field separately is insufficient. A lower bound can pass its own integer check while the complete range remains invalid. Any later code that assumes the range has already been validated receives a false premise. Rejecting overflow at the bounds calculation prevents that premise from reaching assignment processing.

Tom Lane receives credit for reporting this issue. The announcement lists the supported affected versions as 9.6 through 13 and notes that the problem is old. It does not establish a tested vulnerability range for unsupported branches. An operator should not infer that an unlisted, unsupported branch is safe merely because the security team did not test it.

Internal columns escaped into stored rows

CVE-2021-32028 concerns INSERT with ON CONFLICT DO UPDATE. The release notes describe mishandling of internal junk columns when the update target list contains multicolumn subselects. Those internal columns exist in addition to the actual result values the update should store.

On the affected update path, PostgreSQL could store tuples containing the extra values. The notes explain why that might appear harmless initially. Adding columns later could make the values accessible, with additional malfunctions if the exposed values did not match the new columns' data types.

That sequence makes the defect difficult to characterize only by the statement that first triggers it. The immediate operation can leave an invalid row representation whose consequences become visible after a later schema change. The correctness requirement concerns what gets stored, even when the current table definition does not expose every stored value.

Cross-partition updates had a related failure in the opposite direction. In versions supporting that operation, PostgreSQL removed the junk columns from the target list. The multicolumn subselect machinery could then malfunction and usually crash. The same internal values needed different treatment at different execution stages.

The security announcement describes the issue as permitting arbitrary server-memory reads through a purpose-built table. Andres Freund reported it. The supported affected branches are 9.6 through 13, while the announcement notes that ON CONFLICT first appeared in 9.5. The distinction between feature introduction and the tested supported range matters when describing the advisory.

A moved row can have a different physical layout

CVE-2021-32029 also concerns update processing, but its trigger is a joined update that moves a row between partitions. The destination partition can have a physically different row type. The release notes give different sets of dropped columns as an example of how those layouts can differ.

Computing RETURNING values for the moved row could then produce errors or incorrect answers. The notes specify that the observed problem requires other tables joined to the update target. Merely naming partitioning and RETURNING does not describe the full failure condition.

The announcement classifies the security consequence as arbitrary server-memory disclosure through a specially prepared partitioned table. Versions 11 through 13 are affected. Tom Lane reported the issue, while Amit Langote and Etsuro Fujita receive credit in the release notes for the fix.

The partition arrangement explains why a logical table abstraction does not eliminate physical row-layout work inside the executor. An operation can cross a partition boundary while still needing to produce RETURNING values associated with the joined statement. Correctly interpreting the row at that stage requires the right description of its physical form.

Creation privileges affect exposure

For the two memory-disclosure issues, the announcement discusses the privileges needed to prepare an attack. Under the default configuration, an authenticated user can create the prerequisite objects. Restricted creation privileges change that assessment because the attacker needs a suitable table.

The advisory states that a user without CREATE and TEMPORARY privileges on every database, and without CREATE on every schema, cannot use the ON CONFLICT attack at will. For the partitioned-table issue, it qualifies the equivalent statement with typically. That qualification belongs in any explanation of the mitigation.

These restrictions affect an attacker's ability to construct the required objects. They do not repair the underlying execution paths. The array-bound advisory also describes authenticated-user exposure without presenting the same object-creation restriction as its boundary.

I consider that privilege detail useful because it explains the immediate risk for different database roles. It also prevents an application-only assessment from overlooking users who can submit SQL directly. The security description concerns authenticated database access, including authority that may be broader than one application's normal queries.

Applying this minor update does not require a dump and restore for a 13.x database. The release notes direct anyone upgrading from before 13.2 to that earlier release's additional instructions. May's binaries fix the newly described execution paths, while those earlier migration instructions still determine whether the complete update procedure needs work on existing objects.