From 99bf6eceafcde4c0498798d69fc0aae3eab7d297 Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat Date: Thu, 19 Jun 2025 10:39:35 +0530 Subject: [PATCH 2/2] Avoid bloating RelfilenumberMap cache by negative entries RelidByRelfilenumber() has three users, logical replication, autoprewarm and pg_filenode_relation(). The first two seldom cause negative entries in the cache since they lookup a valid relation using valid tablespace and relfilenode. Presence of negative entries doesn't help them. But pg_filenode_relation(), which is SQL callable, may be invoked with invalid tablespace and relfilenode pair causing negative entries in the cache. These entries consume memory which is freed only when an invalidation message is received. This can lead to bloating of the cache. The function can be used for a denial of service attack since any user can execute it. This commit avoids bloating the cache by not adding negative entries. Reported by: Ashutosh Bapat Author: Ashutosh Bapat --- src/backend/utils/cache/relfilenumbermap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/utils/cache/relfilenumbermap.c b/src/backend/utils/cache/relfilenumbermap.c index 14c30276e24..f12f79694ad 100644 --- a/src/backend/utils/cache/relfilenumbermap.c +++ b/src/backend/utils/cache/relfilenumbermap.c @@ -60,13 +60,15 @@ RelfilenumberMapInvalidateCallback(Datum arg, Oid relid) hash_seq_init(&status, RelfilenumberMapHash); while ((entry = (RelfilenumberMapEntry *) hash_seq_search(&status)) != NULL) { + /* Negative cache entries are not expected. */ + Assert(OidIsValid(entry->relid)); + /* * If relid is InvalidOid, signaling a complete reset, we must remove * all entries, otherwise just remove the specific relation's entry. * Always remove negative cache entries. */ if (relid == InvalidOid || /* complete reset */ - entry->relid == InvalidOid || /* negative cache entry */ entry->relid == relid) /* individual flushed relation */ { if (hash_search(RelfilenumberMapHash, @@ -175,7 +177,11 @@ RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber) entry = hash_search(RelfilenumberMapHash, &key, HASH_FIND, &found); if (found) + { + /* Negative cache entries are not expected. */ + Assert(OidIsValid(entry->relid)); return entry->relid; + } /* ok, no previous cache entry, do it the hard way */ @@ -241,6 +247,10 @@ RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber) relid = RelationMapFilenumberToOid(relfilenumber, false); } + /* Avoid bloating cache with negative entries. */ + if (!OidIsValid(relid)) + return relid; + /* * Only enter entry into cache now, our opening of pg_class could have * caused cache invalidations to be executed which would have deleted a -- 2.34.1