mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-14 00:42:54 +00:00
Add the migration for fixing CVE-2024-4317
At some point in the future, we can disable this migration because only databases created prior to Neon supporting 14.12, 15.7, and 16.3 will have this vulnerability. Link: https://www.postgresql.org/support/security/CVE-2024-4317/ Signed-off-by: Tristan Partin <tristan@neon.tech>
This commit is contained in:
@@ -31,7 +31,6 @@ pub(crate) enum Migration<'m> {
|
||||
/// a new database, that database will not receive the migration, but we
|
||||
/// will have marked the migration as completed successfully, assuming all
|
||||
/// previous databases ran the migration to completion.
|
||||
#[expect(dead_code)]
|
||||
PerDatabase(&'m str),
|
||||
}
|
||||
|
||||
|
||||
235
compute_tools/src/migrations/0012-fix-CVE-2024-4317.sql
Normal file
235
compute_tools/src/migrations/0012-fix-CVE-2024-4317.sql
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* fix-CVE-2024-4317.sql
|
||||
*
|
||||
* Copyright (c) 2024, PostgreSQL Global Development Group
|
||||
*
|
||||
* src/backend/catalog/fix-CVE-2024-4317.sql
|
||||
*
|
||||
* This file should be run in every database in the cluster to address
|
||||
* CVE-2024-4317.
|
||||
*/
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
server_version_num numeric;
|
||||
BEGIN
|
||||
SET search_path = pg_catalog;
|
||||
|
||||
SELECT setting::numeric FROM pg_settings INTO server_version_num WHERE name = 'server_version_num';
|
||||
|
||||
-- Everything after Postgres 17 will have the fix
|
||||
IF server_version_num >= 170000 THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
-- pg_statistic_ext_data doesn't have the stxdinherit column in 14 and below
|
||||
IF server_version_num < 150000 THEN
|
||||
CREATE OR REPLACE VIEW pg_stats_ext WITH (security_barrier) AS
|
||||
SELECT cn.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
sn.nspname AS statistics_schemaname,
|
||||
s.stxname AS statistics_name,
|
||||
pg_get_userbyid(s.stxowner) AS statistics_owner,
|
||||
( SELECT array_agg(a.attname ORDER BY a.attnum)
|
||||
FROM unnest(s.stxkeys) k
|
||||
JOIN pg_attribute a
|
||||
ON (a.attrelid = s.stxrelid AND a.attnum = k)
|
||||
) AS attnames,
|
||||
pg_get_statisticsobjdef_expressions(s.oid) as exprs,
|
||||
s.stxkind AS kinds,
|
||||
sd.stxdndistinct AS n_distinct,
|
||||
sd.stxddependencies AS dependencies,
|
||||
m.most_common_vals,
|
||||
m.most_common_val_nulls,
|
||||
m.most_common_freqs,
|
||||
m.most_common_base_freqs
|
||||
FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid)
|
||||
JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid)
|
||||
LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace)
|
||||
LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace)
|
||||
LEFT JOIN LATERAL
|
||||
( SELECT array_agg(values) AS most_common_vals,
|
||||
array_agg(nulls) AS most_common_val_nulls,
|
||||
array_agg(frequency) AS most_common_freqs,
|
||||
array_agg(base_frequency) AS most_common_base_freqs
|
||||
FROM pg_mcv_list_items(sd.stxdmcv)
|
||||
) m ON sd.stxdmcv IS NOT NULL
|
||||
WHERE pg_has_role(c.relowner, 'USAGE')
|
||||
AND (c.relrowsecurity = false OR NOT row_security_active(c.oid));
|
||||
|
||||
CREATE OR REPLACE VIEW pg_stats_ext_exprs WITH (security_barrier) AS
|
||||
SELECT cn.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
sn.nspname AS statistics_schemaname,
|
||||
s.stxname AS statistics_name,
|
||||
pg_get_userbyid(s.stxowner) AS statistics_owner,
|
||||
stat.expr,
|
||||
(stat.a).stanullfrac AS null_frac,
|
||||
(stat.a).stawidth AS avg_width,
|
||||
(stat.a).stadistinct AS n_distinct,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 1 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 1 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 1 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 1 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 1 THEN (stat.a).stavalues5
|
||||
END) AS most_common_vals,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 1 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 1 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 1 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 1 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 1 THEN (stat.a).stanumbers5
|
||||
END) AS most_common_freqs,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 2 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 2 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 2 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 2 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 2 THEN (stat.a).stavalues5
|
||||
END) AS histogram_bounds,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 3 THEN (stat.a).stanumbers1[1]
|
||||
WHEN (stat.a).stakind2 = 3 THEN (stat.a).stanumbers2[1]
|
||||
WHEN (stat.a).stakind3 = 3 THEN (stat.a).stanumbers3[1]
|
||||
WHEN (stat.a).stakind4 = 3 THEN (stat.a).stanumbers4[1]
|
||||
WHEN (stat.a).stakind5 = 3 THEN (stat.a).stanumbers5[1]
|
||||
END) correlation,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 4 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 4 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 4 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 4 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 4 THEN (stat.a).stavalues5
|
||||
END) AS most_common_elems,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 4 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 4 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 4 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 4 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 4 THEN (stat.a).stanumbers5
|
||||
END) AS most_common_elem_freqs,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 5 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 5 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 5 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 5 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 5 THEN (stat.a).stanumbers5
|
||||
END) AS elem_count_histogram
|
||||
FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid)
|
||||
LEFT JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid)
|
||||
LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace)
|
||||
LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace)
|
||||
JOIN LATERAL (
|
||||
SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr,
|
||||
unnest(sd.stxdexpr)::pg_statistic AS a
|
||||
) stat ON (stat.expr IS NOT NULL)
|
||||
WHERE pg_has_role(c.relowner, 'USAGE')
|
||||
AND (c.relrowsecurity = false OR NOT row_security_active(c.oid));
|
||||
ELSE
|
||||
CREATE OR REPLACE VIEW pg_stats_ext WITH (security_barrier) AS
|
||||
SELECT cn.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
sn.nspname AS statistics_schemaname,
|
||||
s.stxname AS statistics_name,
|
||||
pg_get_userbyid(s.stxowner) AS statistics_owner,
|
||||
( SELECT array_agg(a.attname ORDER BY a.attnum)
|
||||
FROM unnest(s.stxkeys) k
|
||||
JOIN pg_attribute a
|
||||
ON (a.attrelid = s.stxrelid AND a.attnum = k)
|
||||
) AS attnames,
|
||||
pg_get_statisticsobjdef_expressions(s.oid) as exprs,
|
||||
s.stxkind AS kinds,
|
||||
sd.stxdinherit AS inherited,
|
||||
sd.stxdndistinct AS n_distinct,
|
||||
sd.stxddependencies AS dependencies,
|
||||
m.most_common_vals,
|
||||
m.most_common_val_nulls,
|
||||
m.most_common_freqs,
|
||||
m.most_common_base_freqs
|
||||
FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid)
|
||||
JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid)
|
||||
LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace)
|
||||
LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace)
|
||||
LEFT JOIN LATERAL
|
||||
( SELECT array_agg(values) AS most_common_vals,
|
||||
array_agg(nulls) AS most_common_val_nulls,
|
||||
array_agg(frequency) AS most_common_freqs,
|
||||
array_agg(base_frequency) AS most_common_base_freqs
|
||||
FROM pg_mcv_list_items(sd.stxdmcv)
|
||||
) m ON sd.stxdmcv IS NOT NULL
|
||||
WHERE pg_has_role(c.relowner, 'USAGE')
|
||||
AND (c.relrowsecurity = false OR NOT row_security_active(c.oid));
|
||||
|
||||
CREATE OR REPLACE VIEW pg_stats_ext_exprs WITH (security_barrier) AS
|
||||
SELECT cn.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
sn.nspname AS statistics_schemaname,
|
||||
s.stxname AS statistics_name,
|
||||
pg_get_userbyid(s.stxowner) AS statistics_owner,
|
||||
stat.expr,
|
||||
sd.stxdinherit AS inherited,
|
||||
(stat.a).stanullfrac AS null_frac,
|
||||
(stat.a).stawidth AS avg_width,
|
||||
(stat.a).stadistinct AS n_distinct,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 1 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 1 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 1 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 1 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 1 THEN (stat.a).stavalues5
|
||||
END) AS most_common_vals,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 1 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 1 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 1 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 1 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 1 THEN (stat.a).stanumbers5
|
||||
END) AS most_common_freqs,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 2 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 2 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 2 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 2 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 2 THEN (stat.a).stavalues5
|
||||
END) AS histogram_bounds,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 3 THEN (stat.a).stanumbers1[1]
|
||||
WHEN (stat.a).stakind2 = 3 THEN (stat.a).stanumbers2[1]
|
||||
WHEN (stat.a).stakind3 = 3 THEN (stat.a).stanumbers3[1]
|
||||
WHEN (stat.a).stakind4 = 3 THEN (stat.a).stanumbers4[1]
|
||||
WHEN (stat.a).stakind5 = 3 THEN (stat.a).stanumbers5[1]
|
||||
END) correlation,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 4 THEN (stat.a).stavalues1
|
||||
WHEN (stat.a).stakind2 = 4 THEN (stat.a).stavalues2
|
||||
WHEN (stat.a).stakind3 = 4 THEN (stat.a).stavalues3
|
||||
WHEN (stat.a).stakind4 = 4 THEN (stat.a).stavalues4
|
||||
WHEN (stat.a).stakind5 = 4 THEN (stat.a).stavalues5
|
||||
END) AS most_common_elems,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 4 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 4 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 4 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 4 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 4 THEN (stat.a).stanumbers5
|
||||
END) AS most_common_elem_freqs,
|
||||
(CASE
|
||||
WHEN (stat.a).stakind1 = 5 THEN (stat.a).stanumbers1
|
||||
WHEN (stat.a).stakind2 = 5 THEN (stat.a).stanumbers2
|
||||
WHEN (stat.a).stakind3 = 5 THEN (stat.a).stanumbers3
|
||||
WHEN (stat.a).stakind4 = 5 THEN (stat.a).stanumbers4
|
||||
WHEN (stat.a).stakind5 = 5 THEN (stat.a).stanumbers5
|
||||
END) AS elem_count_histogram
|
||||
FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid)
|
||||
LEFT JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid)
|
||||
LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace)
|
||||
LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace)
|
||||
JOIN LATERAL (
|
||||
SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr,
|
||||
unnest(sd.stxdexpr)::pg_statistic AS a
|
||||
) stat ON (stat.expr IS NOT NULL)
|
||||
WHERE pg_has_role(c.relowner, 'USAGE')
|
||||
AND (c.relrowsecurity = false OR NOT row_security_active(c.oid));
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Testing that this migration actually works would require spinning up a
|
||||
-- Postgres instance running on a vulnerable version. Let's trust that the
|
||||
-- Postgres community created a SQL fix that actually works.
|
||||
|
||||
SELECT 1;
|
||||
@@ -209,6 +209,7 @@ pub async fn handle_migrations(config: Config) -> Result<()> {
|
||||
Migration::Cluster(include_str!(
|
||||
"./migrations/0011-grant_pg_show_replication_origin_status_to_neon_superuser.sql"
|
||||
)),
|
||||
Migration::PerDatabase(include_str!("./migrations/0012-fix-CVE-2024-4317.sql")),
|
||||
];
|
||||
|
||||
let runner = match MigrationRunner::new(config, &migrations) {
|
||||
|
||||
Reference in New Issue
Block a user