Acquire ControlFileLock in relevant SQL functions.
authorThomas Munro
Sun, 15 Oct 2023 21:43:47 +0000 (10:43 +1300)
committerThomas Munro
Sun, 15 Oct 2023 21:43:47 +0000 (10:43 +1300)
Commit dc7d70ea added functions that read the control file, but didn't
acquire ControlFileLock.  With unlucky timing, file systems that have
weak interlocking like ext4 and ntfs could expose partially overwritten
contents, and the checksum would fail.

Back-patch to all supported releases.

Reviewed-by: David Steele
Reviewed-by: Anton A. Melnikov
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20221123014224.xisi44byq3cf5psi%40awork3.anarazel.de

src/backend/utils/misc/pg_controldata.c

index f2c1084797b0d79b36d838cc58fdf4bab660d292..a1003a464dc0e67830512222177426fc8034beb7 100644 (file)
@@ -24,6 +24,7 @@
 #include "common/controldata_utils.h"
 #include "funcapi.h"
 #include "miscadmin.h"
+#include "storage/lwlock.h"
 #include "utils/builtins.h"
 #include "utils/pg_lsn.h"
 #include "utils/timestamp.h"
@@ -42,7 +43,9 @@ pg_control_system(PG_FUNCTION_ARGS)
        elog(ERROR, "return type must be a row type");
 
    /* read the control file */
+   LWLockAcquire(ControlFileLock, LW_SHARED);
    ControlFile = get_controlfile(DataDir, &crc_ok);
+   LWLockRelease(ControlFileLock);
    if (!crc_ok)
        ereport(ERROR,
                (errmsg("calculated CRC checksum does not match value stored in file")));
@@ -80,7 +83,9 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
        elog(ERROR, "return type must be a row type");
 
    /* Read the control file. */
+   LWLockAcquire(ControlFileLock, LW_SHARED);
    ControlFile = get_controlfile(DataDir, &crc_ok);
+   LWLockRelease(ControlFileLock);
    if (!crc_ok)
        ereport(ERROR,
                (errmsg("calculated CRC checksum does not match value stored in file")));
@@ -169,7 +174,9 @@ pg_control_recovery(PG_FUNCTION_ARGS)
        elog(ERROR, "return type must be a row type");
 
    /* read the control file */
+   LWLockAcquire(ControlFileLock, LW_SHARED);
    ControlFile = get_controlfile(DataDir, &crc_ok);
+   LWLockRelease(ControlFileLock);
    if (!crc_ok)
        ereport(ERROR,
                (errmsg("calculated CRC checksum does not match value stored in file")));
@@ -208,7 +215,9 @@ pg_control_init(PG_FUNCTION_ARGS)
        elog(ERROR, "return type must be a row type");
 
    /* read the control file */
+   LWLockAcquire(ControlFileLock, LW_SHARED);
    ControlFile = get_controlfile(DataDir, &crc_ok);
+   LWLockRelease(ControlFileLock);
    if (!crc_ok)
        ereport(ERROR,
                (errmsg("calculated CRC checksum does not match value stored in file")));