Skip to content

Commit cb614b3

Browse files
committed
Add missing permission checks to internal chunk functions
Several internal chunk functions were missing permission checks: - drop_chunk - drop_osm_chunk - create_compressed_chunk - freeze_chunk, unfreeze_chunk - hypertable_osm_range_update - lock_osm_chunk_dimension_slice
1 parent 517c13e commit cb614b3

11 files changed

Lines changed: 130 additions & 0 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes: #10386 Add missing permission checks to internal chunk functions

src/chunk.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,6 +4073,10 @@ ts_chunk_drop_single_chunk(PG_FUNCTION_ARGS)
40734073
CurrentMemoryContext,
40744074
true);
40754075
Assert(ch != NULL);
4076+
4077+
/* Only the hypertable owner may drop a chunk */
4078+
ts_hypertable_permissions_check(ch->hypertable_relid, GetUserId());
4079+
40764080
ts_chunk_validate_chunk_status_for_operation(ch, CHUNK_DROP, true /*throw_error */);
40774081

40784082
/* do not drop any chunk dependencies */
@@ -5289,6 +5293,9 @@ ts_chunk_drop_osm_chunk(PG_FUNCTION_ARGS)
52895293
int32 osm_chunk_id = ts_chunk_get_osm_chunk_id(ht->fd.id);
52905294
Chunk *osm_chunk = ts_chunk_get_by_id(osm_chunk_id, true);
52915295

5296+
/* Only the hypertable owner may drop the OSM chunk */
5297+
ts_hypertable_permissions_check(ht->main_table_relid, GetUserId());
5298+
52925299
ts_chunk_validate_chunk_status_for_operation(osm_chunk, CHUNK_DROP, true);
52935300

52945301
/* do not drop any chunk dependencies */

src/hypertable.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,6 +2561,9 @@ ts_hypertable_osm_range_update(PG_FUNCTION_ARGS)
25612561
quote_identifier(NameStr(ht->fd.schema_name)),
25622562
quote_identifier(NameStr(ht->fd.table_name))));
25632563
}
2564+
2565+
/* Only the hypertable owner may update the OSM chunk range */
2566+
ts_hypertable_permissions_check(ht->main_table_relid, GetUserId());
25642567
/*
25652568
* range_start, range_end arguments must be converted to internal representation
25662569
* a NULL start value is interpreted as INT64_MAX - 1 and a NULL end value is
@@ -2725,6 +2728,9 @@ ts_lock_osm_chunk_dimension_slice(PG_FUNCTION_ARGS)
27252728
quote_identifier(NameStr(ht->fd.table_name))));
27262729
}
27272730

2731+
/* Only the hypertable owner may lock the OSM chunk dimension slice */
2732+
ts_hypertable_permissions_check(ht->main_table_relid, GetUserId());
2733+
27282734
/*
27292735
* Lock the OSM chunk's dimension slice tuple FOR UPDATE. The row lock is
27302736
* held until the end of the current transaction.

test/expected/chunk_utils.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,3 +1569,19 @@ SELECT pg_typeof(_timescaledb_functions.hypertable_status_text(0));
15691569
-----------
15701570
text[]
15711571

1572+
-- A non-owner must not be able to drop a chunk via the internal drop_chunk API
1573+
\c :TEST_DBNAME :ROLE_SUPERUSER
1574+
CREATE TABLE drop_chunk_perm(time timestamptz NOT NULL);
1575+
SELECT create_hypertable('drop_chunk_perm', 'time');
1576+
create_hypertable
1577+
-------------------------------
1578+
(20,public,drop_chunk_perm,t)
1579+
1580+
INSERT INTO drop_chunk_perm VALUES ('2025-01-01');
1581+
SELECT ch AS "PERMCHUNK" FROM show_chunks('drop_chunk_perm') ch \gset
1582+
SET ROLE :ROLE_DEFAULT_PERM_USER;
1583+
\set ON_ERROR_STOP 0
1584+
SELECT _timescaledb_functions.drop_chunk(:'PERMCHUNK');
1585+
ERROR: must be owner of hypertable "drop_chunk_perm"
1586+
\set ON_ERROR_STOP 1
1587+
RESET ROLE;

test/sql/chunk_utils.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,3 +699,15 @@ SELECT _timescaledb_functions.hypertable_status('pg_class'::regclass);
699699
-- Test that function exists and returns an array type
700700
SELECT pg_typeof(_timescaledb_functions.hypertable_status_text(0));
701701

702+
-- A non-owner must not be able to drop a chunk via the internal drop_chunk API
703+
\c :TEST_DBNAME :ROLE_SUPERUSER
704+
CREATE TABLE drop_chunk_perm(time timestamptz NOT NULL);
705+
SELECT create_hypertable('drop_chunk_perm', 'time');
706+
INSERT INTO drop_chunk_perm VALUES ('2025-01-01');
707+
SELECT ch AS "PERMCHUNK" FROM show_chunks('drop_chunk_perm') ch \gset
708+
SET ROLE :ROLE_DEFAULT_PERM_USER;
709+
\set ON_ERROR_STOP 0
710+
SELECT _timescaledb_functions.drop_chunk(:'PERMCHUNK');
711+
\set ON_ERROR_STOP 1
712+
RESET ROLE;
713+

tsl/src/chunk.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ chunk_freeze_chunk(PG_FUNCTION_ARGS)
4747
TS_PREVENT_FUNC_IF_READ_ONLY();
4848
Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true);
4949
Assert(chunk != NULL);
50+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
5051
if (chunk->relkind == RELKIND_FOREIGN_TABLE)
5152
{
5253
ereport(ERROR,
@@ -75,6 +76,7 @@ chunk_unfreeze_chunk(PG_FUNCTION_ARGS)
7576
TS_PREVENT_FUNC_IF_READ_ONLY();
7677
Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true);
7778
Assert(chunk != NULL);
79+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
7880
if (chunk->relkind == RELKIND_FOREIGN_TABLE)
7981
{
8082
ereport(ERROR,

tsl/src/compression/api.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,7 @@ tsl_create_compressed_chunk(PG_FUNCTION_ARGS)
842842
TS_PREVENT_FUNC_IF_READ_ONLY();
843843

844844
chunk = ts_chunk_get_by_relid(chunk_relid, true);
845+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
845846
hcache = ts_hypertable_cache_pin();
846847
compresschunkcxt_init(&cxt, hcache, chunk->hypertable_relid, chunk_relid);
847848

tsl/test/expected/chunk_utils_internal.out

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,15 @@ ERROR: must be owner of hypertable "ht_try"
868868
CREATE TABLE non_ht (time bigint, temp float);
869869
SELECT _timescaledb_functions.attach_osm_table_chunk('non_ht', 'child_fdw_table');
870870
ERROR: "non_ht" is not a hypertable
871+
-- TEST error have to be hypertable owner to drop the OSM chunk
872+
SELECT _timescaledb_functions.drop_osm_chunk('ht_try');
873+
ERROR: must be owner of hypertable "ht_try"
874+
-- TEST error have to be hypertable owner to update the OSM chunk range
875+
SELECT _timescaledb_functions.hypertable_osm_range_update('ht_try', NULL::timestamptz, NULL::timestamptz);
876+
ERROR: must be owner of hypertable "ht_try"
877+
-- TEST error have to be hypertable owner to lock the OSM chunk dimension slice
878+
SELECT _timescaledb_functions.lock_osm_chunk_dimension_slice('ht_try');
879+
ERROR: must be owner of hypertable "ht_try"
871880
-- TEST drop OSM chunk
872881
\c :TEST_DBNAME :ROLE_4
873882
-- We need the OSM chunk for other tests so we run the test in a single
@@ -1886,3 +1895,22 @@ SELECT compress_chunk(ch) FROM show_chunks('metrics') ch;
18861895
ERROR: chunk "_timescaledb_internal._hyper_25_43_chunk" is frozen, skipping compression
18871896
ROLLBACK;
18881897
\set ON_ERROR_STOP 1
1898+
-- A non-owner must not be able to freeze or unfreeze a chunk
1899+
\c :TEST_DBNAME :ROLE_SUPERUSER
1900+
CREATE TABLE freeze_perm(time timestamptz NOT NULL);
1901+
SELECT create_hypertable('freeze_perm', 'time');
1902+
create_hypertable
1903+
---------------------------
1904+
(26,public,freeze_perm,t)
1905+
1906+
INSERT INTO freeze_perm VALUES ('2025-01-01');
1907+
SELECT ch AS "FREEZECHUNK" FROM show_chunks('freeze_perm') ch \gset
1908+
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
1909+
\set ON_ERROR_STOP 0
1910+
SELECT _timescaledb_functions.freeze_chunk(:'FREEZECHUNK');
1911+
ERROR: must be owner of hypertable "freeze_perm"
1912+
SELECT _timescaledb_functions.unfreeze_chunk(:'FREEZECHUNK');
1913+
ERROR: must be owner of hypertable "freeze_perm"
1914+
\set ON_ERROR_STOP 1
1915+
\c :TEST_DBNAME :ROLE_SUPERUSER
1916+
DROP TABLE freeze_perm;

tsl/test/expected/compression_create_compressed_table.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,20 @@ SELECT count(*) FROM "_timescaledb_internal"."_hyper_1_1_chunk";
6363
-------
6464
2
6565

66+
-- A non-owner must not be able to attach a compressed chunk
67+
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
68+
\set ON_ERROR_STOP 0
69+
SELECT _timescaledb_functions.create_compressed_chunk(
70+
'"_timescaledb_internal"."_hyper_1_1_chunk"'::TEXT::REGCLASS,
71+
'"_timescaledb_internal"."custom_compressed_chunk"'::TEXT::REGCLASS,
72+
8192,
73+
8192,
74+
16384,
75+
8192,
76+
8192,
77+
16384,
78+
1,
79+
1
80+
);
81+
ERROR: must be owner of hypertable "metrics"
82+
\set ON_ERROR_STOP 1

tsl/test/sql/chunk_utils_internal.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,15 @@ SELECT _timescaledb_functions.attach_osm_table_chunk('ht_try', 'child_fdw_table'
535535
CREATE TABLE non_ht (time bigint, temp float);
536536
SELECT _timescaledb_functions.attach_osm_table_chunk('non_ht', 'child_fdw_table');
537537

538+
-- TEST error have to be hypertable owner to drop the OSM chunk
539+
SELECT _timescaledb_functions.drop_osm_chunk('ht_try');
540+
541+
-- TEST error have to be hypertable owner to update the OSM chunk range
542+
SELECT _timescaledb_functions.hypertable_osm_range_update('ht_try', NULL::timestamptz, NULL::timestamptz);
543+
544+
-- TEST error have to be hypertable owner to lock the OSM chunk dimension slice
545+
SELECT _timescaledb_functions.lock_osm_chunk_dimension_slice('ht_try');
546+
538547
-- TEST drop OSM chunk
539548
\c :TEST_DBNAME :ROLE_4
540549
-- We need the OSM chunk for other tests so we run the test in a single
@@ -1037,3 +1046,17 @@ SELECT _timescaledb_functions.freeze_chunk(chunk) FROM show_chunks('metrics') ch
10371046
SELECT compress_chunk(ch) FROM show_chunks('metrics') ch;
10381047
ROLLBACK;
10391048
\set ON_ERROR_STOP 1
1049+
1050+
-- A non-owner must not be able to freeze or unfreeze a chunk
1051+
\c :TEST_DBNAME :ROLE_SUPERUSER
1052+
CREATE TABLE freeze_perm(time timestamptz NOT NULL);
1053+
SELECT create_hypertable('freeze_perm', 'time');
1054+
INSERT INTO freeze_perm VALUES ('2025-01-01');
1055+
SELECT ch AS "FREEZECHUNK" FROM show_chunks('freeze_perm') ch \gset
1056+
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
1057+
\set ON_ERROR_STOP 0
1058+
SELECT _timescaledb_functions.freeze_chunk(:'FREEZECHUNK');
1059+
SELECT _timescaledb_functions.unfreeze_chunk(:'FREEZECHUNK');
1060+
\set ON_ERROR_STOP 1
1061+
\c :TEST_DBNAME :ROLE_SUPERUSER
1062+
DROP TABLE freeze_perm;

0 commit comments

Comments
 (0)