Arrange to ignore SIGPIPE during SSL_read() and SSL_shutdown(), as these
are known to write on the socket sometimes and thus we are vulnerable to being killed by the signal if the server happens to go away unexpectedly. Noticed while trying (futilely) to reproduce bug #3902. This bug has been there all along, but since the situation is usually only of interest to developers, I chose not to back-patch the changes.
This commit is contained in:
parent
cf9990c66e
commit
fad2b99523
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.101 2008/01/01 19:46:00 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.102 2008/01/29 02:03:39 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
|
||||
@ -162,6 +162,50 @@ static bool pq_initssllib = true;
|
||||
static SSL_CTX *SSL_context = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros to handle disabling and then restoring the state of SIGPIPE handling.
|
||||
* Note that DISABLE_SIGPIPE() must appear at the start of a block.
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
|
||||
#define DISABLE_SIGPIPE(failaction) \
|
||||
sigset_t osigmask; \
|
||||
bool sigpipe_pending; \
|
||||
bool got_epipe = false; \
|
||||
\
|
||||
if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0) \
|
||||
failaction
|
||||
|
||||
#define REMEMBER_EPIPE(cond) \
|
||||
do { \
|
||||
if (cond) \
|
||||
got_epipe = true; \
|
||||
} while (0)
|
||||
|
||||
#define RESTORE_SIGPIPE() \
|
||||
pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe)
|
||||
|
||||
#else /* !ENABLE_THREAD_SAFETY */
|
||||
|
||||
#define DISABLE_SIGPIPE(failaction) \
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN)
|
||||
|
||||
#define REMEMBER_EPIPE(cond)
|
||||
|
||||
#define RESTORE_SIGPIPE() \
|
||||
pqsignal(SIGPIPE, oldsighandler)
|
||||
|
||||
#endif /* ENABLE_THREAD_SAFETY */
|
||||
#else /* WIN32 */
|
||||
|
||||
#define DISABLE_SIGPIPE(failaction)
|
||||
#define REMEMBER_EPIPE(cond)
|
||||
#define RESTORE_SIGPIPE()
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Procedures common to all secure sessions */
|
||||
/* ------------------------------------------------------------ */
|
||||
@ -268,6 +312,9 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* SSL_read can write to the socket, so we need to disable SIGPIPE */
|
||||
DISABLE_SIGPIPE(return -1);
|
||||
|
||||
rloop:
|
||||
n = SSL_read(conn->ssl, ptr, len);
|
||||
err = SSL_get_error(conn->ssl, n);
|
||||
@ -292,9 +339,12 @@ rloop:
|
||||
char sebuf[256];
|
||||
|
||||
if (n == -1)
|
||||
{
|
||||
REMEMBER_EPIPE(SOCK_ERRNO == EPIPE);
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("SSL SYSCALL error: %s\n"),
|
||||
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
||||
}
|
||||
else
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
@ -325,6 +375,8 @@ rloop:
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
RESTORE_SIGPIPE();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -341,19 +393,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
sigset_t osigmask;
|
||||
bool sigpipe_pending;
|
||||
bool got_epipe = false;
|
||||
|
||||
|
||||
if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0)
|
||||
return -1;
|
||||
#else
|
||||
pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
||||
#endif /* ENABLE_THREAD_SAFETY */
|
||||
#endif /* WIN32 */
|
||||
DISABLE_SIGPIPE(return -1);
|
||||
|
||||
#ifdef USE_SSL
|
||||
if (conn->ssl)
|
||||
@ -384,10 +424,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
||||
|
||||
if (n == -1)
|
||||
{
|
||||
#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
||||
if (SOCK_ERRNO == EPIPE)
|
||||
got_epipe = true;
|
||||
#endif
|
||||
REMEMBER_EPIPE(SOCK_ERRNO == EPIPE);
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("SSL SYSCALL error: %s\n"),
|
||||
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
||||
@ -426,19 +463,10 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
||||
#endif
|
||||
{
|
||||
n = send(conn->sock, ptr, len, 0);
|
||||
#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
||||
if (n < 0 && SOCK_ERRNO == EPIPE)
|
||||
got_epipe = true;
|
||||
#endif
|
||||
REMEMBER_EPIPE(n < 0 && SOCK_ERRNO == EPIPE);
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef ENABLE_THREAD_SAFETY
|
||||
pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe);
|
||||
#else
|
||||
pqsignal(SIGPIPE, oldsighandler);
|
||||
#endif /* ENABLE_THREAD_SAFETY */
|
||||
#endif /* WIN32 */
|
||||
RESTORE_SIGPIPE();
|
||||
|
||||
return n;
|
||||
}
|
||||
@ -1092,9 +1120,13 @@ close_SSL(PGconn *conn)
|
||||
{
|
||||
if (conn->ssl)
|
||||
{
|
||||
DISABLE_SIGPIPE((void) 0);
|
||||
SSL_shutdown(conn->ssl);
|
||||
SSL_free(conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
/* We have to assume we got EPIPE */
|
||||
REMEMBER_EPIPE(true);
|
||||
RESTORE_SIGPIPE();
|
||||
}
|
||||
|
||||
if (conn->peer)
|
||||
@ -1167,6 +1199,7 @@ PQgetssl(PGconn *conn)
|
||||
}
|
||||
#endif /* USE_SSL */
|
||||
|
||||
|
||||
#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
||||
|
||||
/*
|
||||
@ -1251,4 +1284,4 @@ pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
|
||||
SOCK_ERRNO_SET(save_errno);
|
||||
}
|
||||
|
||||
#endif /* ENABLE_THREAD_SAFETY */
|
||||
#endif /* ENABLE_THREAD_SAFETY && !WIN32 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user