!1 CVE-2020-21469 安全更新:In-the-postmaster-rely-on-the-signal-infrastructure

Merge pull request !1 from 吴诚/openkylin/yangtze
This commit is contained in:
赵玉彪 2023-12-29 08:57:43 +00:00 committed by Gitee
commit aafdb4ff4f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 116 additions and 57 deletions

View File

@ -95,3 +95,52 @@ pqinitmask(void)
sigdelset(&StartupBlockSig, SIGALRM); sigdelset(&StartupBlockSig, SIGALRM);
#endif #endif
} }
/*
* Set up a postmaster signal handler for signal "signo"
*
* Returns the previous handler.
*
* This is used only in the postmaster, which has its own odd approach to
* signal handling. For signals with handlers, we block all signals for the
* duration of signal handler execution. We also do not set the SA_RESTART
* flag; this should be safe given the tiny range of code in which the
* postmaster ever unblocks signals.
*
* pqinitmask() must have been invoked previously.
*
* On Windows, this function is just an alias for pqsignal()
* (and note that it's calling the code in src/backend/port/win32/signal.c,
* not src/port/pqsignal.c). On that platform, the postmaster's signal
* handlers still have to block signals for themselves.
*/
pqsigfunc
pqsignal_pm(int signo, pqsigfunc func)
{
#ifndef WIN32
struct sigaction act,
oact;
act.sa_handler = func;
if (func == SIG_IGN || func == SIG_DFL)
{
/* in these cases, act the same as pqsignal() */
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
}
else
{
act.sa_mask = BlockSig;
act.sa_flags = 0;
}
#ifdef SA_NOCLDSTOP
if (signo == SIGCHLD)
act.sa_flags |= SA_NOCLDSTOP;
#endif
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
#else /* WIN32 */
return pqsignal(signo, func);
#endif
}

View File

@ -606,14 +606,25 @@ PostmasterMain(int argc, char *argv[])
/* /*
* Set up signal handlers for the postmaster process. * Set up signal handlers for the postmaster process.
* *
* In the postmaster, we want to install non-ignored handlers *without* * In the postmaster, we use pqsignal_pm() rather than pqsignal() (which
* SA_RESTART. This is because they'll be blocked at all times except * is used by all child processes and client processes). That has a
* when ServerLoop is waiting for something to happen, and during that * couple of special behaviors:
* window, we want signals to exit the select(2) wait so that ServerLoop *
* can respond if anything interesting happened. On some platforms, * 1. Except on Windows, we tell sigaction() to block all signals for the
* signals marked SA_RESTART would not cause the select() wait to end. * duration of the signal handler. This is faster than our old approach
* Child processes will generally want SA_RESTART, but we expect them to * of blocking/unblocking explicitly in the signal handler, and it should
* set up their own handlers before unblocking signals. * also prevent excessive stack consumption if signals arrive quickly.
*
* 2. We do not set the SA_RESTART flag. This is because signals will be
* blocked at all times except when ServerLoop is waiting for something to
* happen, and during that window, we want signals to exit the select(2)
* wait so that ServerLoop can respond if anything interesting happened.
* On some platforms, signals marked SA_RESTART would not cause the
* select() wait to end.
*
* Child processes will generally want SA_RESTART, so pqsignal() sets that
* flag. We expect children to set up their own handlers before
* unblocking signals.
* *
* CAUTION: when changing this list, check for side-effects on the signal * CAUTION: when changing this list, check for side-effects on the signal
* handling setup of child processes. See tcop/postgres.c, * handling setup of child processes. See tcop/postgres.c,
@ -625,18 +636,16 @@ PostmasterMain(int argc, char *argv[])
pqinitmask(); pqinitmask();
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
pqsignal_no_restart(SIGHUP, SIGHUP_handler); /* reread config file and pqsignal_pm(SIGHUP, SIGHUP_handler); /* reread config file and have
* have children do same */ * children do same */
pqsignal_no_restart(SIGINT, pmdie); /* send SIGTERM and shut down */ pqsignal_pm(SIGINT, pmdie); /* send SIGTERM and shut down */
pqsignal_no_restart(SIGQUIT, pmdie); /* send SIGQUIT and die */ pqsignal_pm(SIGQUIT, pmdie); /* send SIGQUIT and die */
pqsignal_no_restart(SIGTERM, pmdie); /* wait for children and shut down */ pqsignal_pm(SIGTERM, pmdie); /* wait for children and shut down */
pqsignal(SIGALRM, SIG_IGN); /* ignored */ pqsignal_pm(SIGALRM, SIG_IGN); /* ignored */
pqsignal(SIGPIPE, SIG_IGN); /* ignored */ pqsignal_pm(SIGPIPE, SIG_IGN); /* ignored */
pqsignal_no_restart(SIGUSR1, sigusr1_handler); /* message from child pqsignal_pm(SIGUSR1, sigusr1_handler); /* message from child process */
* process */ pqsignal_pm(SIGUSR2, dummy_handler); /* unused, reserve for children */
pqsignal_no_restart(SIGUSR2, dummy_handler); /* unused, reserve for pqsignal_pm(SIGCHLD, reaper); /* handle child termination */
* children */
pqsignal_no_restart(SIGCHLD, reaper); /* handle child termination */
/* /*
* No other place in Postgres should touch SIGTTIN/SIGTTOU handling. We * No other place in Postgres should touch SIGTTIN/SIGTTOU handling. We
@ -646,15 +655,15 @@ PostmasterMain(int argc, char *argv[])
* child processes should just allow the inherited settings to stand. * child processes should just allow the inherited settings to stand.
*/ */
#ifdef SIGTTIN #ifdef SIGTTIN
pqsignal(SIGTTIN, SIG_IGN); /* ignored */ pqsignal_pm(SIGTTIN, SIG_IGN); /* ignored */
#endif #endif
#ifdef SIGTTOU #ifdef SIGTTOU
pqsignal(SIGTTOU, SIG_IGN); /* ignored */ pqsignal_pm(SIGTTOU, SIG_IGN); /* ignored */
#endif #endif
/* ignore SIGXFSZ, so that ulimit violations work like disk full */ /* ignore SIGXFSZ, so that ulimit violations work like disk full */
#ifdef SIGXFSZ #ifdef SIGXFSZ
pqsignal(SIGXFSZ, SIG_IGN); /* ignored */ pqsignal_pm(SIGXFSZ, SIG_IGN); /* ignored */
#endif #endif
/* /*
@ -2627,7 +2636,13 @@ SIGHUP_handler(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
/*
* We rely on the signal mechanism to have blocked all signals ... except
* on Windows, which lacks sigaction(), so we have to do it manually.
*/
#ifdef WIN32
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
#endif
if (Shutdown <= SmartShutdown) if (Shutdown <= SmartShutdown)
{ {
@ -2687,7 +2702,9 @@ SIGHUP_handler(SIGNAL_ARGS)
#endif #endif
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -2701,7 +2718,13 @@ pmdie(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
/*
* We rely on the signal mechanism to have blocked all signals ... except
* on Windows, which lacks sigaction(), so we have to do it manually.
*/
#ifdef WIN32
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
#endif
ereport(DEBUG2, ereport(DEBUG2,
(errmsg_internal("postmaster received signal %d", (errmsg_internal("postmaster received signal %d",
@ -2867,7 +2890,9 @@ pmdie(SIGNAL_ARGS)
break; break;
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -2882,7 +2907,13 @@ reaper(SIGNAL_ARGS)
int pid; /* process id of dead child process */ int pid; /* process id of dead child process */
int exitstatus; /* its exit status */ int exitstatus; /* its exit status */
/*
* We rely on the signal mechanism to have blocked all signals ... except
* on Windows, which lacks sigaction(), so we have to do it manually.
*/
#ifdef WIN32
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
#endif
ereport(DEBUG4, ereport(DEBUG4,
(errmsg_internal("reaping dead processes"))); (errmsg_internal("reaping dead processes")));
@ -3184,7 +3215,9 @@ reaper(SIGNAL_ARGS)
PostmasterStateMachine(); PostmasterStateMachine();
/* Done with signal handler */ /* Done with signal handler */
#ifdef WIN32
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }
@ -5086,7 +5119,13 @@ sigusr1_handler(SIGNAL_ARGS)
{ {
int save_errno = errno; int save_errno = errno;
/*
* We rely on the signal mechanism to have blocked all signals ... except
* on Windows, which lacks sigaction(), so we have to do it manually.
*/
#ifdef WIN32
PG_SETMASK(&BlockSig); PG_SETMASK(&BlockSig);
#endif
/* Process background worker state change. */ /* Process background worker state change. */
if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE)) if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE))
@ -5244,7 +5283,9 @@ sigusr1_handler(SIGNAL_ARGS)
signal_child(StartupPID, SIGUSR2); signal_child(StartupPID, SIGUSR2);
} }
#ifdef WIN32
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
#endif
errno = save_errno; errno = save_errno;
} }

View File

@ -36,4 +36,7 @@ extern sigset_t UnBlockSig,
extern void pqinitmask(void); extern void pqinitmask(void);
/* pqsigfunc is declared in src/include/port.h */
extern pqsigfunc pqsignal_pm(int signo, pqsigfunc func);
#endif /* PQSIGNAL_H */ #endif /* PQSIGNAL_H */

View File

@ -524,11 +524,6 @@ extern int pg_mkdir_p(char *path, int omode);
/* port/pqsignal.c */ /* port/pqsignal.c */
typedef void (*pqsigfunc) (int signo); typedef void (*pqsigfunc) (int signo);
extern pqsigfunc pqsignal(int signo, pqsigfunc func); extern pqsigfunc pqsignal(int signo, pqsigfunc func);
#ifndef WIN32
extern pqsigfunc pqsignal_no_restart(int signo, pqsigfunc func);
#else
#define pqsignal_no_restart(signo, func) pqsignal(signo, func)
#endif
/* port/quotes.c */ /* port/quotes.c */
extern char *escape_single_quotes_ascii(const char *src); extern char *escape_single_quotes_ascii(const char *src);

View File

@ -58,33 +58,4 @@ pqsignal(int signo, pqsigfunc func)
#endif #endif
} }
/*
* Set up a signal handler, without SA_RESTART, for signal "signo"
*
* Returns the previous handler.
*
* On Windows, this would be identical to pqsignal(), so don't bother.
*/
#ifndef WIN32
pqsigfunc
pqsignal_no_restart(int signo, pqsigfunc func)
{
struct sigaction act,
oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_NOCLDSTOP
if (signo == SIGCHLD)
act.sa_flags |= SA_NOCLDSTOP;
#endif
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
}
#endif /* !WIN32 */
#endif /* !defined(WIN32) || defined(FRONTEND) */ #endif /* !defined(WIN32) || defined(FRONTEND) */