1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-13 14:22:43 +03:00

Add runtime checks for bogus multixact offsets

It's not far-fetched that we'd try to read a multixid with an invalid
offset in case of bugs or corruption. Or if you call
pg_get_multixact_members() after a crash that left behind invalid but
unused multixids. Better to get a somewhat descriptive error message
if that happens.

Discussion: https://www.postgresql.org/message-id/3624730d-6dae-42bf-9458-76c4c965fb27@iki.fi
This commit is contained in:
Heikki Linnakangas
2025-12-11 11:18:14 +02:00
parent 795e94c70c
commit d4b7bde418

View File

@@ -1153,6 +1153,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
int slotno; int slotno;
MultiXactOffset *offptr; MultiXactOffset *offptr;
MultiXactOffset offset; MultiXactOffset offset;
MultiXactOffset nextMXOffset;
int length; int length;
MultiXactId oldestMXact; MultiXactId oldestMXact;
MultiXactId nextMXact; MultiXactId nextMXact;
@@ -1244,12 +1245,14 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
offptr += entryno; offptr += entryno;
offset = *offptr; offset = *offptr;
Assert(offset != 0); if (offset == 0)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("MultiXact %u has invalid offset", multi)));
/* read next multi's offset */ /* read next multi's offset */
{ {
MultiXactId tmpMXact; MultiXactId tmpMXact;
MultiXactOffset nextMXOffset;
/* handle wraparound if needed */ /* handle wraparound if needed */
tmpMXact = multi + 1; tmpMXact = multi + 1;
@@ -1283,21 +1286,27 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
offptr += entryno; offptr += entryno;
nextMXOffset = *offptr; nextMXOffset = *offptr;
if (nextMXOffset == 0)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("MultiXact %u has invalid next offset",
multi)));
length = nextMXOffset - offset;
} }
LWLockRelease(lock); LWLockRelease(lock);
lock = NULL; lock = NULL;
/* A multixid with zero members should not happen */ /* Sanity check the next offset */
Assert(length > 0); if (nextMXOffset == 0)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("MultiXact %u has invalid next offset", multi)));
if (nextMXOffset < offset)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")",
multi, offset, nextMXOffset)));
if (nextMXOffset - offset > INT32_MAX)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
errmsg("MultiXact %u has too many members (%" PRIu64 ")",
multi, nextMXOffset - offset)));
length = nextMXOffset - offset;
/* read the members */ /* read the members */
ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember)); ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));