Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 35b7601

Browse files
committed
Add an overall timeout on the client authentication cycle, so that
a hung client or lost connection can't indefinitely block a postmaster child (not to mention the possibility of deliberate DoS attacks). Timeout is controlled by new authentication_timeout GUC variable, which I set to 60 seconds by default ... does that seem reasonable?
1 parent e3f5bc3 commit 35b7601

File tree

8 files changed

+136
-63
lines changed

8 files changed

+136
-63
lines changed

doc/src/sgml/runtime.sgml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.82 2001/09/21 03:32:35 tgl Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.83 2001/09/21 17:06:12 tgl Exp $
33
-->
44

55
<Chapter Id="runtime">
@@ -1018,6 +1018,20 @@ env PGOPTIONS='-c geqo=off' psql
10181018
</listitem>
10191019
</varlistentry>
10201020

1021+
<varlistentry>
1022+
<term><varname>AUTHENTICATION_TIMEOUT</varname> (<type>integer</type>)</term>
1023+
<listitem>
1024+
<para>
1025+
Maximum time to complete client authentication, in seconds.
1026+
If a would-be client has not completed the authentication protocol
1027+
in this much time, the server unceremoniously breaks the connection.
1028+
This prevents hung clients from occupying a connection indefinitely.
1029+
This option can only be set at server start or in the
1030+
<filename>postgresql.conf</filename> file.
1031+
</para>
1032+
</listitem>
1033+
</varlistentry>
1034+
10211035
<varlistentry>
10221036
<indexterm>
10231037
<primary>deadlock</primary>

src/backend/libpq/pqsignal.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.23 2001/09/08 01:10:20 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.24 2001/09/21 17:06:12 tgl Exp $
1313
*
1414
* NOTES
1515
* This shouldn't be in libpq, but the monitor and some other
@@ -53,7 +53,7 @@
5353
* signals that should never be turned off.
5454
*
5555
* AuthBlockSig is the set of signals to block during authentication;
56-
* it's essentially BlockSig minus SIGTERM and SIGQUIT.
56+
* it's essentially BlockSig minus SIGTERM, SIGQUIT, SIGALRM.
5757
*
5858
* UnBlockSig is the set of signals to block when we don't want to block
5959
* signals (is this ever nonzero??)
@@ -109,14 +109,17 @@ pqinitmask(void)
109109
#ifdef SIGQUIT
110110
sigdelset(&AuthBlockSig, SIGQUIT);
111111
#endif
112+
#ifdef SIGALRM
113+
sigdelset(&AuthBlockSig, SIGALRM);
114+
#endif
112115
#else
113116
UnBlockSig = 0;
114117
BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
115118
sigmask(SIGTERM) | sigmask(SIGALRM) |
116119
sigmask(SIGINT) | sigmask(SIGUSR1) |
117120
sigmask(SIGUSR2) | sigmask(SIGCHLD) |
118121
sigmask(SIGWINCH) | sigmask(SIGFPE);
119-
AuthBlockSig = sigmask(SIGHUP) | sigmask(SIGALRM) |
122+
AuthBlockSig = sigmask(SIGHUP) |
120123
sigmask(SIGINT) | sigmask(SIGUSR1) |
121124
sigmask(SIGUSR2) | sigmask(SIGCHLD) |
122125
sigmask(SIGWINCH) | sigmask(SIGFPE);

src/backend/postmaster/postmaster.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*
3838
*
3939
* IDENTIFICATION
40-
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.241 2001/09/08 01:10:20 tgl Exp $
40+
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.242 2001/09/21 17:06:12 tgl Exp $
4141
*
4242
* NOTES
4343
*
@@ -190,6 +190,8 @@ bool NetServer = false; /* listen on TCP/IP */
190190
bool EnableSSL = false;
191191
bool SilentMode = false; /* silent mode (-S) */
192192

193+
int PreAuthDelay = 0;
194+
int AuthenticationTimeout = 60;
193195
int CheckPointTimeout = 300;
194196

195197
/* Startup/shutdown state */
@@ -1941,16 +1943,38 @@ DoBackend(Port *port)
19411943
/* Reset MyProcPid to new backend's pid */
19421944
MyProcPid = getpid();
19431945

1946+
/*
1947+
* Initialize libpq and enable reporting of elog errors to the client.
1948+
* Must do this now because authentication uses libpq to send messages.
1949+
*/
1950+
pq_init(); /* initialize libpq to talk to client */
1951+
whereToSendOutput = Remote; /* now safe to elog to client */
1952+
19441953
/*
19451954
* We arrange for a simple exit(0) if we receive SIGTERM or SIGQUIT
19461955
* during any client authentication related communication. Otherwise
19471956
* the postmaster cannot shutdown the database FAST or IMMED cleanly
1948-
* if a buggy client blocks a backend during authentication.
1957+
* if a buggy client blocks a backend during authentication. We also
1958+
* will exit(0) after a time delay, so that a broken client can't hog
1959+
* a connection indefinitely.
1960+
*
1961+
* PreAuthDelay is a debugging aid for investigating problems in the
1962+
* authentication cycle: it can be set in postgresql.conf to allow
1963+
* time to attach to the newly-forked backend with a debugger.
1964+
* (See also the -W backend switch, which we allow clients to pass
1965+
* through PGOPTIONS, but it is not honored until after authentication.)
19491966
*/
19501967
pqsignal(SIGTERM, authdie);
19511968
pqsignal(SIGQUIT, authdie);
1969+
pqsignal(SIGALRM, authdie);
19521970
PG_SETMASK(&AuthBlockSig);
19531971

1972+
if (PreAuthDelay > 0)
1973+
sleep(PreAuthDelay);
1974+
1975+
if (! enable_sigalrm_interrupt(AuthenticationTimeout * 1000))
1976+
elog(FATAL, "DoBackend: Unable to set timer for auth timeout");
1977+
19541978
/*
19551979
* Receive the startup packet (which might turn out to be a cancel
19561980
* request packet); then perform client authentication.
@@ -1963,9 +1987,11 @@ DoBackend(Port *port)
19631987
ClientAuthentication(MyProcPort); /* might not return, if failure */
19641988

19651989
/*
1966-
* Done with authentication. Prevent SIGTERM/SIGQUIT again until
1967-
* backend startup is complete.
1990+
* Done with authentication. Disable timeout, and prevent SIGTERM/SIGQUIT
1991+
* again until backend startup is complete.
19681992
*/
1993+
if (! disable_sigalrm_interrupt())
1994+
elog(FATAL, "DoBackend: Unable to disable timer for auth timeout");
19691995
PG_SETMASK(&BlockSig);
19701996

19711997
/*

src/backend/storage/lmgr/proc.c

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.107 2001/09/07 00:27:29 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.108 2001/09/21 17:06:12 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -327,18 +327,7 @@ LockWaitCancel(void)
327327
waitingForLock = false;
328328

329329
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
330-
#ifndef __BEOS__
331-
{
332-
struct itimerval timeval,
333-
dummy;
334-
335-
MemSet(&timeval, 0, sizeof(struct itimerval));
336-
setitimer(ITIMER_REAL, &timeval, &dummy);
337-
}
338-
#else
339-
/* BeOS doesn't have setitimer, but has set_alarm */
340-
set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM);
341-
#endif /* __BEOS__ */
330+
disable_sigalrm_interrupt();
342331

343332
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
344333
LockLockTable();
@@ -501,12 +490,6 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
501490
bool early_deadlock = false;
502491
PROC *proc;
503492
int i;
504-
#ifndef __BEOS__
505-
struct itimerval timeval,
506-
dummy;
507-
#else
508-
bigtime_t time_interval;
509-
#endif
510493

511494
/*
512495
* Determine where to add myself in the wait queue.
@@ -629,21 +612,9 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
629612
*
630613
* By delaying the check until we've waited for a bit, we can avoid
631614
* running the rather expensive deadlock-check code in most cases.
632-
*
633-
* Need to zero out struct to set the interval and the microseconds
634-
* fields to 0.
635615
*/
636-
#ifndef __BEOS__
637-
MemSet(&timeval, 0, sizeof(struct itimerval));
638-
timeval.it_value.tv_sec = DeadlockTimeout / 1000;
639-
timeval.it_value.tv_usec = (DeadlockTimeout % 1000) * 1000;
640-
if (setitimer(ITIMER_REAL, &timeval, &dummy))
616+
if (! enable_sigalrm_interrupt(DeadlockTimeout))
641617
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
642-
#else
643-
time_interval = DeadlockTimeout * 1000000; /* usecs */
644-
if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
645-
elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
646-
#endif
647618

648619
/*
649620
* If someone wakes us between SpinRelease and IpcSemaphoreLock,
@@ -664,14 +635,8 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
664635
/*
665636
* Disable the timer, if it's still running
666637
*/
667-
#ifndef __BEOS__
668-
MemSet(&timeval, 0, sizeof(struct itimerval));
669-
if (setitimer(ITIMER_REAL, &timeval, &dummy))
670-
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
671-
#else
672-
if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
638+
if (! disable_sigalrm_interrupt())
673639
elog(FATAL, "ProcSleep: Unable to disable timer for process wakeup");
674-
#endif
675640

676641
/*
677642
* Now there is nothing for LockWaitCancel to do.
@@ -949,6 +914,69 @@ ProcSendSignal(BackendId procId)
949914
}
950915

951916

917+
/*****************************************************************************
918+
* SIGALRM interrupt support
919+
*
920+
* Maybe these should be in pqsignal.c?
921+
*****************************************************************************/
922+
923+
/*
924+
* Enable the SIGALRM interrupt to fire after the specified delay
925+
*
926+
* Delay is given in milliseconds. Caller should be sure a SIGALRM
927+
* signal handler is installed before this is called.
928+
*
929+
* Returns TRUE if okay, FALSE on failure.
930+
*/
931+
bool
932+
enable_sigalrm_interrupt(int delayms)
933+
{
934+
#ifndef __BEOS__
935+
struct itimerval timeval,
936+
dummy;
937+
938+
MemSet(&timeval, 0, sizeof(struct itimerval));
939+
timeval.it_value.tv_sec = delayms / 1000;
940+
timeval.it_value.tv_usec = (delayms % 1000) * 1000;
941+
if (setitimer(ITIMER_REAL, &timeval, &dummy))
942+
return false;
943+
#else
944+
/* BeOS doesn't have setitimer, but has set_alarm */
945+
bigtime_t time_interval;
946+
947+
time_interval = delayms * 1000; /* usecs */
948+
if (set_alarm(time_interval, B_ONE_SHOT_RELATIVE_ALARM) < 0)
949+
return false;
950+
#endif
951+
952+
return true;
953+
}
954+
955+
/*
956+
* Disable the SIGALRM interrupt, if it has not yet fired
957+
*
958+
* Returns TRUE if okay, FALSE on failure.
959+
*/
960+
bool
961+
disable_sigalrm_interrupt(void)
962+
{
963+
#ifndef __BEOS__
964+
struct itimerval timeval,
965+
dummy;
966+
967+
MemSet(&timeval, 0, sizeof(struct itimerval));
968+
if (setitimer(ITIMER_REAL, &timeval, &dummy))
969+
return false;
970+
#else
971+
/* BeOS doesn't have setitimer, but has set_alarm */
972+
if (set_alarm(B_INFINITE_TIMEOUT, B_PERIODIC_ALARM) < 0)
973+
return false;
974+
#endif
975+
976+
return true;
977+
}
978+
979+
952980
/*****************************************************************************
953981
*
954982
*****************************************************************************/

src/backend/tcop/postgres.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.232 2001/09/08 01:10:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.233 2001/09/21 17:06:12 tgl Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -967,12 +967,12 @@ die(SIGNAL_ARGS)
967967
}
968968

969969
/*
970-
* Shutdown signal from postmaster during client authentication.
970+
* Timeout or shutdown signal from postmaster during client authentication.
971971
* Simply exit(0).
972972
*
973973
* XXX: possible future improvement: try to send a message indicating
974974
* why we are disconnecting. Problem is to be sure we don't block while
975-
* doing so nor mess up the authentication message exchange.
975+
* doing so, nor mess up the authentication message exchange.
976976
*/
977977
void
978978
authdie(SIGNAL_ARGS)
@@ -1168,16 +1168,6 @@ PostgresMain(int argc, char *argv[],
11681168

11691169
SetProcessingMode(InitProcessing);
11701170

1171-
/*
1172-
* If under postmaster, initialize libpq and enable reporting of
1173-
* elog errors to the client.
1174-
*/
1175-
if (IsUnderPostmaster)
1176-
{
1177-
pq_init(); /* initialize libpq at backend startup */
1178-
whereToSendOutput = Remote; /* now safe to elog to client */
1179-
}
1180-
11811171
/*
11821172
* Set default values for command-line options.
11831173
*/
@@ -1736,7 +1726,7 @@ PostgresMain(int argc, char *argv[],
17361726
if (!IsUnderPostmaster)
17371727
{
17381728
puts("\nPOSTGRES backend interactive interface ");
1739-
puts("$Revision: 1.232 $ $Date: 2001/09/08 01:10:20 $\n");
1729+
puts("$Revision: 1.233 $ $Date: 2001/09/21 17:06:12 $\n");
17401730
}
17411731

17421732
/*

src/backend/utils/misc/guc.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Support for grand unified configuration scheme, including SET
55
* command, configuration file, and command line options.
66
*
7-
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.50 2001/09/21 03:32:35 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.51 2001/09/21 17:06:12 tgl Exp $
88
*
99
* Copyright 2000 by PostgreSQL Global Development Group
1010
* Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -41,6 +41,8 @@
4141

4242
/* XXX these should be in other modules' header files */
4343
extern bool Log_connections;
44+
extern int PreAuthDelay;
45+
extern int AuthenticationTimeout;
4446
extern int CheckPointTimeout;
4547
extern int CommitDelay;
4648
extern int CommitSiblings;
@@ -320,6 +322,12 @@ static struct config_int
320322
{"max_locks_per_transaction", PGC_POSTMASTER, &max_locks_per_xact,
321323
64, 10, INT_MAX, NULL, NULL},
322324

325+
{"authentication_timeout", PGC_SIGHUP, &AuthenticationTimeout,
326+
60, 1, 600, NULL, NULL},
327+
328+
{"pre_auth_delay", PGC_SIGHUP, &PreAuthDelay,
329+
0, 0, 60, NULL, NULL},
330+
323331
{"checkpoint_segments", PGC_SIGHUP, &CheckPointSegments,
324332
3, 1, INT_MAX, NULL, NULL},
325333

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
#
177177
#dynamic_library_path = '$libdir'
178178
#australian_timezones = false
179+
#authentication_timeout = 60 # min 1, max 600
179180
#deadlock_timeout = 1000
180181
#default_transaction_isolation = 'read committed'
181182
#max_expr_depth = 10000 # min 10

src/include/storage/proc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: proc.h,v 1.46 2001/09/07 00:27:30 tgl Exp $
10+
* $Id: proc.h,v 1.47 2001/09/21 17:06:12 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -154,4 +154,7 @@ extern void ProcWaitForSignal(void);
154154
extern void ProcCancelWaitForSignal(void);
155155
extern void ProcSendSignal(BackendId procId);
156156

157+
extern bool enable_sigalrm_interrupt(int delayms);
158+
extern bool disable_sigalrm_interrupt(void);
159+
157160
#endif /* PROC_H */

0 commit comments

Comments
 (0)