Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitedc0a8d

Browse files
committed
Detect integer overflow while computing new array dimensions.
array_set_element() and related functions allow an array to beenlarged by assigning to subscripts outside the current array bounds.While these places were careful to check that the new bounds areallowable, they neglected to consider the risk of integer overflowin computing the new bounds. In edge cases, we could compute newbounds that are invalid but get past the subsequent checks,allowing bad things to happen. Memory stomps that are potentiallyexploitable for arbitrary code execution are possible, and so isdisclosure of server memory.To fix, perform the hazardous computations using overflow-detectingarithmetic routines, which fortunately exist in all still-supportedbranches.The test cases added for this generate (after patching) errors thatmention the value of MaxArraySize, which is platform-dependent.Rather than introduce multiple expected-files, use psql's VERBOSITYparameter to suppress the printing of the message text. v11 psqllacks that parameter, so omit the tests in that branch.Our thanks to Pedro Gallegos for reporting this problem.Security:CVE-2023-5869
1 parent9146d0d commitedc0a8d

File tree

5 files changed

+110
-24
lines changed

5 files changed

+110
-24
lines changed

‎src/backend/utils/adt/arrayfuncs.c

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include"access/htup_details.h"
2121
#include"catalog/pg_type.h"
22+
#include"common/int.h"
2223
#include"funcapi.h"
2324
#include"libpq/pqformat.h"
2425
#include"nodes/nodeFuncs.h"
@@ -2334,22 +2335,38 @@ array_set_element(Datum arraydatum,
23342335
addedbefore=addedafter=0;
23352336

23362337
/*
2337-
* Check subscripts
2338+
* Check subscripts. We assume the existing subscripts passed
2339+
* ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2340+
* overflow. But we must beware of other overflows in our calculations of
2341+
* new dim[] values.
23382342
*/
23392343
if (ndim==1)
23402344
{
23412345
if (indx[0]<lb[0])
23422346
{
2343-
addedbefore=lb[0]-indx[0];
2344-
dim[0]+=addedbefore;
2347+
/* addedbefore = lb[0] - indx[0]; */
2348+
/* dim[0] += addedbefore; */
2349+
if (pg_sub_s32_overflow(lb[0],indx[0],&addedbefore)||
2350+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2351+
ereport(ERROR,
2352+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2353+
errmsg("array size exceeds the maximum allowed (%d)",
2354+
(int)MaxArraySize)));
23452355
lb[0]=indx[0];
23462356
if (addedbefore>1)
23472357
newhasnulls= true;/* will insert nulls */
23482358
}
23492359
if (indx[0] >= (dim[0]+lb[0]))
23502360
{
2351-
addedafter=indx[0]- (dim[0]+lb[0])+1;
2352-
dim[0]+=addedafter;
2361+
/* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2362+
/* dim[0] += addedafter; */
2363+
if (pg_sub_s32_overflow(indx[0],dim[0]+lb[0],&addedafter)||
2364+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2365+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2366+
ereport(ERROR,
2367+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2368+
errmsg("array size exceeds the maximum allowed (%d)",
2369+
(int)MaxArraySize)));
23532370
if (addedafter>1)
23542371
newhasnulls= true;/* will insert nulls */
23552372
}
@@ -2595,23 +2612,39 @@ array_set_element_expanded(Datum arraydatum,
25952612
addedbefore=addedafter=0;
25962613

25972614
/*
2598-
* Check subscripts (this logic matches original array_set_element)
2615+
* Check subscripts (this logic must match array_set_element). We assume
2616+
* the existing subscripts passed ArrayCheckBounds, so that dim[i] + lb[i]
2617+
* can be computed without overflow. But we must beware of other
2618+
* overflows in our calculations of new dim[] values.
25992619
*/
26002620
if (ndim==1)
26012621
{
26022622
if (indx[0]<lb[0])
26032623
{
2604-
addedbefore=lb[0]-indx[0];
2605-
dim[0]+=addedbefore;
2624+
/* addedbefore = lb[0] - indx[0]; */
2625+
/* dim[0] += addedbefore; */
2626+
if (pg_sub_s32_overflow(lb[0],indx[0],&addedbefore)||
2627+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2628+
ereport(ERROR,
2629+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2630+
errmsg("array size exceeds the maximum allowed (%d)",
2631+
(int)MaxArraySize)));
26062632
lb[0]=indx[0];
26072633
dimschanged= true;
26082634
if (addedbefore>1)
26092635
newhasnulls= true;/* will insert nulls */
26102636
}
26112637
if (indx[0] >= (dim[0]+lb[0]))
26122638
{
2613-
addedafter=indx[0]- (dim[0]+lb[0])+1;
2614-
dim[0]+=addedafter;
2639+
/* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2640+
/* dim[0] += addedafter; */
2641+
if (pg_sub_s32_overflow(indx[0],dim[0]+lb[0],&addedafter)||
2642+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2643+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2644+
ereport(ERROR,
2645+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2646+
errmsg("array size exceeds the maximum allowed (%d)",
2647+
(int)MaxArraySize)));
26152648
dimschanged= true;
26162649
if (addedafter>1)
26172650
newhasnulls= true;/* will insert nulls */
@@ -2894,7 +2927,10 @@ array_set_slice(Datum arraydatum,
28942927
addedbefore=addedafter=0;
28952928

28962929
/*
2897-
* Check subscripts
2930+
* Check subscripts. We assume the existing subscripts passed
2931+
* ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2932+
* overflow. But we must beware of other overflows in our calculations of
2933+
* new dim[] values.
28982934
*/
28992935
if (ndim==1)
29002936
{
@@ -2909,18 +2945,31 @@ array_set_slice(Datum arraydatum,
29092945
errmsg("upper bound cannot be less than lower bound")));
29102946
if (lowerIndx[0]<lb[0])
29112947
{
2912-
if (upperIndx[0]<lb[0]-1)
2913-
newhasnulls= true;/* will insert nulls */
2914-
addedbefore=lb[0]-lowerIndx[0];
2915-
dim[0]+=addedbefore;
2948+
/* addedbefore = lb[0] - lowerIndx[0]; */
2949+
/* dim[0] += addedbefore; */
2950+
if (pg_sub_s32_overflow(lb[0],lowerIndx[0],&addedbefore)||
2951+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2952+
ereport(ERROR,
2953+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2954+
errmsg("array size exceeds the maximum allowed (%d)",
2955+
(int)MaxArraySize)));
29162956
lb[0]=lowerIndx[0];
2957+
if (addedbefore>1)
2958+
newhasnulls= true;/* will insert nulls */
29172959
}
29182960
if (upperIndx[0] >= (dim[0]+lb[0]))
29192961
{
2920-
if (lowerIndx[0]> (dim[0]+lb[0]))
2962+
/* addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; */
2963+
/* dim[0] += addedafter; */
2964+
if (pg_sub_s32_overflow(upperIndx[0],dim[0]+lb[0],&addedafter)||
2965+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2966+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2967+
ereport(ERROR,
2968+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2969+
errmsg("array size exceeds the maximum allowed (%d)",
2970+
(int)MaxArraySize)));
2971+
if (addedafter>1)
29212972
newhasnulls= true;/* will insert nulls */
2922-
addedafter=upperIndx[0]- (dim[0]+lb[0])+1;
2923-
dim[0]+=addedafter;
29242973
}
29252974
}
29262975
else

‎src/backend/utils/adt/arrayutils.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ ArrayGetOffset0(int n, const int *tup, const int *scale)
6464
* This must do overflow checking, since it is used to validate that a user
6565
* dimensionality request doesn't overflow what we can handle.
6666
*
67-
* We limit array sizes to at most about a quarter billion elements,
68-
* so that it's not necessary to check for overflow in quite so many
69-
* places --- for instance when palloc'ing Datum arrays.
70-
*
7167
* The multiplication overflow check only works on machines that have int64
7268
* arithmetic, but that is nearly all platforms these days, and doing check
7369
* divides for those that don't seems way too expensive.
@@ -78,8 +74,6 @@ ArrayGetNItems(int ndim, const int *dims)
7874
int32ret;
7975
inti;
8076

81-
#defineMaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
82-
8377
if (ndim <=0)
8478
return0;
8579
ret=1;

‎src/include/utils/array.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ struct ExprContext;
7474
*/
7575
#defineMAXDIM 6
7676

77+
/*
78+
* Maximum number of elements in an array. We limit this to at most about a
79+
* quarter billion elements, so that it's not necessary to check for overflow
80+
* in quite so many places --- for instance when palloc'ing Datum arrays.
81+
*/
82+
#defineMaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
83+
7784
/*
7885
* Arrays are varlena objects, so must meet the varlena convention that
7986
* the first int32 of the object contains the total object size in bytes.

‎src/test/regress/expected/arrays.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,23 @@ insert into arr_pk_tbl(pk, f1[1:2]) values (1, '{6,7,8}') on conflict (pk)
13801380
-- then you didn't get an indexscan plan, and something is busted.
13811381
reset enable_seqscan;
13821382
reset enable_bitmapscan;
1383+
-- test subscript overflow detection
1384+
-- The normal error message includes a platform-dependent limit,
1385+
-- so suppress it to avoid needing multiple expected-files.
1386+
\set VERBOSITY sqlstate
1387+
insert into arr_pk_tbl values(10, '[-2147483648:-2147483647]={1,2}');
1388+
update arr_pk_tbl set f1[2147483647] = 42 where pk = 10;
1389+
ERROR: 54000
1390+
update arr_pk_tbl set f1[2147483646:2147483647] = array[4,2] where pk = 10;
1391+
ERROR: 54000
1392+
-- also exercise the expanded-array case
1393+
do $$ declare a int[];
1394+
begin
1395+
a := '[-2147483648:-2147483647]={1,2}'::int[];
1396+
a[2147483647] := 42;
1397+
end $$;
1398+
ERROR: 54000
1399+
\set VERBOSITY default
13831400
-- test [not] (like|ilike) (any|all) (...)
13841401
select 'foo' like any (array['%a', '%o']); -- t
13851402
?column?

‎src/test/regress/sql/arrays.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,25 @@ insert into arr_pk_tbl(pk, f1[1:2]) values (1, '{6,7,8}') on conflict (pk)
415415
reset enable_seqscan;
416416
reset enable_bitmapscan;
417417

418+
-- test subscript overflow detection
419+
420+
-- The normal error message includes a platform-dependent limit,
421+
-- so suppress it to avoid needing multiple expected-files.
422+
\set VERBOSITY sqlstate
423+
424+
insert into arr_pk_tblvalues(10,'[-2147483648:-2147483647]={1,2}');
425+
update arr_pk_tblset f1[2147483647]=42where pk=10;
426+
update arr_pk_tblset f1[2147483646:2147483647]= array[4,2]where pk=10;
427+
428+
-- also exercise the expanded-array case
429+
do $$ declare aint[];
430+
begin
431+
a :='[-2147483648:-2147483647]={1,2}'::int[];
432+
a[2147483647] :=42;
433+
end $$;
434+
435+
\set VERBOSITY default
436+
418437
-- test [not] (like|ilike) (any|all) (...)
419438
select'foo'like any (array['%a','%o']);-- t
420439
select'foo'like any (array['%a','%b']);-- f

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp