mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Do stack-depth checking in all postmaster children.
We used to only initialize the stack base pointer when starting up a regular backend, not in other processes. In particular, autovacuum workers can run arbitrary user code, and without stack-depth checking, infinite recursion in e.g an index expression will bring down the whole cluster. The comment about PL/Java using set_stack_base() is not yet true. As the code stands, PL/java still modifies the stack_base_ptr variable directly. However, it's been discussed in the PL/Java mailing list that it should be changed to use the function, because PL/Java is currently oblivious to the register stack used on Itanium. There's another issues with PL/Java, namely that the stack base pointer it sets is not really the base of the stack, it could be something close to the bottom of the stack. That's a separate issue that might need some further changes to this code, but that's a different story. Backpatch to all supported releases.
This commit is contained in:
@ -970,6 +970,11 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
set_max_safe_fds();
|
set_max_safe_fds();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set reference point for stack-depth checking.
|
||||||
|
*/
|
||||||
|
set_stack_base();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the list of active backends.
|
* Initialize the list of active backends.
|
||||||
*/
|
*/
|
||||||
@ -3990,6 +3995,11 @@ SubPostmasterMain(int argc, char *argv[])
|
|||||||
memset(&port, 0, sizeof(Port));
|
memset(&port, 0, sizeof(Port));
|
||||||
read_backend_variables(argv[2], &port);
|
read_backend_variables(argv[2], &port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set reference point for stack-depth checking
|
||||||
|
*/
|
||||||
|
set_stack_base();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up memory area for GSS information. Mirrors the code in ConnCreate
|
* Set up memory area for GSS information. Mirrors the code in ConnCreate
|
||||||
* for the non-exec case.
|
* for the non-exec case.
|
||||||
|
@ -114,8 +114,10 @@ int PostAuthDelay = 0;
|
|||||||
static long max_stack_depth_bytes = 100 * 1024L;
|
static long max_stack_depth_bytes = 100 * 1024L;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack base pointer -- initialized by PostgresMain. This is not static
|
* Stack base pointer -- initialized by PostmasterMain and inherited by
|
||||||
* so that PL/Java can modify it.
|
* subprocesses. This is not static because old versions of PL/Java modify
|
||||||
|
* it directly. Newer versions use set_stack_base(), but we want to stay
|
||||||
|
* binary-compatible for the time being.
|
||||||
*/
|
*/
|
||||||
char *stack_base_ptr = NULL;
|
char *stack_base_ptr = NULL;
|
||||||
|
|
||||||
@ -3002,6 +3004,53 @@ ia64_get_bsp(void)
|
|||||||
#endif /* IA64 */
|
#endif /* IA64 */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set_stack_base: set up reference point for stack depth checking
|
||||||
|
*
|
||||||
|
* Returns the old reference point, if any.
|
||||||
|
*/
|
||||||
|
pg_stack_base_t
|
||||||
|
set_stack_base(void)
|
||||||
|
{
|
||||||
|
char stack_base;
|
||||||
|
pg_stack_base_t old;
|
||||||
|
|
||||||
|
#if defined(__ia64__) || defined(__ia64)
|
||||||
|
old.stack_base_ptr = stack_base_ptr;
|
||||||
|
old.register_stack_base_ptr = register_stack_base_ptr;
|
||||||
|
#else
|
||||||
|
old = stack_base_ptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set up reference point for stack depth checking */
|
||||||
|
stack_base_ptr = &stack_base;
|
||||||
|
#if defined(__ia64__) || defined(__ia64)
|
||||||
|
register_stack_base_ptr = ia64_get_bsp();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* restore_stack_base: restore reference point for stack depth checking
|
||||||
|
*
|
||||||
|
* This can be used after set_stack_base() to restore the old value. This
|
||||||
|
* is currently only used in PL/Java. When PL/Java calls a backend function
|
||||||
|
* from different thread, the thread's stack is at a different location than
|
||||||
|
* the main thread's stack, so it sets the base pointer before the call, and
|
||||||
|
* restores it afterwards.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
restore_stack_base(pg_stack_base_t base)
|
||||||
|
{
|
||||||
|
#if defined(__ia64__) || defined(__ia64)
|
||||||
|
stack_base_ptr = base.stack_base_ptr;
|
||||||
|
register_stack_base_ptr = base.register_stack_base_ptr;
|
||||||
|
#else
|
||||||
|
stack_base_ptr = base;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check_stack_depth: check for excessively deep recursion
|
* check_stack_depth: check for excessively deep recursion
|
||||||
*
|
*
|
||||||
@ -3017,7 +3066,7 @@ check_stack_depth(void)
|
|||||||
long stack_depth;
|
long stack_depth;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute distance from PostgresMain's local variables to my own
|
* Compute distance from reference point to to my local variables
|
||||||
*/
|
*/
|
||||||
stack_depth = (long) (stack_base_ptr - &stack_top_loc);
|
stack_depth = (long) (stack_base_ptr - &stack_top_loc);
|
||||||
|
|
||||||
@ -3459,7 +3508,6 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
{
|
{
|
||||||
const char *dbname;
|
const char *dbname;
|
||||||
int firstchar;
|
int firstchar;
|
||||||
char stack_base;
|
|
||||||
StringInfoData input_message;
|
StringInfoData input_message;
|
||||||
sigjmp_buf local_sigjmp_buf;
|
sigjmp_buf local_sigjmp_buf;
|
||||||
volatile bool send_ready_for_query = true;
|
volatile bool send_ready_for_query = true;
|
||||||
@ -3486,10 +3534,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
SetProcessingMode(InitProcessing);
|
SetProcessingMode(InitProcessing);
|
||||||
|
|
||||||
/* Set up reference point for stack depth checking */
|
/* Set up reference point for stack depth checking */
|
||||||
stack_base_ptr = &stack_base;
|
set_stack_base();
|
||||||
#if defined(__ia64__) || defined(__ia64)
|
|
||||||
register_stack_base_ptr = ia64_get_bsp();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Compute paths, if we didn't inherit them from postmaster */
|
/* Compute paths, if we didn't inherit them from postmaster */
|
||||||
if (my_exec_path[0] == '\0')
|
if (my_exec_path[0] == '\0')
|
||||||
|
@ -235,6 +235,19 @@ extern bool VacuumCostActive;
|
|||||||
|
|
||||||
|
|
||||||
/* in tcop/postgres.c */
|
/* in tcop/postgres.c */
|
||||||
|
|
||||||
|
#if defined(__ia64__) || defined(__ia64)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *stack_base_ptr;
|
||||||
|
char *register_stack_base_ptr;
|
||||||
|
} pg_stack_base_t;
|
||||||
|
#else
|
||||||
|
typedef char *pg_stack_base_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern pg_stack_base_t set_stack_base(void);
|
||||||
|
extern void restore_stack_base(pg_stack_base_t base);
|
||||||
extern void check_stack_depth(void);
|
extern void check_stack_depth(void);
|
||||||
|
|
||||||
/* in tcop/utility.c */
|
/* in tcop/utility.c */
|
||||||
|
Reference in New Issue
Block a user