diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index a632cf98ba..ab4a6e6c7b 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -3008,6 +3008,25 @@ include_dir 'conf.d' + + wal_sessioninfo (boolean) + + wal_sessioninfo configuration parameter + + + + + When this parameter is on, the PostgreSQL + server will add information about the user's session onto every + commit or abort record. This is intended to provide additional information + to trace the changes made by specific sessions, allowing more in-depth + investigation during security audits or impact assessment of bugs. + The default value is off. + Only superusers can change this setting. + + + + wal_init_zero (boolean) diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c index addd95faec..77af6911e9 100644 --- a/src/backend/access/rmgrdesc/xactdesc.c +++ b/src/backend/access/rmgrdesc/xactdesc.c @@ -123,6 +123,20 @@ ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *pars data += sizeof(xl_xact_origin); } + + if (parsed->xinfo & XACT_XINFO_HAS_SESSIONINFO) + { + xl_xact_sessioninfo xl_sessioninfo; + + /* no alignment is guaranteed, so copy onto stack */ + memcpy(&xl_sessioninfo, data, sizeof(xl_sessioninfo)); + + parsed->session_start_time = xl_sessioninfo.session_start_time; + parsed->session_pid = xl_sessioninfo.session_pid; + parsed->userid = xl_sessioninfo.userid; + + data += sizeof(xl_xact_sessioninfo); + } } void @@ -207,6 +221,20 @@ ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed) data += sizeof(xl_xact_origin); } + + if (parsed->xinfo & XACT_XINFO_HAS_SESSIONINFO) + { + xl_xact_sessioninfo xl_sessioninfo; + + /* no alignment is guaranteed, so copy onto stack */ + memcpy(&xl_sessioninfo, data, sizeof(xl_sessioninfo)); + + parsed->session_start_time = xl_sessioninfo.session_start_time; + parsed->session_pid = xl_sessioninfo.session_pid; + parsed->userid = xl_sessioninfo.userid; + + data += sizeof(xl_xact_sessioninfo); + } } /* @@ -310,6 +338,14 @@ xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId (uint32) parsed.origin_lsn, timestamptz_to_str(parsed.origin_timestamp)); } + + if (parsed.xinfo & XACT_XINFO_HAS_SESSIONINFO) + { + appendStringInfo(buf, "; session: pid %u, start at %s userid %u", + parsed.session_pid, + timestamptz_to_str(parsed.session_start_time), + parsed.userid); + } } static void @@ -327,6 +363,14 @@ xact_desc_abort(StringInfo buf, uint8 info, xl_xact_abort *xlrec) xact_desc_relations(buf, "rels", parsed.nrels, parsed.xnodes); xact_desc_subxacts(buf, parsed.nsubxacts, parsed.subxacts); + + if (parsed.xinfo & XACT_XINFO_HAS_SESSIONINFO) + { + appendStringInfo(buf, "; session: pid %u, start at %s userid %u", + parsed.session_pid, + timestamptz_to_str(parsed.session_start_time), + parsed.userid); + } } static void diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 03c553e7ea..83022e28f8 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -82,6 +82,8 @@ bool XactDeferrable; int synchronous_commit = SYNCHRONOUS_COMMIT_ON; +bool wal_sessioninfo = false; + /* * CheckXidAlive is a xid value pointing to a possibly ongoing (sub) * transaction. Currently, it is used in logical decoding. It's possible @@ -5515,6 +5517,7 @@ XactLogCommitRecord(TimestampTz commit_time, xl_xact_invals xl_invals; xl_xact_twophase xl_twophase; xl_xact_origin xl_origin; + xl_xact_sessioninfo xl_sessioninfo; uint8 info; Assert(CritSectionCount > 0); @@ -5594,6 +5597,15 @@ XactLogCommitRecord(TimestampTz commit_time, xl_origin.origin_timestamp = replorigin_session_origin_timestamp; } + if (wal_sessioninfo) + { + xl_xinfo.xinfo |= XACT_XINFO_HAS_SESSIONINFO; + + xl_sessioninfo.session_start_time = MyStartTimestamp; + xl_sessioninfo.session_pid = MyProcPid; + xl_sessioninfo.userid = GetUserId(); + } + if (xl_xinfo.xinfo != 0) info |= XLOG_XACT_HAS_INFO; @@ -5642,6 +5654,9 @@ XactLogCommitRecord(TimestampTz commit_time, if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN) XLogRegisterData((char *) (&xl_origin), sizeof(xl_xact_origin)); + if (xl_xinfo.xinfo & XACT_XINFO_HAS_SESSIONINFO) + XLogRegisterData((char *) (&xl_sessioninfo), sizeof(xl_xact_sessioninfo)); + /* we allow filtering by xacts */ XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); @@ -5668,6 +5683,7 @@ XactLogAbortRecord(TimestampTz abort_time, xl_xact_twophase xl_twophase; xl_xact_dbinfo xl_dbinfo; xl_xact_origin xl_origin; + xl_xact_sessioninfo xl_sessioninfo; uint8 info; @@ -5730,6 +5746,15 @@ XactLogAbortRecord(TimestampTz abort_time, xl_origin.origin_timestamp = replorigin_session_origin_timestamp; } + if (wal_sessioninfo) + { + xl_xinfo.xinfo |= XACT_XINFO_HAS_SESSIONINFO; + + xl_sessioninfo.session_start_time = MyStartTimestamp; + xl_sessioninfo.session_pid = MyProcPid; + xl_sessioninfo.userid = GetUserId(); + } + if (xl_xinfo.xinfo != 0) info |= XLOG_XACT_HAS_INFO; @@ -5771,6 +5796,9 @@ XactLogAbortRecord(TimestampTz abort_time, if (xl_xinfo.xinfo & XACT_XINFO_HAS_ORIGIN) XLogRegisterData((char *) (&xl_origin), sizeof(xl_xact_origin)); + if (xl_xinfo.xinfo & XACT_XINFO_HAS_SESSIONINFO) + XLogRegisterData((char *) (&xl_sessioninfo), sizeof(xl_xact_sessioninfo)); + if (TransactionIdIsValid(twophase_xid)) XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); @@ -5870,6 +5898,8 @@ xact_redo_commit(xl_xact_parsed_commit *parsed, false /* backward */ , false /* WAL */ ); } + /* No action if XACT_INFO_HAS_SESSIONINFO */ + /* Make sure files supposed to be dropped are dropped */ if (parsed->nrels > 0) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index bb34630e8e..c69754531d 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -130,6 +130,7 @@ extern char *temp_tablespaces; extern bool ignore_checksum_failure; extern bool ignore_invalid_pages; extern bool synchronize_seqscans; +extern bool wal_sessioninfo; #ifdef TRACE_SYNCSCAN extern bool trace_syncscan; @@ -1269,6 +1270,16 @@ static struct config_bool ConfigureNamesBool[] = NULL, NULL, NULL }, + { + {"wal_sessioninfo", PGC_SUSET, WAL_SETTINGS, + gettext_noop("Includes sessionfo onto the WAL records for transaction completion."), + NULL + }, + &wal_sessioninfo, + true, + NULL, NULL, NULL + }, + { {"wal_init_zero", PGC_SUSET, WAL_SETTINGS, gettext_noop("Writes zeroes to new WAL files before first use."), diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 7320de345c..533be43950 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -172,6 +172,7 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid, #define XACT_XINFO_HAS_ORIGIN (1U << 5) #define XACT_XINFO_HAS_AE_LOCKS (1U << 6) #define XACT_XINFO_HAS_GID (1U << 7) +#define XACT_XINFO_HAS_SESSIONINFO (1U << 8) /* * Also stored in xinfo, these indicating a variety of additional actions that @@ -267,6 +268,13 @@ typedef struct xl_xact_origin TimestampTz origin_timestamp; } xl_xact_origin; +typedef struct xl_xact_sessioninfo +{ + TimestampTz session_start_time; + int session_pid; + Oid userid; +} xl_xact_sessioninfo; + typedef struct xl_xact_commit { TimestampTz xact_time; /* time of commit */ @@ -279,6 +287,7 @@ typedef struct xl_xact_commit /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */ /* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */ /* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */ + /* xl_xact_sessioninfo follows if XINFO_HAS_SESSIONINFO */ } xl_xact_commit; #define MinSizeOfXactCommit (offsetof(xl_xact_commit, xact_time) + sizeof(TimestampTz)) @@ -294,6 +303,7 @@ typedef struct xl_xact_abort /* xl_xact_twophase follows if XINFO_HAS_TWOPHASE */ /* twophase_gid follows if XINFO_HAS_GID. As a null-terminated string. */ /* xl_xact_origin follows if XINFO_HAS_ORIGIN, stored unaligned! */ + /* xl_xact_sessioninfo follows if XINFO_HAS_SESSIONINFO */ } xl_xact_abort; #define MinSizeOfXactAbort sizeof(xl_xact_abort) @@ -344,6 +354,10 @@ typedef struct xl_xact_parsed_commit XLogRecPtr origin_lsn; TimestampTz origin_timestamp; + + TimestampTz session_start_time; + int session_pid; + Oid userid; } xl_xact_parsed_commit; typedef xl_xact_parsed_commit xl_xact_parsed_prepare; @@ -367,6 +381,10 @@ typedef struct xl_xact_parsed_abort XLogRecPtr origin_lsn; TimestampTz origin_timestamp; + + TimestampTz session_start_time; + int session_pid; + Oid userid; } xl_xact_parsed_abort;