|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* libpq.h
|
|
|
|
* POSTGRES LIBPQ buffer structure definitions.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* src/include/libpq/libpq.h
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#ifndef LIBPQ_H
|
|
|
|
#define LIBPQ_H
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include "lib/stringinfo.h"
|
|
|
|
#include "libpq/libpq-be.h"
|
Introduce WaitEventSet API.
Commit ac1d794 ("Make idle backends exit if the postmaster dies.")
introduced a regression on, at least, large linux systems. Constantly
adding the same postmaster_alive_fds to the OSs internal datastructures
for implementing poll/select can cause significant contention; leading
to a performance regression of nearly 3x in one example.
This can be avoided by using e.g. linux' epoll, which avoids having to
add/remove file descriptors to the wait datastructures at a high rate.
Unfortunately the current latch interface makes it hard to allocate any
persistent per-backend resources.
Replace, with a backward compatibility layer, WaitLatchOrSocket with a
new WaitEventSet API. Users can allocate such a Set across multiple
calls, and add more than one file-descriptor to wait on. The latter has
been added because there's upcoming postgres features where that will be
helpful.
In addition to the previously existing poll(2), select(2),
WaitForMultipleObjects() implementations also provide an epoll_wait(2)
based implementation to address the aforementioned performance
problem. Epoll is only available on linux, but that is the most likely
OS for machines large enough (four sockets) to reproduce the problem.
To actually address the aforementioned regression, create and use a
long-lived WaitEventSet for FE/BE communication. There are additional
places that would benefit from a long-lived set, but that's a task for
another day.
Thanks to Amit Kapila, who helped make the windows code I blindly wrote
actually work.
Reported-By: Dmitry Vasilyev Discussion:
CAB-SwXZh44_2ybvS5Z67p_CDz=XFn4hNAD=CnMEF+QqkXwFrGg@mail.gmail.com
20160114143931.GG10941@awork2.anarazel.de
10 years ago
|
|
|
#include "storage/latch.h"
|
|
|
|
|
|
|
|
|
Add heuristic incoming-message-size limits in the server.
We had a report of confusing server behavior caused by a client bug
that sent junk to the server: the server thought the junk was a
very long message length and waited patiently for data that would
never come. We can reduce the risk of that by being less trusting
about message lengths.
For a long time, libpq has had a heuristic rule that it wouldn't
believe large message size words, except for a small number of
message types that are expected to be (potentially) long. This
provides some defense against loss of message-boundary sync and
other corrupted-data cases. The server does something similar,
except that up to now it only limited the lengths of messages
received during the connection authentication phase. Let's
do the same as in libpq and put restrictions on the allowed
length of all messages, while distinguishing between message
types that are expected to be long and those that aren't.
I used a limit of 10000 bytes for non-long messages. (libpq's
corresponding limit is 30000 bytes, but given the asymmetry of
the FE/BE protocol, there's no good reason why the numbers should
be the same.) Experimentation suggests that this is at least a
factor of 10, maybe a factor of 100, more than we really need;
but plenty of daylight seems desirable to avoid false positives.
In any case we can adjust the limit based on beta-test results.
For long messages, set a limit of MaxAllocSize - 1, which is the
most that we can absorb into the StringInfo buffer that the message
is collected in. This just serves to make sure that a bogus message
size is reported as such, rather than as a confusing gripe about
not being able to enlarge a string buffer.
While at it, make sure that non-mainline code paths (such as
COPY FROM STDIN) are as paranoid as SocketBackend is, and validate
the message type code before believing the message length.
This provides an additional guard against getting stuck on corrupted
input.
Discussion: https://postgr.es/m/2003757.1619373089@sss.pgh.pa.us
4 years ago
|
|
|
/*
|
|
|
|
* Callers of pq_getmessage() must supply a maximum expected message size.
|
|
|
|
* By convention, if there's not any specific reason to use another value,
|
|
|
|
* use PQ_SMALL_MESSAGE_LIMIT for messages that shouldn't be too long, and
|
|
|
|
* PQ_LARGE_MESSAGE_LIMIT for messages that can be long.
|
|
|
|
*/
|
|
|
|
#define PQ_SMALL_MESSAGE_LIMIT 10000
|
|
|
|
#define PQ_LARGE_MESSAGE_LIMIT (MaxAllocSize - 1)
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
void (*comm_reset) (void);
|
|
|
|
int (*flush) (void);
|
|
|
|
int (*flush_if_writable) (void);
|
|
|
|
bool (*is_send_pending) (void);
|
|
|
|
int (*putmessage) (char msgtype, const char *s, size_t len);
|
|
|
|
void (*putmessage_noblock) (char msgtype, const char *s, size_t len);
|
|
|
|
} PQcommMethods;
|
|
|
|
|
|
|
|
extern const PGDLLIMPORT PQcommMethods *PqCommMethods;
|
|
|
|
|
|
|
|
#define pq_comm_reset() (PqCommMethods->comm_reset())
|
|
|
|
#define pq_flush() (PqCommMethods->flush())
|
|
|
|
#define pq_flush_if_writable() (PqCommMethods->flush_if_writable())
|
|
|
|
#define pq_is_send_pending() (PqCommMethods->is_send_pending())
|
|
|
|
#define pq_putmessage(msgtype, s, len) \
|
|
|
|
(PqCommMethods->putmessage(msgtype, s, len))
|
|
|
|
#define pq_putmessage_noblock(msgtype, s, len) \
|
|
|
|
(PqCommMethods->putmessage_noblock(msgtype, s, len))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* External functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prototypes for functions in pqcomm.c
|
|
|
|
*/
|
|
|
|
extern PGDLLIMPORT WaitEventSet *FeBeWaitSet;
|
|
|
|
|
|
|
|
#define FeBeWaitSetSocketPos 0
|
|
|
|
#define FeBeWaitSetLatchPos 1
|
|
|
|
#define FeBeWaitSetNEvents 3
|
|
|
|
|
|
|
|
extern int ListenServerPort(int family, const char *hostName,
|
|
|
|
unsigned short portNumber, const char *unixSocketDir,
|
|
|
|
pgsocket ListenSockets[], int *NumListenSockets, int MaxListen);
|
|
|
|
extern int AcceptConnection(pgsocket server_fd, ClientSocket *client_sock);
|
|
|
|
extern void TouchSocketFiles(void);
|
|
|
|
extern void RemoveSocketFiles(void);
|
|
|
|
extern Port *pq_init(ClientSocket *client_sock);
|
|
|
|
extern int pq_getbytes(void *b, size_t len);
|
Be more careful to not lose sync in the FE/BE protocol.
If any error occurred while we were in the middle of reading a protocol
message from the client, we could lose sync, and incorrectly try to
interpret a part of another message as a new protocol message. That will
usually lead to an "invalid frontend message" error that terminates the
connection. However, this is a security issue because an attacker might
be able to deliberately cause an error, inject a Query message in what's
supposed to be just user data, and have the server execute it.
We were quite careful to not have CHECK_FOR_INTERRUPTS() calls or other
operations that could ereport(ERROR) in the middle of processing a message,
but a query cancel interrupt or statement timeout could nevertheless cause
it to happen. Also, the V2 fastpath and COPY handling were not so careful.
It's very difficult to recover in the V2 COPY protocol, so we will just
terminate the connection on error. In practice, that's what happened
previously anyway, as we lost protocol sync.
To fix, add a new variable in pqcomm.c, PqCommReadingMsg, that is set
whenever we're in the middle of reading a message. When it's set, we cannot
safely ERROR out and continue running, because we might've read only part
of a message. PqCommReadingMsg acts somewhat similarly to critical sections
in that if an error occurs while it's set, the error handler will force the
connection to be terminated, as if the error was FATAL. It's not
implemented by promoting ERROR to FATAL in elog.c, like ERROR is promoted
to PANIC in critical sections, because we want to be able to use
PG_TRY/CATCH to recover and regain protocol sync. pq_getmessage() takes
advantage of that to prevent an OOM error from terminating the connection.
To prevent unnecessary connection terminations, add a holdoff mechanism
similar to HOLD/RESUME_INTERRUPTS() that can be used hold off query cancel
interrupts, but still allow die interrupts. The rules on which interrupts
are processed when are now a bit more complicated, so refactor
ProcessInterrupts() and the calls to it in signal handlers so that the
signal handlers always call it if ImmediateInterruptOK is set, and
ProcessInterrupts() can decide to not do anything if the other conditions
are not met.
Reported by Emil Lenngren. Patch reviewed by Noah Misch and Andres Freund.
Backpatch to all supported versions.
Security: CVE-2015-0244
11 years ago
|
|
|
extern void pq_startmsgread(void);
|
|
|
|
extern void pq_endmsgread(void);
|
|
|
|
extern bool pq_is_reading_msg(void);
|
|
|
|
extern int pq_getmessage(StringInfo s, int maxlen);
|
|
|
|
extern int pq_getbyte(void);
|
|
|
|
extern int pq_peekbyte(void);
|
|
|
|
extern int pq_getbyte_if_available(unsigned char *c);
|
|
|
|
extern ssize_t pq_buffer_remaining_data(void);
|
|
|
|
extern int pq_putmessage_v2(char msgtype, const char *s, size_t len);
|
|
|
|
extern bool pq_check_connection(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prototypes for functions in be-secure.c
|
|
|
|
*/
|
|
|
|
extern int secure_initialize(bool isServerStart);
|
|
|
|
extern bool secure_loaded_verify_locations(void);
|
|
|
|
extern void secure_destroy(void);
|
|
|
|
extern int secure_open_server(Port *port);
|
|
|
|
extern void secure_close(Port *port);
|
|
|
|
extern ssize_t secure_read(Port *port, void *ptr, size_t len);
|
|
|
|
extern ssize_t secure_write(Port *port, const void *ptr, size_t len);
|
Break out OpenSSL-specific code to separate files.
This refactoring is in preparation for adding support for other SSL
implementations, with no user-visible effects. There are now two #defines,
USE_OPENSSL which is defined when building with OpenSSL, and USE_SSL which
is defined when building with any SSL implementation. Currently, OpenSSL is
the only implementation so the two #defines go together, but USE_SSL is
supposed to be used for implementation-independent code.
The libpq SSL code is changed to use a custom BIO, which does all the raw
I/O, like we've been doing in the backend for a long time. That makes it
possible to use MSG_NOSIGNAL to block SIGPIPE when using SSL, which avoids
a couple of syscall for each send(). Probably doesn't make much performance
difference in practice - the SSL encryption is expensive enough to mask the
effect - but it was a natural result of this refactoring.
Based on a patch by Martijn van Oosterhout from 2006. Briefly reviewed by
Alvaro Herrera, Andreas Karlsson, Jeff Janes.
11 years ago
|
|
|
extern ssize_t secure_raw_read(Port *port, void *ptr, size_t len);
|
|
|
|
extern ssize_t secure_raw_write(Port *port, const void *ptr, size_t len);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* declarations for variables defined in be-secure.c
|
|
|
|
*/
|
|
|
|
extern PGDLLIMPORT char *ssl_library;
|
|
|
|
extern PGDLLIMPORT char *ssl_ca_file;
|
|
|
|
extern PGDLLIMPORT char *ssl_cert_file;
|
|
|
|
extern PGDLLIMPORT char *ssl_crl_file;
|
|
|
|
extern PGDLLIMPORT char *ssl_crl_dir;
|
|
|
|
extern PGDLLIMPORT char *ssl_key_file;
|
|
|
|
extern PGDLLIMPORT int ssl_min_protocol_version;
|
|
|
|
extern PGDLLIMPORT int ssl_max_protocol_version;
|
|
|
|
extern PGDLLIMPORT char *ssl_passphrase_command;
|
|
|
|
extern PGDLLIMPORT bool ssl_passphrase_command_supports_reload;
|
|
|
|
extern PGDLLIMPORT char *ssl_dh_params_file;
|
|
|
|
extern PGDLLIMPORT char *SSLCipherSuites;
|
|
|
|
extern PGDLLIMPORT char *SSLCipherList;
|
|
|
|
extern PGDLLIMPORT char *SSLECDHCurve;
|
|
|
|
extern PGDLLIMPORT bool SSLPreferServerCiphers;
|
|
|
|
#ifdef USE_SSL
|
|
|
|
extern PGDLLIMPORT bool ssl_loaded_verify_locations;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_SSL
|
|
|
|
#define SSL_LIBRARY "OpenSSL"
|
|
|
|
#else
|
|
|
|
#define SSL_LIBRARY ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
#define DEFAULT_SSL_CIPHERS "HIGH:MEDIUM:+3DES:!aNULL"
|
|
|
|
#else
|
|
|
|
#define DEFAULT_SSL_CIPHERS "none"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_SSL
|
|
|
|
#define DEFAULT_SSL_GROUPS "X25519:prime256v1"
|
|
|
|
#else
|
|
|
|
#define DEFAULT_SSL_GROUPS "none"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prototypes for functions in be-secure-gssapi.c
|
|
|
|
*/
|
|
|
|
#ifdef ENABLE_GSS
|
|
|
|
extern ssize_t secure_open_gssapi(Port *port);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
enum ssl_protocol_versions
|
|
|
|
{
|
|
|
|
PG_TLS_ANY = 0,
|
|
|
|
PG_TLS1_VERSION,
|
|
|
|
PG_TLS1_1_VERSION,
|
|
|
|
PG_TLS1_2_VERSION,
|
|
|
|
PG_TLS1_3_VERSION,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prototypes for functions in be-secure-common.c
|
|
|
|
*/
|
|
|
|
extern int run_ssl_passphrase_command(const char *prompt, bool is_server_start,
|
|
|
|
char *buf, int size);
|
|
|
|
extern bool check_ssl_key_file_permissions(const char *ssl_key_file,
|
|
|
|
bool isServerStart);
|
|
|
|
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
8 years ago
|
|
|
#endif /* LIBPQ_H */
|