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

Commit26c599b

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 parentd3de70f commit26c599b

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"
@@ -2311,22 +2312,38 @@ array_set_element(Datum arraydatum,
23112312
addedbefore=addedafter=0;
23122313

23132314
/*
2314-
* Check subscripts
2315+
* Check subscripts. We assume the existing subscripts passed
2316+
* ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2317+
* overflow. But we must beware of other overflows in our calculations of
2318+
* new dim[] values.
23152319
*/
23162320
if (ndim==1)
23172321
{
23182322
if (indx[0]<lb[0])
23192323
{
2320-
addedbefore=lb[0]-indx[0];
2321-
dim[0]+=addedbefore;
2324+
/* addedbefore = lb[0] - indx[0]; */
2325+
/* dim[0] += addedbefore; */
2326+
if (pg_sub_s32_overflow(lb[0],indx[0],&addedbefore)||
2327+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2328+
ereport(ERROR,
2329+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2330+
errmsg("array size exceeds the maximum allowed (%d)",
2331+
(int)MaxArraySize)));
23222332
lb[0]=indx[0];
23232333
if (addedbefore>1)
23242334
newhasnulls= true;/* will insert nulls */
23252335
}
23262336
if (indx[0] >= (dim[0]+lb[0]))
23272337
{
2328-
addedafter=indx[0]- (dim[0]+lb[0])+1;
2329-
dim[0]+=addedafter;
2338+
/* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2339+
/* dim[0] += addedafter; */
2340+
if (pg_sub_s32_overflow(indx[0],dim[0]+lb[0],&addedafter)||
2341+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2342+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2343+
ereport(ERROR,
2344+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2345+
errmsg("array size exceeds the maximum allowed (%d)",
2346+
(int)MaxArraySize)));
23302347
if (addedafter>1)
23312348
newhasnulls= true;/* will insert nulls */
23322349
}
@@ -2569,23 +2586,39 @@ array_set_element_expanded(Datum arraydatum,
25692586
addedbefore=addedafter=0;
25702587

25712588
/*
2572-
* Check subscripts (this logic matches original array_set_element)
2589+
* Check subscripts (this logic must match array_set_element). We assume
2590+
* the existing subscripts passed ArrayCheckBounds, so that dim[i] + lb[i]
2591+
* can be computed without overflow. But we must beware of other
2592+
* overflows in our calculations of new dim[] values.
25732593
*/
25742594
if (ndim==1)
25752595
{
25762596
if (indx[0]<lb[0])
25772597
{
2578-
addedbefore=lb[0]-indx[0];
2579-
dim[0]+=addedbefore;
2598+
/* addedbefore = lb[0] - indx[0]; */
2599+
/* dim[0] += addedbefore; */
2600+
if (pg_sub_s32_overflow(lb[0],indx[0],&addedbefore)||
2601+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2602+
ereport(ERROR,
2603+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2604+
errmsg("array size exceeds the maximum allowed (%d)",
2605+
(int)MaxArraySize)));
25802606
lb[0]=indx[0];
25812607
dimschanged= true;
25822608
if (addedbefore>1)
25832609
newhasnulls= true;/* will insert nulls */
25842610
}
25852611
if (indx[0] >= (dim[0]+lb[0]))
25862612
{
2587-
addedafter=indx[0]- (dim[0]+lb[0])+1;
2588-
dim[0]+=addedafter;
2613+
/* addedafter = indx[0] - (dim[0] + lb[0]) + 1; */
2614+
/* dim[0] += addedafter; */
2615+
if (pg_sub_s32_overflow(indx[0],dim[0]+lb[0],&addedafter)||
2616+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2617+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2618+
ereport(ERROR,
2619+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2620+
errmsg("array size exceeds the maximum allowed (%d)",
2621+
(int)MaxArraySize)));
25892622
dimschanged= true;
25902623
if (addedafter>1)
25912624
newhasnulls= true;/* will insert nulls */
@@ -2867,7 +2900,10 @@ array_set_slice(Datum arraydatum,
28672900
addedbefore=addedafter=0;
28682901

28692902
/*
2870-
* Check subscripts
2903+
* Check subscripts. We assume the existing subscripts passed
2904+
* ArrayCheckBounds, so that dim[i] + lb[i] can be computed without
2905+
* overflow. But we must beware of other overflows in our calculations of
2906+
* new dim[] values.
28712907
*/
28722908
if (ndim==1)
28732909
{
@@ -2882,18 +2918,31 @@ array_set_slice(Datum arraydatum,
28822918
errmsg("upper bound cannot be less than lower bound")));
28832919
if (lowerIndx[0]<lb[0])
28842920
{
2885-
if (upperIndx[0]<lb[0]-1)
2886-
newhasnulls= true;/* will insert nulls */
2887-
addedbefore=lb[0]-lowerIndx[0];
2888-
dim[0]+=addedbefore;
2921+
/* addedbefore = lb[0] - lowerIndx[0]; */
2922+
/* dim[0] += addedbefore; */
2923+
if (pg_sub_s32_overflow(lb[0],lowerIndx[0],&addedbefore)||
2924+
pg_add_s32_overflow(dim[0],addedbefore,&dim[0]))
2925+
ereport(ERROR,
2926+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2927+
errmsg("array size exceeds the maximum allowed (%d)",
2928+
(int)MaxArraySize)));
28892929
lb[0]=lowerIndx[0];
2930+
if (addedbefore>1)
2931+
newhasnulls= true;/* will insert nulls */
28902932
}
28912933
if (upperIndx[0] >= (dim[0]+lb[0]))
28922934
{
2893-
if (lowerIndx[0]> (dim[0]+lb[0]))
2935+
/* addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; */
2936+
/* dim[0] += addedafter; */
2937+
if (pg_sub_s32_overflow(upperIndx[0],dim[0]+lb[0],&addedafter)||
2938+
pg_add_s32_overflow(addedafter,1,&addedafter)||
2939+
pg_add_s32_overflow(dim[0],addedafter,&dim[0]))
2940+
ereport(ERROR,
2941+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2942+
errmsg("array size exceeds the maximum allowed (%d)",
2943+
(int)MaxArraySize)));
2944+
if (addedafter>1)
28942945
newhasnulls= true;/* will insert nulls */
2895-
addedafter=upperIndx[0]- (dim[0]+lb[0])+1;
2896-
dim[0]+=addedafter;
28972946
}
28982947
}
28992948
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
@@ -69,6 +69,13 @@ struct ExprState;
6969
structExprContext;
7070

7171

72+
/*
73+
* Maximum number of elements in an array. We limit this to at most about a
74+
* quarter billion elements, so that it's not necessary to check for overflow
75+
* in quite so many places --- for instance when palloc'ing Datum arrays.
76+
*/
77+
#defineMaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))
78+
7279
/*
7380
* Arrays are varlena objects, so must meet the varlena convention that
7481
* 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
@@ -1359,6 +1359,23 @@ insert into arr_pk_tbl(pk, f1[1:2]) values (1, '{6,7,8}') on conflict (pk)
13591359
-- then you didn't get an indexscan plan, and something is busted.
13601360
reset enable_seqscan;
13611361
reset enable_bitmapscan;
1362+
-- test subscript overflow detection
1363+
-- The normal error message includes a platform-dependent limit,
1364+
-- so suppress it to avoid needing multiple expected-files.
1365+
\set VERBOSITY sqlstate
1366+
insert into arr_pk_tbl values(10, '[-2147483648:-2147483647]={1,2}');
1367+
update arr_pk_tbl set f1[2147483647] = 42 where pk = 10;
1368+
ERROR: 54000
1369+
update arr_pk_tbl set f1[2147483646:2147483647] = array[4,2] where pk = 10;
1370+
ERROR: 54000
1371+
-- also exercise the expanded-array case
1372+
do $$ declare a int[];
1373+
begin
1374+
a := '[-2147483648:-2147483647]={1,2}'::int[];
1375+
a[2147483647] := 42;
1376+
end $$;
1377+
ERROR: 54000
1378+
\set VERBOSITY default
13621379
-- test [not] (like|ilike) (any|all) (...)
13631380
select 'foo' like any (array['%a', '%o']); -- t
13641381
?column?

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

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

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp