Skip to content

Commit c3e42dd

Browse files
committed
Check hypertable ownership before recompression
The SQL functions for compressing and rebuilding chunks did not verify that the caller owned the hypertable. The first-time compression path was protected by a check inside a shared helper, but the recompression paths skipped it. Any user who could read a chunk OID from the catalog could trigger a recompression on chunks owned by someone else. Add the ownership check at the entry of each affected function.
1 parent 23a6f53 commit c3e42dd

8 files changed

Lines changed: 38 additions & 0 deletions

File tree

.unreleased/pr_9800

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes: #9800 Check hypertable ownership before recompression

tsl/src/compression/api.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ tsl_compress_chunk(PG_FUNCTION_ARGS)
885885

886886
TS_PREVENT_FUNC_IF_READ_ONLY();
887887
Chunk *chunk = ts_chunk_get_by_relid(uncompressed_chunk_id, true);
888+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
888889

889890
uncompressed_chunk_id = tsl_compress_chunk_wrapper(chunk, if_not_compressed, recompress);
890891

@@ -1028,6 +1029,7 @@ tsl_rebuild_columnstore(PG_FUNCTION_ARGS)
10281029
}
10291030

10301031
Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true);
1032+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
10311033

10321034
if (!ts_chunk_is_compressed(chunk) || ts_chunk_is_frozen(chunk))
10331035
{

tsl/src/compression/recompress.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <postgres.h>
88
#include "debug_point.h"
9+
#include <miscadmin.h>
910
#include <parser/parse_coerce.h>
1011
#include <parser/parse_relation.h>
1112
#include <utils/inval.h>
@@ -22,6 +23,7 @@
2223
#include "create.h"
2324
#include "debug_assert.h"
2425
#include "guc.h"
26+
#include "hypertable.h"
2527
#include "indexing.h"
2628
#include "recompress.h"
2729
#include "ts_catalog/array_utils.h"
@@ -82,6 +84,7 @@ tsl_recompress_chunk_segmentwise(PG_FUNCTION_ARGS)
8284
ts_feature_flag_check(FEATURE_HYPERTABLE_COMPRESSION);
8385
TS_PREVENT_FUNC_IF_READ_ONLY();
8486
Chunk *chunk = ts_chunk_get_by_relid(uncompressed_chunk_id, true);
87+
ts_hypertable_permissions_check(chunk->hypertable_relid, GetUserId());
8588

8689
if (!ts_chunk_is_partial(chunk))
8790
{

tsl/test/expected/compression_permissions-15.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,15 @@ ERROR: must be owner of table conditions
5959
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
6060
SELECT compress_chunk(show_chunks('conditions'));
6161
ERROR: must be owner of hypertable "conditions"
62+
SELECT compress_chunk(show_chunks('conditions'), recompress => true);
63+
ERROR: must be owner of hypertable "conditions"
6264
SELECT decompress_chunk(show_chunks('conditions'));
6365
ERROR: must be owner of hypertable "conditions"
66+
SELECT show_chunks('conditions') AS chunk LIMIT 1 \gset
67+
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
68+
ERROR: must be owner of hypertable "conditions"
69+
SELECT _timescaledb_functions.recompress_chunk_segmentwise(show_chunks('conditions'));
70+
ERROR: must be owner of hypertable "conditions"
6471
select add_compression_policy('conditions', '1day'::interval);
6572
ERROR: must be owner of hypertable "conditions"
6673
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER

tsl/test/expected/compression_permissions-16.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,15 @@ ERROR: must be owner of table conditions
5959
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
6060
SELECT compress_chunk(show_chunks('conditions'));
6161
ERROR: must be owner of hypertable "conditions"
62+
SELECT compress_chunk(show_chunks('conditions'), recompress => true);
63+
ERROR: must be owner of hypertable "conditions"
6264
SELECT decompress_chunk(show_chunks('conditions'));
6365
ERROR: must be owner of hypertable "conditions"
66+
SELECT show_chunks('conditions') AS chunk LIMIT 1 \gset
67+
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
68+
ERROR: must be owner of hypertable "conditions"
69+
SELECT _timescaledb_functions.recompress_chunk_segmentwise(show_chunks('conditions'));
70+
ERROR: must be owner of hypertable "conditions"
6471
select add_compression_policy('conditions', '1day'::interval);
6572
ERROR: must be owner of hypertable "conditions"
6673
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER

tsl/test/expected/compression_permissions-17.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,15 @@ ERROR: must be owner of table conditions
5959
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
6060
SELECT compress_chunk(show_chunks('conditions'));
6161
ERROR: must be owner of hypertable "conditions"
62+
SELECT compress_chunk(show_chunks('conditions'), recompress => true);
63+
ERROR: must be owner of hypertable "conditions"
6264
SELECT decompress_chunk(show_chunks('conditions'));
6365
ERROR: must be owner of hypertable "conditions"
66+
SELECT show_chunks('conditions') AS chunk LIMIT 1 \gset
67+
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
68+
ERROR: must be owner of hypertable "conditions"
69+
SELECT _timescaledb_functions.recompress_chunk_segmentwise(show_chunks('conditions'));
70+
ERROR: must be owner of hypertable "conditions"
6471
select add_compression_policy('conditions', '1day'::interval);
6572
ERROR: must be owner of hypertable "conditions"
6673
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER

tsl/test/expected/compression_permissions-18.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,15 @@ ERROR: must be owner of table conditions
5959
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
6060
SELECT compress_chunk(show_chunks('conditions'));
6161
ERROR: must be owner of hypertable "conditions"
62+
SELECT compress_chunk(show_chunks('conditions'), recompress => true);
63+
ERROR: must be owner of hypertable "conditions"
6264
SELECT decompress_chunk(show_chunks('conditions'));
6365
ERROR: must be owner of hypertable "conditions"
66+
SELECT show_chunks('conditions') AS chunk LIMIT 1 \gset
67+
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
68+
ERROR: must be owner of hypertable "conditions"
69+
SELECT _timescaledb_functions.recompress_chunk_segmentwise(show_chunks('conditions'));
70+
ERROR: must be owner of hypertable "conditions"
6471
select add_compression_policy('conditions', '1day'::interval);
6572
ERROR: must be owner of hypertable "conditions"
6673
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER

tsl/test/sql/compression_permissions.sql.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ alter table conditions set (timescaledb.compress, timescaledb.compress_segmentby
6060
--- compress_chunks and decompress_chunks fail without correct perm --
6161
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER_2
6262
SELECT compress_chunk(show_chunks('conditions'));
63+
SELECT compress_chunk(show_chunks('conditions'), recompress => true);
6364
SELECT decompress_chunk(show_chunks('conditions'));
65+
SELECT show_chunks('conditions') AS chunk LIMIT 1 \gset
66+
CALL _timescaledb_functions.rebuild_columnstore(:'chunk'::regclass);
67+
SELECT _timescaledb_functions.recompress_chunk_segmentwise(show_chunks('conditions'));
6468
select add_compression_policy('conditions', '1day'::interval);
6569

6670
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER

0 commit comments

Comments
 (0)