Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb5ebef7

Browse files
committed
Push enable/disable of notify and catchup interrupts all the way down
to just around the bare recv() call that gets a command from the client.The former placement in PostgresMain was unsafe because the intermediateprocessing layers (especially SSL) use facilities such as malloc that arenot necessarily re-entrant. Per report from counterstorm.com.
1 parent8dfb616 commitb5ebef7

File tree

3 files changed

+142
-24
lines changed

3 files changed

+142
-24
lines changed

‎src/backend/libpq/be-secure.c

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.56 2005/01/08 22:51:12 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.57 2005/06/02 21:03:17 tgl Exp $
1515
*
1616
* Since the server static private key ($DataDir/server.key)
1717
* will normally be stored unencrypted so that the database
@@ -79,7 +79,6 @@
7979
#include<sys/stat.h>
8080
#include<signal.h>
8181
#include<fcntl.h>
82-
#include<errno.h>
8382
#include<ctype.h>
8483
#include<sys/socket.h>
8584
#include<unistd.h>
@@ -97,6 +96,8 @@
9796

9897
#include"libpq/libpq.h"
9998
#include"miscadmin.h"
99+
#include"tcop/tcopprot.h"
100+
100101

101102
#ifdefUSE_SSL
102103
staticDH*load_dh_file(intkeylength);
@@ -308,8 +309,14 @@ secure_read(Port *port, void *ptr, size_t len)
308309
}
309310
else
310311
#endif
312+
{
313+
prepare_for_client_read();
314+
311315
n=recv(port->sock,ptr,len,0);
312316

317+
client_read_ended();
318+
}
319+
313320
returnn;
314321
}
315322

@@ -410,6 +417,73 @@ secure_write(Port *port, void *ptr, size_t len)
410417
/* SSL specific code*/
411418
/* ------------------------------------------------------------ */
412419
#ifdefUSE_SSL
420+
421+
/*
422+
* Private substitute BIO: this wraps the SSL library's standard socket BIO
423+
* so that we can enable and disable interrupts just while calling recv().
424+
* We cannot have interrupts occurring while the bulk of openssl runs,
425+
* because it uses malloc() and possibly other non-reentrant libc facilities.
426+
*
427+
* As of openssl 0.9.7, we can use the reasonably clean method of interposing
428+
* a wrapper around the standard socket BIO's sock_read() method. This relies
429+
* on the fact that sock_read() doesn't call anything non-reentrant, in fact
430+
* not much of anything at all except recv(). If this ever changes we'd
431+
* probably need to duplicate the code of sock_read() in order to push the
432+
* interrupt enable/disable down yet another level.
433+
*/
434+
435+
staticboolmy_bio_initialized= false;
436+
staticBIO_METHODmy_bio_methods;
437+
staticint (*std_sock_read) (BIO*h,char*buf,intsize);
438+
439+
staticint
440+
my_sock_read(BIO*h,char*buf,intsize)
441+
{
442+
intres;
443+
444+
prepare_for_client_read();
445+
446+
res=std_sock_read(h,buf,size);
447+
448+
client_read_ended();
449+
450+
returnres;
451+
}
452+
453+
staticBIO_METHOD*
454+
my_BIO_s_socket(void)
455+
{
456+
if (!my_bio_initialized)
457+
{
458+
memcpy(&my_bio_methods,BIO_s_socket(),sizeof(BIO_METHOD));
459+
std_sock_read=my_bio_methods.bread;
460+
my_bio_methods.bread=my_sock_read;
461+
my_bio_initialized= true;
462+
}
463+
return&my_bio_methods;
464+
}
465+
466+
/* This should exactly match openssl's SSL_set_fd except for using my BIO */
467+
staticint
468+
my_SSL_set_fd(SSL*s,intfd)
469+
{
470+
intret=0;
471+
BIO*bio=NULL;
472+
473+
bio=BIO_new(my_BIO_s_socket());
474+
475+
if (bio==NULL)
476+
{
477+
SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
478+
gotoerr;
479+
}
480+
BIO_set_fd(bio,fd,BIO_NOCLOSE);
481+
SSL_set_bio(s,bio,bio);
482+
ret=1;
483+
err:
484+
return(ret);
485+
}
486+
413487
/*
414488
*Load precomputed DH parameters.
415489
*
@@ -761,7 +835,7 @@ open_server_SSL(Port *port)
761835
close_SSL(port);
762836
return-1;
763837
}
764-
if (!SSL_set_fd(port->ssl,port->sock))
838+
if (!my_SSL_set_fd(port->ssl,port->sock))
765839
{
766840
ereport(COMMERROR,
767841
(errcode(ERRCODE_PROTOCOL_VIOLATION),

‎src/backend/tcop/postgres.c

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.445 2005/06/01 23:27:03 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.446 2005/06/02 21:03:24 tgl Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -111,6 +111,13 @@ static volatile sig_atomic_t got_SIGHUP = false;
111111
*/
112112
staticboolxact_started= false;
113113

114+
/*
115+
* Flag to indicate that we are doing the outer loop's read-from-client,
116+
* as opposed to any random read from client that might happen within
117+
* commands like COPY FROM STDIN.
118+
*/
119+
staticboolDoingCommandRead= false;
120+
114121
/*
115122
* Flags to implement skip-till-Sync-after-error behavior for messages of
116123
* the extended query protocol.
@@ -406,6 +413,52 @@ ReadCommand(StringInfo inBuf)
406413
returnresult;
407414
}
408415

416+
/*
417+
* prepare_for_client_read -- set up to possibly block on client input
418+
*
419+
* This must be called immediately before any low-level read from the
420+
* client connection. It is necessary to do it at a sufficiently low level
421+
* that there won't be any other operations except the read kernel call
422+
* itself between this call and the subsequent client_read_ended() call.
423+
* In particular there mustn't be use of malloc() or other potentially
424+
* non-reentrant libc functions. This restriction makes it safe for us
425+
* to allow interrupt service routines to execute nontrivial code while
426+
* we are waiting for input.
427+
*/
428+
void
429+
prepare_for_client_read(void)
430+
{
431+
if (DoingCommandRead)
432+
{
433+
/* Enable immediate processing of asynchronous signals */
434+
EnableNotifyInterrupt();
435+
EnableCatchupInterrupt();
436+
437+
/* Allow "die" interrupt to be processed while waiting */
438+
ImmediateInterruptOK= true;
439+
440+
/* And don't forget to detect one that already arrived */
441+
QueryCancelPending= false;
442+
CHECK_FOR_INTERRUPTS();
443+
}
444+
}
445+
446+
/*
447+
* client_read_ended -- get out of the client-input state
448+
*/
449+
void
450+
client_read_ended(void)
451+
{
452+
if (DoingCommandRead)
453+
{
454+
ImmediateInterruptOK= false;
455+
QueryCancelPending= false;/* forget any CANCEL signal */
456+
457+
DisableNotifyInterrupt();
458+
DisableCatchupInterrupt();
459+
}
460+
}
461+
409462

410463
/*
411464
* Parse a query string and pass it through the rewriter.
@@ -2959,6 +3012,7 @@ PostgresMain(int argc, char *argv[], const char *username)
29593012
* not in other exception-catching places since these interrupts
29603013
* are only enabled while we wait for client input.
29613014
*/
3015+
DoingCommandRead= false;
29623016
DisableNotifyInterrupt();
29633017
DisableCatchupInterrupt();
29643018

@@ -3063,21 +3117,13 @@ PostgresMain(int argc, char *argv[], const char *username)
30633117
}
30643118

30653119
/*
3066-
* (2) deal with pending asynchronous NOTIFY from other backends,
3067-
* and enable async.c's signal handler to execute NOTIFY directly.
3068-
* Then set up other stuff needed before blocking for input.
3120+
* (2) Allow asynchronous signals to be executed immediately
3121+
* if they come in while we are waiting for client input.
3122+
* (This must be conditional since we don't want, say, reads on
3123+
* behalf of COPY FROM STDIN doing the same thing.)
30693124
*/
3070-
QueryCancelPending= false;/* forget any earlier CANCEL
3071-
* signal */
3072-
3073-
EnableNotifyInterrupt();
3074-
EnableCatchupInterrupt();
3075-
3076-
/* Allow "die" interrupt to be processed while waiting */
3077-
ImmediateInterruptOK= true;
3078-
/* and don't forget to detect one that already arrived */
3079-
QueryCancelPending= false;
3080-
CHECK_FOR_INTERRUPTS();
3125+
QueryCancelPending= false;/* forget any earlier CANCEL signal */
3126+
DoingCommandRead= true;
30813127

30823128
/*
30833129
* (3) read a command (loop blocks here)
@@ -3087,11 +3133,7 @@ PostgresMain(int argc, char *argv[], const char *username)
30873133
/*
30883134
* (4) disable async signal conditions again.
30893135
*/
3090-
ImmediateInterruptOK= false;
3091-
QueryCancelPending= false;/* forget any CANCEL signal */
3092-
3093-
DisableNotifyInterrupt();
3094-
DisableCatchupInterrupt();
3136+
DoingCommandRead= false;
30953137

30963138
/*
30973139
* (5) check for any other interesting events that happened while

‎src/include/tcop/tcopprot.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.73 2004/12/31 22:03:44 pgsql Exp $
10+
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.74 2005/06/02 21:03:25 tgl Exp $
1111
*
1212
* OLD COMMENTS
1313
* This file was created so that other c files could get the two
@@ -59,6 +59,8 @@ extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);
5959
externvoiddie(SIGNAL_ARGS);
6060
externvoidquickdie(SIGNAL_ARGS);
6161
externvoidauthdie(SIGNAL_ARGS);
62+
externvoidprepare_for_client_read(void);
63+
externvoidclient_read_ended(void);
6264
externintPostgresMain(intargc,char*argv[],constchar*username);
6365
externvoidResetUsage(void);
6466
externvoidShowUsage(constchar*title);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp