diff options
author | Michael Paquier | 2012-10-23 08:01:15 +0000 |
---|---|---|
committer | Michael Paquier | 2012-10-23 08:01:15 +0000 |
commit | 786d74ba8bf8058a504df6ac6b20023cfe260991 (patch) | |
tree | 4163bb5a277923d9324acea2c596de47ea0ef53d | |
parent | 23220741845f72669e5bd4bb5825d8818fb16223 (diff) |
Fix memory corruption for GTM/backend buffer on backend side
This commit fixes an issue that corrupted data from GTM on Postgres backend for
snapshots and transaction IDs. The origin of the failure was the startup
package of GTM that was not initialized correctly, so the data it contained
could be used as snapshot or GXID data in very particular situations like when
a vacuum freeze is kicked on a system table due to the table oldest XID being
too old in accordance to settings like autovacuum_freeze_max_age and
autovacuum_freeze_min_age.
In order to reproduce easily the problem, I personnally had to use a cluster
of 5 nodes with autovacuum_freeze_max_age at its minimum value, then wait for
a system table to be automatically vacuumed. Once the vacuum was kicked, the
buffer of 16kb used at backend side to store messages from GTM got corrupted,
having as consequence to generate multiple types of crashes related to memory
allocation (realloc and malloc calls).
It is really surprising that this issue was not reproducible in other
circumstances and could only be spotted with a forced vacuum as it was a pretty
general problem related to GTM communication, and valgrind helped to spot pretty
easily the memory area that was corrupted.
-rw-r--r-- | src/gtm/client/fe-connect.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/src/gtm/client/fe-connect.c b/src/gtm/client/fe-connect.c index a3add0e1f4..bfcb5f4e54 100644 --- a/src/gtm/client/fe-connect.c +++ b/src/gtm/client/fe-connect.c @@ -665,7 +665,11 @@ keep_going: /* We will come back to here until there is case CONNECTION_MADE: { - GTM_StartupPacket sp; + GTM_StartupPacket *sp = (GTM_StartupPacket *) + malloc(sizeof(GTM_StartupPacket)); + int packetlen = sizeof(GTM_StartupPacket); + + MemSet(sp, 0, sizeof(GTM_StartupPacket)); /* * Build a startup packet. We tell the GTM server/proxy our @@ -675,9 +679,9 @@ keep_going: /* We will come back to here until there is * server know about it so that some special headers are * handled correctly by the server. */ - strcpy(sp.sp_node_name, conn->gc_node_name); - sp.sp_remotetype = conn->remote_type; - sp.sp_ispostmaster = conn->is_postmaster; + strncpy(sp->sp_node_name, conn->gc_node_name, SP_NODE_NAME); + sp->sp_remotetype = conn->remote_type; + sp->sp_ispostmaster = conn->is_postmaster; /* * Send the startup packet. @@ -685,7 +689,7 @@ keep_going: /* We will come back to here until there is * Theoretically, this could block, but it really shouldn't * since we only got here if the socket is write-ready. */ - if (pqPacketSend(conn, 'A', &sp, sizeof (GTM_StartupPacket)) != STATUS_OK) + if (pqPacketSend(conn, 'A', (char *)sp, packetlen) != STATUS_OK) { appendGTMPQExpBuffer(&conn->errorMessage, "could not send startup packet: \n"); @@ -693,6 +697,10 @@ keep_going: /* We will come back to here until there is } conn->status = CONNECTION_AWAITING_RESPONSE; + + /* Clean up startup packet */ + free(sp); + return PGRES_POLLING_READING; } |