mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Clean up some lack-of-STRICT issues in the core code, too.
A scan for missed proisstrict markings in the core code turned up these functions: brin_summarize_new_values pg_stat_reset_single_table_counters pg_stat_reset_single_function_counters pg_create_logical_replication_slot pg_create_physical_replication_slot pg_drop_replication_slot The first three of these take OID, so a null argument will normally look like a zero to them, resulting in "ERROR: could not open relation with OID 0" for brin_summarize_new_values, and no action for the pg_stat_reset_XXX functions. The other three will dump core on a null argument, though this is mitigated by the fact that they won't do so until after checking that the caller is superuser or has rolreplication privilege. In addition, the pg_logical_slot_get/peek[_binary]_changes family was intentionally marked nonstrict, but failed to make nullness checks on all the arguments; so again a null-pointer-dereference crash is possible but only for superusers and rolreplication users. Add the missing ARGISNULL checks to the latter functions, and mark the former functions as strict in pg_proc. Make that change in the back branches too, even though we can't force initdb there, just so that installations initdb'd in future won't have the issue. Since none of these bugs rise to the level of security issues (and indeed the pg_stat_reset_XXX functions hardly misbehave at all), it seems sufficient to do this. In addition, fix some order-of-operations oddities in the slot_get_changes family, mostly cosmetic, but not the part that moves the function's last few operations into the PG_TRY block. As it stood, there was significant risk for an error to exit without clearing historical information from the system caches. The slot_get_changes bugs go back to 9.4 where that code was introduced. Back-patch appropriate subsets of the pg_proc changes into all active branches, as well.
This commit is contained in:
@@ -276,25 +276,31 @@ logical_read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
|
||||
static Datum
|
||||
pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool binary)
|
||||
{
|
||||
Name name = PG_GETARG_NAME(0);
|
||||
Name name;
|
||||
XLogRecPtr upto_lsn;
|
||||
int32 upto_nchanges;
|
||||
|
||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
MemoryContext per_query_ctx;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
XLogRecPtr end_of_wal;
|
||||
XLogRecPtr startptr;
|
||||
|
||||
LogicalDecodingContext *ctx;
|
||||
|
||||
ResourceOwner old_resowner = CurrentResourceOwner;
|
||||
ArrayType *arr;
|
||||
Size ndim;
|
||||
List *options = NIL;
|
||||
DecodingOutputState *p;
|
||||
|
||||
check_permissions();
|
||||
|
||||
CheckLogicalDecodingRequirements();
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("slot name must not be null")));
|
||||
name = PG_GETARG_NAME(0);
|
||||
|
||||
if (PG_ARGISNULL(1))
|
||||
upto_lsn = InvalidXLogRecPtr;
|
||||
else
|
||||
@@ -305,6 +311,12 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
else
|
||||
upto_nchanges = PG_GETARG_INT32(2);
|
||||
|
||||
if (PG_ARGISNULL(3))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
||||
errmsg("options array must not be null")));
|
||||
arr = PG_GETARG_ARRAYTYPE_P(3);
|
||||
|
||||
/* check to see if caller supports us returning a tuplestore */
|
||||
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
||||
ereport(ERROR,
|
||||
@@ -324,16 +336,11 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
if (get_call_result_type(fcinfo, NULL, &p->tupdesc) != TYPEFUNC_COMPOSITE)
|
||||
elog(ERROR, "return type must be a row type");
|
||||
|
||||
check_permissions();
|
||||
|
||||
CheckLogicalDecodingRequirements();
|
||||
|
||||
arr = PG_GETARG_ARRAYTYPE_P(3);
|
||||
ndim = ARR_NDIM(arr);
|
||||
|
||||
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||
|
||||
/* Deconstruct options array */
|
||||
ndim = ARR_NDIM(arr);
|
||||
if (ndim > 1)
|
||||
{
|
||||
ereport(ERROR,
|
||||
@@ -382,7 +389,6 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
else
|
||||
end_of_wal = GetXLogReplayRecPtr(NULL);
|
||||
|
||||
CheckLogicalDecodingRequirements();
|
||||
ReplicationSlotAcquire(NameStr(*name));
|
||||
|
||||
PG_TRY();
|
||||
@@ -444,6 +450,23 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
break;
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
}
|
||||
|
||||
tuplestore_donestoring(tupstore);
|
||||
|
||||
CurrentResourceOwner = old_resowner;
|
||||
|
||||
/*
|
||||
* Next time, start where we left off. (Hunting things, the family
|
||||
* business..)
|
||||
*/
|
||||
if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
|
||||
LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
|
||||
|
||||
/* free context, call shutdown callback */
|
||||
FreeDecodingContext(ctx);
|
||||
|
||||
ReplicationSlotRelease();
|
||||
InvalidateSystemCaches();
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
@@ -454,23 +477,6 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
}
|
||||
PG_END_TRY();
|
||||
|
||||
tuplestore_donestoring(tupstore);
|
||||
|
||||
CurrentResourceOwner = old_resowner;
|
||||
|
||||
/*
|
||||
* Next time, start where we left off. (Hunting things, the family
|
||||
* business..)
|
||||
*/
|
||||
if (ctx->reader->EndRecPtr != InvalidXLogRecPtr && confirm)
|
||||
LogicalConfirmReceivedLocation(ctx->reader->EndRecPtr);
|
||||
|
||||
/* free context, call shutdown callback */
|
||||
FreeDecodingContext(ctx);
|
||||
|
||||
ReplicationSlotRelease();
|
||||
InvalidateSystemCaches();
|
||||
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
@@ -480,9 +486,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
Datum
|
||||
pg_logical_slot_get_changes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum ret = pg_logical_slot_get_changes_guts(fcinfo, true, false);
|
||||
|
||||
return ret;
|
||||
return pg_logical_slot_get_changes_guts(fcinfo, true, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -491,9 +495,7 @@ pg_logical_slot_get_changes(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_logical_slot_peek_changes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum ret = pg_logical_slot_get_changes_guts(fcinfo, false, false);
|
||||
|
||||
return ret;
|
||||
return pg_logical_slot_get_changes_guts(fcinfo, false, false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -502,9 +504,7 @@ pg_logical_slot_peek_changes(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_logical_slot_get_binary_changes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum ret = pg_logical_slot_get_changes_guts(fcinfo, true, true);
|
||||
|
||||
return ret;
|
||||
return pg_logical_slot_get_changes_guts(fcinfo, true, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -513,7 +513,5 @@ pg_logical_slot_get_binary_changes(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_logical_slot_peek_binary_changes(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum ret = pg_logical_slot_get_changes_guts(fcinfo, false, true);
|
||||
|
||||
return ret;
|
||||
return pg_logical_slot_get_changes_guts(fcinfo, false, true);
|
||||
}
|
||||
|
Reference in New Issue
Block a user