0003-WIP-Add-injection-points-and-test-for-early-backend-.patch
text/x-patch
Filename: 0003-WIP-Add-injection-points-and-test-for-early-backend-.patch
Type: text/x-patch
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0003
Subject: WIP: Add injection points and test for early backend startup errors
| File | + | − |
|---|---|---|
| src/backend/tcop/backend_startup.c | 9 | 0 |
| src/backend/utils/misc/injection_point.c | 31 | 2 |
| src/include/utils/injection_point.h | 1 | 0 |
| src/interfaces/libpq/meson.build | 1 | 0 |
| src/interfaces/libpq/t/005_negotiate_encryption.pl | 50 | 0 |
From e893d2e53a9bde6ddf4462d9f8b206c51ebd40cb Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 24 Jun 2024 18:15:53 +0300
Subject: [PATCH 3/4] WIP: Add injection points and test for early backend
startup errors
---
src/backend/tcop/backend_startup.c | 9 ++++
src/backend/utils/misc/injection_point.c | 33 +++++++++++-
src/include/utils/injection_point.h | 1 +
src/interfaces/libpq/meson.build | 1 +
.../libpq/t/005_negotiate_encryption.pl | 50 +++++++++++++++++++
5 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/src/backend/tcop/backend_startup.c b/src/backend/tcop/backend_startup.c
index cfa27551964..7b4a3e23458 100644
--- a/src/backend/tcop/backend_startup.c
+++ b/src/backend/tcop/backend_startup.c
@@ -33,6 +33,7 @@
#include "tcop/backend_startup.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
+#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
@@ -160,6 +161,14 @@ BackendInitialize(ClientSocket *client_sock, CAC_state cac)
whereToSendOutput = DestRemote; /* now safe to ereport to client */
+ /* For testing client error handling */
+ INJECTION_POINT("backend-initialize");
+ if (IsInjectionPointAttached("backend-initialize-v2-error"))
+ {
+ FrontendProtocol = PG_PROTOCOL(2,0);
+ elog(FATAL, "protocol version 2 error triggered");
+ }
+
/* set these to empty in case they are needed before we set them up */
port->remote_host = "";
port->remote_port = "";
diff --git a/src/backend/utils/misc/injection_point.c b/src/backend/utils/misc/injection_point.c
index 5c2a0d2297e..d3995dfd6fc 100644
--- a/src/backend/utils/misc/injection_point.c
+++ b/src/backend/utils/misc/injection_point.c
@@ -24,6 +24,7 @@
#include "port/pg_bitutils.h"
#include "storage/fd.h"
#include "storage/lwlock.h"
+#include "storage/proc.h"
#include "storage/shmem.h"
#include "utils/hsearch.h"
#include "utils/injection_point.h"
@@ -281,6 +282,31 @@ InjectionPointDetach(const char *name)
#endif
}
+/*
+ * Test if an injection point is defined.
+ */
+bool
+IsInjectionPointAttached(const char *name)
+{
+#ifdef USE_INJECTION_POINTS
+ bool found;
+
+ /* FIXME: just skip locking if we don't have a PGPROC entry yet. Obviously unsafe.. */
+ if (MyProc != NULL && IsUnderPostmaster)
+ LWLockAcquire(InjectionPointLock, LW_SHARED);
+
+ (void) hash_search(InjectionPointHash, name, HASH_FIND, &found);
+
+ if (MyProc != NULL && IsUnderPostmaster)
+ LWLockRelease(InjectionPointLock);
+
+ return found;
+#else
+ elog(ERROR, "Injection points are not supported by this build");
+ return false; /* silence compiler */
+#endif
+}
+
/*
* Execute an injection point, if defined.
*
@@ -296,11 +322,14 @@ InjectionPointRun(const char *name)
InjectionPointCallback injection_callback;
const void *private_data;
- LWLockAcquire(InjectionPointLock, LW_SHARED);
+ /* FIXME: just skip locking if we don't have a PGPROC entry yet. Obviously unsafe.. */
+ if (MyProc != NULL && IsUnderPostmaster)
+ LWLockAcquire(InjectionPointLock, LW_SHARED);
entry_by_name = (InjectionPointEntry *)
hash_search(InjectionPointHash, name,
HASH_FIND, &found);
- LWLockRelease(InjectionPointLock);
+ if (MyProc != NULL && IsUnderPostmaster)
+ LWLockRelease(InjectionPointLock);
/*
* If not found, do nothing and remove it from the local cache if it
diff --git a/src/include/utils/injection_point.h b/src/include/utils/injection_point.h
index a61d5d44391..5715eefb31e 100644
--- a/src/include/utils/injection_point.h
+++ b/src/include/utils/injection_point.h
@@ -35,6 +35,7 @@ extern void InjectionPointAttach(const char *name,
const void *private_data,
int private_data_size);
extern void InjectionPointRun(const char *name);
+extern bool IsInjectionPointAttached(const char *name);
extern bool InjectionPointDetach(const char *name);
#endif /* INJECTION_POINT_H */
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
index ed2a4048d18..7623aeadab7 100644
--- a/src/interfaces/libpq/meson.build
+++ b/src/interfaces/libpq/meson.build
@@ -121,6 +121,7 @@ tests += {
't/005_negotiate_encryption.pl',
],
'env': {
+ 'enable_injection_points': get_option('injection_points') ? 'yes' : 'no',
'with_ssl': ssl_library,
'with_gssapi': gssapi.found() ? 'yes' : 'no',
'with_krb_srvnam': 'postgres',
diff --git a/src/interfaces/libpq/t/005_negotiate_encryption.pl b/src/interfaces/libpq/t/005_negotiate_encryption.pl
index c3f70d31bc8..e6bea0f04f8 100644
--- a/src/interfaces/libpq/t/005_negotiate_encryption.pl
+++ b/src/interfaces/libpq/t/005_negotiate_encryption.pl
@@ -90,6 +90,8 @@ my $kerberos_enabled =
$ENV{PG_TEST_EXTRA} && $ENV{PG_TEST_EXTRA} =~ /\bkerberos\b/;
my $ssl_supported = $ENV{with_ssl} eq 'openssl';
+my $injection_points_supported = $ENV{enable_injection_points} eq 'yes';
+
###
### Prepare test server for GSSAPI and SSL authentication, with a few
### different test users and helper functions. We don't actually
@@ -155,6 +157,10 @@ $node->safe_psql('postgres', 'CREATE USER ssluser;');
$node->safe_psql('postgres', 'CREATE USER nossluser;');
$node->safe_psql('postgres', 'CREATE USER gssuser;');
$node->safe_psql('postgres', 'CREATE USER nogssuser;');
+if ($injection_points_supported != 0)
+{
+ $node->safe_psql('postgres', 'CREATE EXTENSION injection_points;')
+}
my $unixdir = $node->safe_psql('postgres', 'SHOW unix_socket_directories;');
chomp($unixdir);
@@ -320,6 +326,27 @@ nossluser . disable postgres connect, authok
\@all_sslmodes, \@all_sslnegotiations,
parse_table($test_table));
+ if ($injection_points_supported != 0)
+ {
+ $node->safe_psql('postgres',
+ "SELECT injection_points_attach('backend-initialize', 'error');",
+ connstr => "user=localuser host=$unixdir");
+ connect_test(
+ $node,
+ "user=testuser sslmode=prefer",
+ 'backenderror -> fail');
+ $node->restart;
+
+ $node->safe_psql('postgres',
+ "SELECT injection_points_attach('backend-initialize-v2-error', 'error');",
+ connstr => "user=localuser host=$unixdir");
+ connect_test(
+ $node,
+ "user=testuser sslmode=prefer",
+ 'v2error -> fail');
+ $node->restart;
+ }
+
# Disable SSL again
$node->adjust_conf('postgresql.conf', 'ssl', 'off');
$node->reload;
@@ -403,6 +430,27 @@ nogssuser disable disable postgres connect, authok
test_matrix($node, $server_config, [ 'testuser', 'gssuser', 'nogssuser' ],
\@all_gssencmodes, $sslmodes, $sslnegotiations,
parse_table($test_table));
+
+ if ($injection_points_supported != 0)
+ {
+ $node->safe_psql('postgres',
+ "SELECT injection_points_attach('backend-initialize', 'error');",
+ connstr => "user=localuser host=$unixdir");
+ connect_test(
+ $node,
+ "user=testuser gssencmode=prefer sslmode=disable",
+ 'backenderror, backenderror -> fail');
+ $node->restart;
+
+ $node->safe_psql('postgres',
+ "SELECT injection_points_attach('backend-initialize-v2-error', 'error');",
+ connstr => "user=localuser host=$unixdir");
+ connect_test(
+ $node,
+ "user=testuser gssencmode=prefer sslmode=disable",
+ 'v2error -> fail');
+ $node->restart;
+ }
}
###
@@ -750,6 +798,8 @@ sub parse_log_events
push @events, "gssreject" if $line =~ /GSSENCRequest rejected/;
push @events, "authfail" if $line =~ /no pg_hba.conf entry/;
push @events, "authok" if $line =~ /connection authenticated/;
+ push @events, "backenderror" if $line =~ /error triggered for injection point backend-/;
+ push @events, "v2error" if $line =~ /protocol version 2 error triggered/;
}
# No events at all is represented by "-"
--
2.39.2