diff --git a/CHANGES b/CHANGES index fd93e51dae..ab1d593d4d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,19 @@ +8.1.0-dev.76 | 2025-08-18 09:40:05 +0200 + + * Report PostgreSQL login success only after ReadyForQuery (Fupeng Zhao) + + Previously, Zeek treated the receipt of `AuthenticationOk` as a + successful login. However, according to the PostgreSQL + Frontend/Backend Protocol, the startup phase is not complete until + the server sends `ReadyForQuery`. It is still possible for the server + to emit an `ErrorResponse` (e.g. ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION) + after `AuthenticationOk` but before `ReadyForQuery`. + + This change updates the PostgreSQL analyzer to defer reporting login + success until `ReadyForQuery` is observed. This prevents false + positives in cases where authentication succeeds but session startup + fails. + 8.1.0-dev.74 | 2025-08-17 17:28:59 +0200 * maintenance updates for ZAM BiF-tracking (Vern Paxson, Corelight) diff --git a/VERSION b/VERSION index e64d827924..1bb074ccb2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.1.0-dev.74 +8.1.0-dev.76 diff --git a/scripts/base/protocols/postgresql/main.zeek b/scripts/base/protocols/postgresql/main.zeek index bf262467d6..16ce4f6d3f 100644 --- a/scripts/base/protocols/postgresql/main.zeek +++ b/scripts/base/protocols/postgresql/main.zeek @@ -53,7 +53,7 @@ export { user: string &optional; database: string &optional; application_name: string &optional; - rows: count &default=0; + rows: count &optional; errors: vector of string; }; @@ -197,8 +197,6 @@ event PostgreSQL::authentication_ok(c: connection) { c$postgresql$backend = "auth_ok"; c$postgresql$success = T; - - emit_log(c); } event PostgreSQL::terminate(c: connection) { @@ -224,6 +222,9 @@ event PostgreSQL::simple_query(c: connection, query: string) { event PostgreSQL::data_row(c: connection, column_values: count) { hook set_session(c); + if ( ! c$postgresql_state?$rows ) + c$postgresql_state$rows = 0; + ++c$postgresql_state$rows; } @@ -236,7 +237,11 @@ event PostgreSQL::ready_for_query(c: connection, transaction_status: string) { if ( ! c$postgresql?$success ) c$postgresql$success = transaction_status == "I" || transaction_status == "T"; - c$postgresql$rows = c$postgresql_state$rows; + if ( c$postgresql_state?$rows ) { + c$postgresql$rows = c$postgresql_state$rows; + delete c$postgresql_state$rows; + } + emit_log(c); } diff --git a/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/conn.cut b/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/conn.cut new file mode 100644 index 0000000000..23728e7aec --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/conn.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid id.orig_h id.orig_p id.resp_h id.resp_p service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.21.179.53 51625 192.168.115.201 5432 postgresql diff --git a/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/postgresql.cut b/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/postgresql.cut new file mode 100644 index 0000000000..66147ecc45 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.postgresql.psql-login-no-role/postgresql.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid id.orig_h id.orig_p id.resp_h id.resp_p user database application_name frontend frontend_arg backend backend_arg success rows +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.21.179.53 51625 192.168.115.201 5432 - - - ssl_request - ssl_reply N F - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 10.21.179.53 51625 192.168.115.201 5432 test postgres Navicat startup - auth_ok,error SeverityLocalized=FATAL,Severity=FATAL,Code=28000,Message=role "test" does not exist,File=miscinit.c,Line=694,Routine=InitializeSessionUserId F - diff --git a/testing/btest/Traces/postgresql/psql-login-no-role.pcap b/testing/btest/Traces/postgresql/psql-login-no-role.pcap new file mode 100644 index 0000000000..c65069ae52 Binary files /dev/null and b/testing/btest/Traces/postgresql/psql-login-no-role.pcap differ diff --git a/testing/btest/scripts/base/protocols/postgresql/psql-login-no-role.zeek b/testing/btest/scripts/base/protocols/postgresql/psql-login-no-role.zeek new file mode 100644 index 0000000000..4591b7b86a --- /dev/null +++ b/testing/btest/scripts/base/protocols/postgresql/psql-login-no-role.zeek @@ -0,0 +1,12 @@ +# @TEST-DOC: Test Zeek parsing a trace file through the PostgreSQL analyzer. +# +# @TEST-REQUIRES: ${SCRIPTS}/have-spicy +# @TEST-EXEC: zeek -b -r ${TRACES}/postgresql/psql-login-no-role.pcap %INPUT >output +# @TEST-EXEC: zeek-cut -m ts uid id.orig_h id.orig_p id.resp_h id.resp_p service < conn.log > conn.cut +# @TEST-EXEC: zeek-cut -m < postgresql.log > postgresql.cut +# +# @TEST-EXEC: btest-diff conn.cut +# @TEST-EXEC: btest-diff postgresql.cut + +@load base/protocols/conn +@load base/protocols/postgresql