PG-325: Fix deadlock.

If a query exceeds pg_stat_monitor.pgsm_query_max_len, then it's
truncated before we save it into the query buffer (SaveQueryText).

When reading the query back, on pg_stat_monitor_internal, we allocate a
buffer for the query with length = pg_stat_monitor.pgsm_query_max_len,
the problem is that the read_query function adds a '\0' to the end of
the buffer when reading a query, thus if a query has been truncated, for
example, to 1024, when reading it back read_query will store the '\0' at
the position 1025, an out of array bounds position.

Then, when we call pfree to release the buffer, PostgreSQL notices the
buffer overrun and triggers an error assertion, the assertion calls our
error hook which attempts to acquire the shared pgss->lock before
pg_stat_monitor_internal has released it, leading to a deadlock.

To avoid the problem we add 1 more byte to the extra '\0' during palloc
call for query_text and parent_query_text.

Also, we release the lock before calling pfree, just in case PostgreSQL
finds a problem in pfree we won't deadlock again and get the error
reported correctly.
pull/184/head
Diego Fronza 2022-01-12 17:02:08 -03:00 committed by Hamid Akhtar
parent 24ae3fa66f
commit 9f8f94ed9c
1 changed files with 5 additions and 4 deletions

View File

@ -1701,8 +1701,8 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
char parentid_txt[32];
pgssSharedState *pgss = pgsm_get_ss();
HTAB *pgss_hash = pgsm_get_hash();
char *query_txt = (char*) palloc0(PGSM_QUERY_MAX_LEN);
char *parent_query_txt = (char*) palloc0(PGSM_QUERY_MAX_LEN);
char *query_txt = (char*) palloc0(PGSM_QUERY_MAX_LEN + 1);
char *parent_query_txt = (char*) palloc0(PGSM_QUERY_MAX_LEN + 1);
/* Safety check... */
if (!IsSystemInitialized())
@ -2048,11 +2048,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
values[i++] = BoolGetDatum(toplevel);
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
pfree(query_txt);
pfree(parent_query_txt);
/* clean up and return the tuplestore */
LWLockRelease(pgss->lock);
pfree(query_txt);
pfree(parent_query_txt);
tuplestore_donestoring(tupstore);
}