Fix use-after-free in pgstat_fetch_stat_backend_by_pid()
authorMichael Paquier <[email protected]>
Mon, 7 Apr 2025 00:51:40 +0000 (09:51 +0900)
committerMichael Paquier <[email protected]>
Mon, 7 Apr 2025 00:51:40 +0000 (09:51 +0900)
stats_fetch_consistency set to "snapshot" causes the backend entry
"beentry" retrieved by pgstat_get_beentry_by_proc_number() to be reset
at the beginning of pgstat_fetch_stat_backend() when fetching the
backend pgstats entry.  As coded, "beentry" was being accessed after
being freed.  This commit moves all the accesses to "beentry" to happen
before calling pgstat_fetch_stat_backend(), fixing the problem.

This problem could be reached by calling the SQL functions
pg_stat_get_backend_io() or pg_stat_get_backend_wal().

Issue caught by valgrind.

Reported-by: Alexander Lakhin <[email protected]>
Author: Bertrand Drouvot <[email protected]>
Discussion: https://postgr.es/m/f1788cc0-253a-4a3a-aee0-1b8ab9538736@gmail.com

src/backend/utils/activity/pgstat_backend.c

index 187c5c76e1eda3b1c80b58e3eb571680df900d32..f6aaf589866741cadc9f8d677b84bd4a48606090 100644 (file)
@@ -133,10 +133,6 @@ pgstat_fetch_stat_backend_by_pid(int pid, BackendType *bktype)
    if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
        return NULL;
 
-   backend_stats = pgstat_fetch_stat_backend(procNumber);
-   if (!backend_stats)
-       return NULL;
-
    /* if PID does not match, leave */
    if (beentry->st_procpid != pid)
        return NULL;
@@ -144,6 +140,18 @@ pgstat_fetch_stat_backend_by_pid(int pid, BackendType *bktype)
    if (bktype)
        *bktype = beentry->st_backendType;
 
+   /*
+    * Retrieve the entry.  Note that "beentry" may be freed depending on the
+    * value of stats_fetch_consistency, so do not access it from this point.
+    */
+   backend_stats = pgstat_fetch_stat_backend(procNumber);
+   if (!backend_stats)
+   {
+       if (bktype)
+           *bktype = B_INVALID;
+       return NULL;
+   }
+
    return backend_stats;
 }