Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e1042a3

Browse files
committed
sepgsql: Check CREATE permissions for some object types.
KaiGai Kohei, reviewed by Dimitri Fontaine and me.
1 parent 7f0e4bb commit e1042a3

File tree

10 files changed

+608
-85
lines changed

10 files changed

+608
-85
lines changed

contrib/sepgsql/database.c

+79-12
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,100 @@
1010
*/
1111
#include "postgres.h"
1212

13+
#include "access/genam.h"
14+
#include "access/heapam.h"
15+
#include "access/sysattr.h"
1316
#include "catalog/dependency.h"
1417
#include "catalog/pg_database.h"
18+
#include "catalog/indexing.h"
19+
#include "commands/dbcommands.h"
1520
#include "commands/seclabel.h"
21+
#include "utils/fmgroids.h"
22+
#include "utils/tqual.h"
1623
#include "sepgsql.h"
1724

25+
/*
26+
* sepgsql_database_post_create
27+
*
28+
* This routine assigns a default security label on a newly defined
29+
* database, and check permission needed for its creation.
30+
*/
1831
void
19-
sepgsql_database_post_create(Oid databaseId)
32+
sepgsql_database_post_create(Oid databaseId, const char *dtemplate)
2033
{
21-
char *scontext = sepgsql_get_client_label();
22-
char *tcontext;
23-
char *ncontext;
24-
ObjectAddress object;
34+
Relation rel;
35+
ScanKeyData skey;
36+
SysScanDesc sscan;
37+
HeapTuple tuple;
38+
char *tcontext;
39+
char *ncontext;
40+
char audit_name[NAMEDATALEN + 20];
41+
ObjectAddress object;
42+
Form_pg_database datForm;
43+
44+
/*
45+
* Oid of the source database is not saved in pg_database catalog,
46+
* so we collect its identifier using contextual information.
47+
* If NULL, its default is "template1" according to createdb().
48+
*/
49+
if (!dtemplate)
50+
dtemplate = "template1";
51+
52+
object.classId = DatabaseRelationId;
53+
object.objectId = get_database_oid(dtemplate, false);
54+
object.objectSubId = 0;
55+
56+
tcontext = sepgsql_get_label(object.classId,
57+
object.objectId,
58+
object.objectSubId);
59+
/*
60+
* check db_database:{getattr} permission
61+
*/
62+
snprintf(audit_name, sizeof(audit_name), "database %s", dtemplate);
63+
sepgsql_avc_check_perms_label(tcontext,
64+
SEPG_CLASS_DB_DATABASE,
65+
SEPG_DB_DATABASE__GETATTR,
66+
audit_name,
67+
true);
2568

2669
/*
2770
* Compute a default security label of the newly created database
2871
* based on a pair of security label of client and source database.
2972
*
30-
* XXX - Right now, this logic uses "template1" as its source, because
31-
* here is no way to know the Oid of source database.
73+
* XXX - uncoming version of libselinux supports to take object
74+
* name to handle special treatment on default security label.
3275
*/
33-
object.classId = DatabaseRelationId;
34-
object.objectId = TemplateDbOid;
35-
object.objectSubId = 0;
36-
tcontext = GetSecurityLabel(&object, SEPGSQL_LABEL_TAG);
76+
rel = heap_open(DatabaseRelationId, AccessShareLock);
77+
78+
ScanKeyInit(&skey,
79+
ObjectIdAttributeNumber,
80+
BTEqualStrategyNumber, F_OIDEQ,
81+
ObjectIdGetDatum(databaseId));
82+
83+
sscan = systable_beginscan(rel, DatabaseOidIndexId, true,
84+
SnapshotSelf, 1, &skey);
85+
tuple = systable_getnext(sscan);
86+
if (!HeapTupleIsValid(tuple))
87+
elog(ERROR, "catalog lookup failed for database %u", databaseId);
88+
89+
datForm = (Form_pg_database) GETSTRUCT(tuple);
3790

38-
ncontext = sepgsql_compute_create(scontext, tcontext,
91+
ncontext = sepgsql_compute_create(sepgsql_get_client_label(),
92+
tcontext,
3993
SEPG_CLASS_DB_DATABASE);
94+
/*
95+
* check db_database:{create} permission
96+
*/
97+
snprintf(audit_name, sizeof(audit_name),
98+
"database %s", NameStr(datForm->datname));
99+
sepgsql_avc_check_perms_label(ncontext,
100+
SEPG_CLASS_DB_DATABASE,
101+
SEPG_DB_DATABASE__CREATE,
102+
audit_name,
103+
true);
104+
105+
systable_endscan(sscan);
106+
heap_close(rel, AccessShareLock);
40107

41108
/*
42109
* Assign the default security label on the new database

contrib/sepgsql/expected/create.out

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--
2+
-- Regression Test for Creation of Object Permission Checks
3+
--
4+
-- confirm required permissions using audit messages
5+
SELECT sepgsql_getcon(); -- confirm client privilege
6+
sepgsql_getcon
7+
-------------------------------------------
8+
unconfined_u:unconfined_r:unconfined_t:s0
9+
(1 row)
10+
11+
SET sepgsql.debug_audit = true;
12+
SET client_min_messages = LOG;
13+
CREATE DATABASE regtest_sepgsql_test_database;
14+
LOG: SELinux: allowed { getattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=system_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database template1"
15+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database"
16+
CREATE SCHEMA regtest_schema;
17+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
18+
SET search_path = regtest_schema, public;
19+
CREATE TABLE regtest_table (x serial primary key, y text);
20+
NOTICE: CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x"
21+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
22+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq"
23+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
24+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
25+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
26+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
27+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmax"
28+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmin"
29+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmin"
30+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
31+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
32+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
33+
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for table "regtest_table"
34+
ALTER TABLE regtest_table ADD COLUMN z int;
35+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column z"
36+
CREATE TABLE regtest_table_2 (a int) WITH OIDS;
37+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
38+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_2"
39+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column tableoid"
40+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmax"
41+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmax"
42+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column cmin"
43+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column xmin"
44+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column oid"
45+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column ctid"
46+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column a"
47+
-- corresponding toast table should not have label and permission checks
48+
ALTER TABLE regtest_table_2 ADD COLUMN b text;
49+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
50+
-- VACUUM FULL internally create a new table and swap them later.
51+
VACUUM FULL regtest_table;
52+
CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
53+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
54+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view"
55+
CREATE SEQUENCE regtest_seq;
56+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
57+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
58+
CREATE TYPE regtest_comptype AS (a int, b text);
59+
CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
60+
AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
61+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
62+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text,integer[])"
63+
CREATE AGGREGATE regtest_agg (
64+
sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
65+
);
66+
LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
67+
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg(integer)"
68+
--
69+
-- clean-up
70+
--
71+
DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
72+
DROP SCHEMA IF EXISTS regtest_schema CASCADE;
73+
NOTICE: drop cascades to 7 other objects
74+
DETAIL: drop cascades to table regtest_table
75+
drop cascades to table regtest_table_2
76+
drop cascades to view regtest_view
77+
drop cascades to sequence regtest_seq
78+
drop cascades to type regtest_comptype
79+
drop cascades to function regtest_func(text,integer[])
80+
drop cascades to function regtest_agg(integer)

0 commit comments

Comments
 (0)