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

Commit5f93c37

Browse files
committed
Add defenses against running with a wrong selection of LOBLKSIZE.
It's critical that the backend's idea of LOBLKSIZE match the way data hasactually been divided up in pg_largeobject. While we don't provide anydirect way to adjust that value, doing so is a one-line source code changeand various people have expressed interest recently in changing it. So,just as with TOAST_MAX_CHUNK_SIZE, it seems prudent to record the value inpg_control and cross-check that the backend's compiled-in setting matchesthe on-disk data.Also tweak the code in inv_api.c so that fetches from pg_largeobjectexplicitly verify that the length of the data field is not more thanLOBLKSIZE. Formerly we just had Asserts() for that, which is no protectionat all in production builds. In some of the call sites an overlength datavalue would translate directly to a security-relevant stack clobber, so itseems worth one extra runtime comparison to be sure.In the back branches, we can't change the contents of pg_control; but wecan still make the extra checks in inv_api.c, which will offer some amountof protection against running with the wrong value of LOBLKSIZE.
1 parentf0c1085 commit5f93c37

File tree

6 files changed

+58
-46
lines changed

6 files changed

+58
-46
lines changed

‎src/backend/access/transam/xlog.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include"storage/bufmgr.h"
5050
#include"storage/fd.h"
5151
#include"storage/ipc.h"
52+
#include"storage/large_object.h"
5253
#include"storage/latch.h"
5354
#include"storage/pmsignal.h"
5455
#include"storage/predicate.h"
@@ -4352,6 +4353,7 @@ WriteControlFile(void)
43524353
ControlFile->indexMaxKeys=INDEX_MAX_KEYS;
43534354

43544355
ControlFile->toast_max_chunk_size=TOAST_MAX_CHUNK_SIZE;
4356+
ControlFile->loblksize=LOBLKSIZE;
43554357

43564358
#ifdefHAVE_INT64_TIMESTAMP
43574359
ControlFile->enableIntTimes= true;
@@ -4545,6 +4547,13 @@ ReadControlFile(void)
45454547
" but the server was compiled with TOAST_MAX_CHUNK_SIZE %d.",
45464548
ControlFile->toast_max_chunk_size, (int)TOAST_MAX_CHUNK_SIZE),
45474549
errhint("It looks like you need to recompile or initdb.")));
4550+
if (ControlFile->loblksize!=LOBLKSIZE)
4551+
ereport(FATAL,
4552+
(errmsg("database files are incompatible with server"),
4553+
errdetail("The database cluster was initialized with LOBLKSIZE %d,"
4554+
" but the server was compiled with LOBLKSIZE %d.",
4555+
ControlFile->loblksize, (int)LOBLKSIZE),
4556+
errhint("It looks like you need to recompile or initdb.")));
45484557

45494558
#ifdefHAVE_INT64_TIMESTAMP
45504559
if (ControlFile->enableIntTimes!= true)

‎src/backend/storage/large_object/inv_api.c

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,38 @@ myLargeObjectExists(Oid loid, Snapshot snapshot)
173173
}
174174

175175

176-
staticint32
177-
getbytealen(bytea*data)
176+
/*
177+
* Extract data field from a pg_largeobject tuple, detoasting if needed
178+
* and verifying that the length is sane. Returns data pointer (a bytea *),
179+
* data length, and an indication of whether to pfree the data pointer.
180+
*/
181+
staticvoid
182+
getdatafield(Form_pg_largeobjecttuple,
183+
bytea**pdatafield,
184+
int*plen,
185+
bool*pfreeit)
178186
{
179-
Assert(!VARATT_IS_EXTENDED(data));
180-
if (VARSIZE(data)<VARHDRSZ)
181-
elog(ERROR,"invalid VARSIZE(data)");
182-
return (VARSIZE(data)-VARHDRSZ);
187+
bytea*datafield;
188+
intlen;
189+
boolfreeit;
190+
191+
datafield=&(tuple->data);/* see note at top of file */
192+
freeit= false;
193+
if (VARATT_IS_EXTENDED(datafield))
194+
{
195+
datafield= (bytea*)
196+
heap_tuple_untoast_attr((structvarlena*)datafield);
197+
freeit= true;
198+
}
199+
len=VARSIZE(datafield)-VARHDRSZ;
200+
if (len<0||len>LOBLKSIZE)
201+
ereport(ERROR,
202+
(errcode(ERRCODE_DATA_CORRUPTED),
203+
errmsg("pg_largeobject entry for OID %u, page %d has invalid data field size %d",
204+
tuple->loid,tuple->pageno,len)));
205+
*pdatafield=datafield;
206+
*plen=len;
207+
*pfreeit=freeit;
183208
}
184209

185210

@@ -366,20 +391,14 @@ inv_getsize(LargeObjectDesc *obj_desc)
366391
{
367392
Form_pg_largeobjectdata;
368393
bytea*datafield;
394+
intlen;
369395
boolpfreeit;
370396

371397
if (HeapTupleHasNulls(tuple))/* paranoia */
372398
elog(ERROR,"null field found in pg_largeobject");
373399
data= (Form_pg_largeobject)GETSTRUCT(tuple);
374-
datafield=&(data->data);/* see note at top of file */
375-
pfreeit= false;
376-
if (VARATT_IS_EXTENDED(datafield))
377-
{
378-
datafield= (bytea*)
379-
heap_tuple_untoast_attr((structvarlena*)datafield);
380-
pfreeit= true;
381-
}
382-
lastbyte= (uint64)data->pageno*LOBLKSIZE+getbytealen(datafield);
400+
getdatafield(data,&datafield,&len,&pfreeit);
401+
lastbyte= (uint64)data->pageno*LOBLKSIZE+len;
383402
if (pfreeit)
384403
pfree(datafield);
385404
}
@@ -506,15 +525,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
506525
off= (int) (obj_desc->offset-pageoff);
507526
Assert(off >=0&&off<LOBLKSIZE);
508527

509-
datafield=&(data->data);/* see note at top of file */
510-
pfreeit= false;
511-
if (VARATT_IS_EXTENDED(datafield))
512-
{
513-
datafield= (bytea*)
514-
heap_tuple_untoast_attr((structvarlena*)datafield);
515-
pfreeit= true;
516-
}
517-
len=getbytealen(datafield);
528+
getdatafield(data,&datafield,&len,&pfreeit);
518529
if (len>off)
519530
{
520531
n=len-off;
@@ -630,16 +641,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
630641
*
631642
* First, load old data into workbuf
632643
*/
633-
datafield=&(olddata->data);/* see note at top of file */
634-
pfreeit= false;
635-
if (VARATT_IS_EXTENDED(datafield))
636-
{
637-
datafield= (bytea*)
638-
heap_tuple_untoast_attr((structvarlena*)datafield);
639-
pfreeit= true;
640-
}
641-
len=getbytealen(datafield);
642-
Assert(len <=LOBLKSIZE);
644+
getdatafield(olddata,&datafield,&len,&pfreeit);
643645
memcpy(workb,VARDATA(datafield),len);
644646
if (pfreeit)
645647
pfree(datafield);
@@ -815,19 +817,11 @@ inv_truncate(LargeObjectDesc *obj_desc, int64 len)
815817
if (olddata!=NULL&&olddata->pageno==pageno)
816818
{
817819
/* First, load old data into workbuf */
818-
bytea*datafield=&(olddata->data);/* see note at top of
819-
* file */
820-
boolpfreeit= false;
820+
bytea*datafield;
821821
intpagelen;
822+
boolpfreeit;
822823

823-
if (VARATT_IS_EXTENDED(datafield))
824-
{
825-
datafield= (bytea*)
826-
heap_tuple_untoast_attr((structvarlena*)datafield);
827-
pfreeit= true;
828-
}
829-
pagelen=getbytealen(datafield);
830-
Assert(pagelen <=LOBLKSIZE);
824+
getdatafield(olddata,&datafield,&pagelen,&pfreeit);
831825
memcpy(workb,VARDATA(datafield),pagelen);
832826
if (pfreeit)
833827
pfree(datafield);

‎src/bin/pg_controldata/pg_controldata.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ main(int argc, char *argv[])
287287
ControlFile.indexMaxKeys);
288288
printf(_("Maximum size of a TOAST chunk: %u\n"),
289289
ControlFile.toast_max_chunk_size);
290+
printf(_("Size of a large-object chunk: %u\n"),
291+
ControlFile.loblksize);
290292
printf(_("Date/time type storage: %s\n"),
291293
(ControlFile.enableIntTimes ?_("64-bit integers") :_("floating-point numbers")));
292294
printf(_("Float4 argument passing: %s\n"),

‎src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include"catalog/catversion.h"
5353
#include"catalog/pg_control.h"
5454
#include"common/fe_memutils.h"
55+
#include"storage/large_object.h"
5556
#include"pg_getopt.h"
5657

5758

@@ -536,6 +537,7 @@ GuessControlValues(void)
536537
ControlFile.nameDataLen=NAMEDATALEN;
537538
ControlFile.indexMaxKeys=INDEX_MAX_KEYS;
538539
ControlFile.toast_max_chunk_size=TOAST_MAX_CHUNK_SIZE;
540+
ControlFile.loblksize=LOBLKSIZE;
539541
#ifdefHAVE_INT64_TIMESTAMP
540542
ControlFile.enableIntTimes= true;
541543
#else
@@ -620,6 +622,8 @@ PrintControlValues(bool guessed)
620622
ControlFile.indexMaxKeys);
621623
printf(_("Maximum size of a TOAST chunk: %u\n"),
622624
ControlFile.toast_max_chunk_size);
625+
printf(_("Size of a large-object chunk: %u\n"),
626+
ControlFile.loblksize);
623627
printf(_("Date/time type storage: %s\n"),
624628
(ControlFile.enableIntTimes ?_("64-bit integers") :_("floating-point numbers")));
625629
printf(_("Float4 argument passing: %s\n"),

‎src/include/catalog/pg_control.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222

2323
/* Version identifier for this pg_control format */
24-
#definePG_CONTROL_VERSION941
24+
#definePG_CONTROL_VERSION942
2525

2626
/*
2727
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -207,6 +207,7 @@ typedef struct ControlFileData
207207
uint32indexMaxKeys;/* max number of columns in an index */
208208

209209
uint32toast_max_chunk_size;/* chunk size in TOAST tables */
210+
uint32loblksize;/* chunk size in pg_largeobject */
210211

211212
/* flag indicating internal format of timestamp, interval, time */
212213
boolenableIntTimes;/* int64 storage enabled? */

‎src/include/storage/large_object.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ typedef struct LargeObjectDesc
6666
* Also, it seems to be a smart move to make the page size be a power of 2,
6767
* since clients will often be written to send data in power-of-2 blocks.
6868
* This avoids unnecessary tuple updates caused by partial-page writes.
69+
*
70+
* NB: Changing LOBLKSIZE requires an initdb.
6971
*/
7072
#defineLOBLKSIZE(BLCKSZ / 4)
7173

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp