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

Commit39129ae

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 parent80d45ae commit39129ae

File tree

1 file changed

+39
-45
lines changed

1 file changed

+39
-45
lines changed

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

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

170170

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

180205

@@ -351,21 +376,15 @@ inv_getsize(LargeObjectDesc *obj_desc)
351376
{
352377
Form_pg_largeobjectdata;
353378
bytea*datafield;
379+
intlen;
354380
boolpfreeit;
355381

356382
found= true;
357383
if (HeapTupleHasNulls(tuple))/* paranoia */
358384
elog(ERROR,"null field found in pg_largeobject");
359385
data= (Form_pg_largeobject)GETSTRUCT(tuple);
360-
datafield=&(data->data);/* see note at top of file */
361-
pfreeit= false;
362-
if (VARATT_IS_EXTENDED(datafield))
363-
{
364-
datafield= (bytea*)
365-
heap_tuple_untoast_attr((structvarlena*)datafield);
366-
pfreeit= true;
367-
}
368-
lastbyte=data->pageno*LOBLKSIZE+getbytealen(datafield);
386+
getdatafield(data,&datafield,&len,&pfreeit);
387+
lastbyte=data->pageno*LOBLKSIZE+len;
369388
if (pfreeit)
370389
pfree(datafield);
371390
break;
@@ -485,15 +504,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
485504
off= (int) (obj_desc->offset-pageoff);
486505
Assert(off >=0&&off<LOBLKSIZE);
487506

488-
datafield=&(data->data);/* see note at top of file */
489-
pfreeit= false;
490-
if (VARATT_IS_EXTENDED(datafield))
491-
{
492-
datafield= (bytea*)
493-
heap_tuple_untoast_attr((structvarlena*)datafield);
494-
pfreeit= true;
495-
}
496-
len=getbytealen(datafield);
507+
getdatafield(data,&datafield,&len,&pfreeit);
497508
if (len>off)
498509
{
499510
n=len-off;
@@ -606,16 +617,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
606617
*
607618
* First, load old data into workbuf
608619
*/
609-
datafield=&(olddata->data);/* see note at top of file */
610-
pfreeit= false;
611-
if (VARATT_IS_EXTENDED(datafield))
612-
{
613-
datafield= (bytea*)
614-
heap_tuple_untoast_attr((structvarlena*)datafield);
615-
pfreeit= true;
616-
}
617-
len=getbytealen(datafield);
618-
Assert(len <=LOBLKSIZE);
620+
getdatafield(olddata,&datafield,&len,&pfreeit);
619621
memcpy(workb,VARDATA(datafield),len);
620622
if (pfreeit)
621623
pfree(datafield);
@@ -782,19 +784,11 @@ inv_truncate(LargeObjectDesc *obj_desc, int len)
782784
if (olddata!=NULL&&olddata->pageno==pageno)
783785
{
784786
/* First, load old data into workbuf */
785-
bytea*datafield=&(olddata->data);/* see note at top of
786-
* file */
787-
boolpfreeit= false;
787+
bytea*datafield;
788788
intpagelen;
789+
boolpfreeit;
789790

790-
if (VARATT_IS_EXTENDED(datafield))
791-
{
792-
datafield= (bytea*)
793-
heap_tuple_untoast_attr((structvarlena*)datafield);
794-
pfreeit= true;
795-
}
796-
pagelen=getbytealen(datafield);
797-
Assert(pagelen <=LOBLKSIZE);
791+
getdatafield(olddata,&datafield,&pagelen,&pfreeit);
798792
memcpy(workb,VARDATA(datafield),pagelen);
799793
if (pfreeit)
800794
pfree(datafield);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp