Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
e1042a34
Commit
e1042a34
authored
Dec 21, 2011
by
Robert Haas
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sepgsql: Check CREATE permissions for some object types.
KaiGai Kohei, reviewed by Dimitri Fontaine and me.
parent
7f0e4bb8
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
608 additions
and
85 deletions
+608
-85
contrib/sepgsql/database.c
contrib/sepgsql/database.c
+79
-12
contrib/sepgsql/expected/create.out
contrib/sepgsql/expected/create.out
+80
-0
contrib/sepgsql/hooks.c
contrib/sepgsql/hooks.c
+155
-37
contrib/sepgsql/proc.c
contrib/sepgsql/proc.c
+49
-6
contrib/sepgsql/relation.c
contrib/sepgsql/relation.c
+121
-23
contrib/sepgsql/schema.c
contrib/sepgsql/schema.c
+46
-4
contrib/sepgsql/sepgsql.h
contrib/sepgsql/sepgsql.h
+2
-1
contrib/sepgsql/sql/create.sql
contrib/sepgsql/sql/create.sql
+46
-0
contrib/sepgsql/test_sepgsql
contrib/sepgsql/test_sepgsql
+1
-1
doc/src/sgml/sepgsql.sgml
doc/src/sgml/sepgsql.sgml
+29
-1
No files found.
contrib/sepgsql/database.c
View file @
e1042a34
...
...
@@ -10,33 +10,100 @@
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/pg_database.h"
#include "catalog/indexing.h"
#include "commands/dbcommands.h"
#include "commands/seclabel.h"
#include "utils/fmgroids.h"
#include "utils/tqual.h"
#include "sepgsql.h"
/*
* sepgsql_database_post_create
*
* This routine assigns a default security label on a newly defined
* database, and check permission needed for its creation.
*/
void
sepgsql_database_post_create
(
Oid
databaseId
)
sepgsql_database_post_create
(
Oid
databaseId
,
const
char
*
dtemplate
)
{
char
*
scontext
=
sepgsql_get_client_label
();
char
*
tcontext
;
char
*
ncontext
;
ObjectAddress
object
;
Relation
rel
;
ScanKeyData
skey
;
SysScanDesc
sscan
;
HeapTuple
tuple
;
char
*
tcontext
;
char
*
ncontext
;
char
audit_name
[
NAMEDATALEN
+
20
];
ObjectAddress
object
;
Form_pg_database
datForm
;
/*
* Oid of the source database is not saved in pg_database catalog,
* so we collect its identifier using contextual information.
* If NULL, its default is "template1" according to createdb().
*/
if
(
!
dtemplate
)
dtemplate
=
"template1"
;
object
.
classId
=
DatabaseRelationId
;
object
.
objectId
=
get_database_oid
(
dtemplate
,
false
);
object
.
objectSubId
=
0
;
tcontext
=
sepgsql_get_label
(
object
.
classId
,
object
.
objectId
,
object
.
objectSubId
);
/*
* check db_database:{getattr} permission
*/
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"database %s"
,
dtemplate
);
sepgsql_avc_check_perms_label
(
tcontext
,
SEPG_CLASS_DB_DATABASE
,
SEPG_DB_DATABASE__GETATTR
,
audit_name
,
true
);
/*
* Compute a default security label of the newly created database
* based on a pair of security label of client and source database.
*
* XXX -
Right now, this logic uses "template1" as its source, because
*
here is no way to know the Oid of source database
.
* XXX -
uncoming version of libselinux supports to take object
*
name to handle special treatment on default security label
.
*/
object
.
classId
=
DatabaseRelationId
;
object
.
objectId
=
TemplateDbOid
;
object
.
objectSubId
=
0
;
tcontext
=
GetSecurityLabel
(
&
object
,
SEPGSQL_LABEL_TAG
);
rel
=
heap_open
(
DatabaseRelationId
,
AccessShareLock
);
ScanKeyInit
(
&
skey
,
ObjectIdAttributeNumber
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
databaseId
));
sscan
=
systable_beginscan
(
rel
,
DatabaseOidIndexId
,
true
,
SnapshotSelf
,
1
,
&
skey
);
tuple
=
systable_getnext
(
sscan
);
if
(
!
HeapTupleIsValid
(
tuple
))
elog
(
ERROR
,
"catalog lookup failed for database %u"
,
databaseId
);
datForm
=
(
Form_pg_database
)
GETSTRUCT
(
tuple
);
ncontext
=
sepgsql_compute_create
(
scontext
,
tcontext
,
ncontext
=
sepgsql_compute_create
(
sepgsql_get_client_label
(),
tcontext
,
SEPG_CLASS_DB_DATABASE
);
/*
* check db_database:{create} permission
*/
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"database %s"
,
NameStr
(
datForm
->
datname
));
sepgsql_avc_check_perms_label
(
ncontext
,
SEPG_CLASS_DB_DATABASE
,
SEPG_DB_DATABASE__CREATE
,
audit_name
,
true
);
systable_endscan
(
sscan
);
heap_close
(
rel
,
AccessShareLock
);
/*
* Assign the default security label on the new database
...
...
contrib/sepgsql/expected/create.out
0 → 100644
View file @
e1042a34
--
-- Regression Test for Creation of Object Permission Checks
--
-- confirm required permissions using audit messages
SELECT sepgsql_getcon(); -- confirm client privilege
sepgsql_getcon
-------------------------------------------
unconfined_u:unconfined_r:unconfined_t:s0
(1 row)
SET sepgsql.debug_audit = true;
SET client_min_messages = LOG;
CREATE DATABASE regtest_sepgsql_test_database;
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"
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"
CREATE SCHEMA regtest_schema;
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"
SET search_path = regtest_schema, public;
CREATE TABLE regtest_table (x serial primary key, y text);
NOTICE: CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for table "regtest_table"
ALTER TABLE regtest_table ADD COLUMN z int;
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"
CREATE TABLE regtest_table_2 (a int) WITH OIDS;
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
-- corresponding toast table should not have label and permission checks
ALTER TABLE regtest_table_2 ADD COLUMN b text;
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"
-- VACUUM FULL internally create a new table and swap them later.
VACUUM FULL regtest_table;
CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 100;
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"
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"
CREATE SEQUENCE regtest_seq;
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"
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"
CREATE TYPE regtest_comptype AS (a int, b text);
CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
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"
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[])"
CREATE AGGREGATE regtest_agg (
sfunc1 = int4pl, basetype = int4, stype1 = int4, initcond1 = '0'
);
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"
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)"
--
-- clean-up
--
DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
DROP SCHEMA IF EXISTS regtest_schema CASCADE;
NOTICE: drop cascades to 7 other objects
DETAIL: drop cascades to table regtest_table
drop cascades to table regtest_table_2
drop cascades to view regtest_view
drop cascades to sequence regtest_seq
drop cascades to type regtest_comptype
drop cascades to function regtest_func(text,integer[])
drop cascades to function regtest_agg(integer)
contrib/sepgsql/hooks.c
View file @
e1042a34
...
...
@@ -41,6 +41,23 @@ static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
static
needs_fmgr_hook_type
next_needs_fmgr_hook
=
NULL
;
static
fmgr_hook_type
next_fmgr_hook
=
NULL
;
static
ProcessUtility_hook_type
next_ProcessUtility_hook
=
NULL
;
static
ExecutorStart_hook_type
next_ExecutorStart_hook
=
NULL
;
/*
* Contextual information on DDL commands
*/
typedef
struct
{
NodeTag
cmdtype
;
/*
* Name of the template database given by users on CREATE DATABASE
* command. Elsewhere (including the case of default) NULL.
*/
const
char
*
createdb_dtemplate
;
}
sepgsql_context_info_t
;
static
sepgsql_context_info_t
sepgsql_context_info
;
/*
* GUC: sepgsql.permissive = (on|off)
...
...
@@ -127,7 +144,8 @@ sepgsql_object_access(ObjectAccessType access,
switch
(
classId
)
{
case
DatabaseRelationId
:
sepgsql_database_post_create
(
objectId
);
sepgsql_database_post_create
(
objectId
,
sepgsql_context_info
.
createdb_dtemplate
);
break
;
case
NamespaceRelationId
:
...
...
@@ -136,7 +154,30 @@ sepgsql_object_access(ObjectAccessType access,
case
RelationRelationId
:
if
(
subId
==
0
)
sepgsql_relation_post_create
(
objectId
);
{
/*
* All cases we want to apply permission checks on
* creation of a new relation are invocation of the
* heap_create_with_catalog via DefineRelation or
* OpenIntoRel.
* Elsewhere, we need neither assignment of security
* label nor permission checks.
*/
switch
(
sepgsql_context_info
.
cmdtype
)
{
case
T_CreateStmt
:
case
T_ViewStmt
:
case
T_CreateSeqStmt
:
case
T_CompositeTypeStmt
:
case
T_CreateForeignTableStmt
:
case
T_SelectStmt
:
sepgsql_relation_post_create
(
objectId
);
break
;
default:
/* via make_new_heap() */
break
;
}
}
else
sepgsql_attribute_post_create
(
objectId
,
subId
);
break
;
...
...
@@ -294,6 +335,46 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
}
}
/*
* sepgsql_executor_start
*
* It saves contextual information during ExecutorStart to distinguish
* a case with/without permission checks later.
*/
static
void
sepgsql_executor_start
(
QueryDesc
*
queryDesc
,
int
eflags
)
{
sepgsql_context_info_t
saved_context_info
=
sepgsql_context_info
;
PG_TRY
();
{
if
(
queryDesc
->
operation
==
CMD_SELECT
)
sepgsql_context_info
.
cmdtype
=
T_SelectStmt
;
else
if
(
queryDesc
->
operation
==
CMD_INSERT
)
sepgsql_context_info
.
cmdtype
=
T_InsertStmt
;
else
if
(
queryDesc
->
operation
==
CMD_DELETE
)
sepgsql_context_info
.
cmdtype
=
T_DeleteStmt
;
else
if
(
queryDesc
->
operation
==
CMD_UPDATE
)
sepgsql_context_info
.
cmdtype
=
T_UpdateStmt
;
/*
* XXX - If queryDesc->operation is not above four cases, an error
* shall be raised on the following executor stage soon.
*/
if
(
next_ExecutorStart_hook
)
(
*
next_ExecutorStart_hook
)
(
queryDesc
,
eflags
);
else
standard_ExecutorStart
(
queryDesc
,
eflags
);
}
PG_CATCH
();
{
sepgsql_context_info
=
saved_context_info
;
PG_RE_THROW
();
}
PG_END_TRY
();
sepgsql_context_info
=
saved_context_info
;
}
/*
* sepgsql_utility_command
*
...
...
@@ -308,44 +389,74 @@ sepgsql_utility_command(Node *parsetree,
DestReceiver
*
dest
,
char
*
completionTag
)
{
if
(
next_ProcessUtility_hook
)
(
*
next_ProcessUtility_hook
)
(
parsetree
,
queryString
,
params
,
isTopLevel
,
dest
,
completionTag
);
sepgsql_context_info_t
saved_context_info
=
sepgsql_context_info
;
ListCell
*
cell
;
/*
* Check command tag to avoid nefarious operations
*/
switch
(
nodeTag
(
parsetree
))
PG_TRY
();
{
case
T_LoadStmt
:
/*
* We reject LOAD command across the board on enforcing mode,
* because a binary module can arbitrarily override hooks.
*/
if
(
sepgsql_getenforce
())
{
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INSUFFICIENT_PRIVILEGE
),
errmsg
(
"SELinux: LOAD is not permitted"
)));
}
break
;
default:
/*
* Right now we don't check any other utility commands, because it
* needs more detailed information to make access control decision
* here, but we don't want to have two parse and analyze routines
* individually.
*/
break
;
/*
* Check command tag to avoid nefarious operations, and save the
* current contextual information to determine whether we should
* apply permission checks here, or not.
*/
sepgsql_context_info
.
cmdtype
=
nodeTag
(
parsetree
);
switch
(
nodeTag
(
parsetree
))
{
case
T_CreatedbStmt
:
/*
* We hope to reference name of the source database, but it
* does not appear in system catalog. So, we save it here.
*/
foreach
(
cell
,
((
CreatedbStmt
*
)
parsetree
)
->
options
)
{
DefElem
*
defel
=
(
DefElem
*
)
lfirst
(
cell
);
if
(
strcmp
(
defel
->
defname
,
"template"
)
==
0
)
{
sepgsql_context_info
.
createdb_dtemplate
=
strVal
(
defel
->
arg
);
break
;
}
}
break
;
case
T_LoadStmt
:
/*
* We reject LOAD command across the board on enforcing mode,
* because a binary module can arbitrarily override hooks.
*/
if
(
sepgsql_getenforce
())
{
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INSUFFICIENT_PRIVILEGE
),
errmsg
(
"SELinux: LOAD is not permitted"
)));
}
break
;
default:
/*
* Right now we don't check any other utility commands,
* because it needs more detailed information to make access
* control decision here, but we don't want to have two parse
* and analyze routines individually.
*/
break
;
}
if
(
next_ProcessUtility_hook
)
(
*
next_ProcessUtility_hook
)
(
parsetree
,
queryString
,
params
,
isTopLevel
,
dest
,
completionTag
);
else
standard_ProcessUtility
(
parsetree
,
queryString
,
params
,
isTopLevel
,
dest
,
completionTag
);
}
/*
* Original implementation
*/
standard_ProcessUtility
(
parsetree
,
queryString
,
params
,
isTopLevel
,
dest
,
completionTag
);
PG_CATCH
();
{
sepgsql_context_info
=
saved_context_info
;
PG_RE_THROW
();
}
PG_END_TRY
();
sepgsql_context_info
=
saved_context_info
;
}
/*
...
...
@@ -456,4 +567,11 @@ _PG_init(void)
/* ProcessUtility hook */
next_ProcessUtility_hook
=
ProcessUtility_hook
;
ProcessUtility_hook
=
sepgsql_utility_command
;
/* ExecutorStart hook */
next_ExecutorStart_hook
=
ExecutorStart_hook
;
ExecutorStart_hook
=
sepgsql_executor_start
;
/* init contextual info */
memset
(
&
sepgsql_context_info
,
0
,
sizeof
(
sepgsql_context_info
));
}
contrib/sepgsql/proc.c
View file @
e1042a34
...
...
@@ -18,6 +18,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "commands/seclabel.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/tqual.h"
...
...
@@ -37,11 +38,13 @@ sepgsql_proc_post_create(Oid functionId)
ScanKeyData
skey
;
SysScanDesc
sscan
;
HeapTuple
tuple
;
Oid
namespaceId
;
ObjectAddress
object
;
char
*
scontext
;
char
*
tcontext
;
char
*
ncontext
;
int
i
;
StringInfoData
audit_name
;
ObjectAddress
object
;
Form_pg_proc
proForm
;
/*
* Fetch namespace of the new procedure. Because pg_proc entry is not
...
...
@@ -61,20 +64,53 @@ sepgsql_proc_post_create(Oid functionId)
if
(
!
HeapTupleIsValid
(
tuple
))
elog
(
ERROR
,
"catalog lookup failed for proc %u"
,
functionId
);
namespaceId
=
((
Form_pg_proc
)
GETSTRUCT
(
tuple
))
->
pronamespace
;
proForm
=
(
Form_pg_proc
)
GETSTRUCT
(
tuple
);
/*
* check db_schema:{add_name} permission of the namespace
*/
object
.
classId
=
NamespaceRelationId
;
object
.
objectId
=
proForm
->
pronamespace
;
object
.
objectSubId
=
0
;
sepgsql_avc_check_perms
(
&
object
,
SEPG_CLASS_DB_SCHEMA
,
SEPG_DB_SCHEMA__ADD_NAME
,
getObjectDescription
(
&
object
),
true
);
/*
* XXX - db_language:{implement} also should be checked here
*/
systable_endscan
(
sscan
);
heap_close
(
rel
,
AccessShareLock
);
/*
* Compute a default security label when we create a new procedure object
* under the specified namespace.
*/
scontext
=
sepgsql_get_client_label
();
tcontext
=
sepgsql_get_label
(
NamespaceRelationId
,
namespaceId
,
0
);
tcontext
=
sepgsql_get_label
(
NamespaceRelationId
,
proForm
->
pronamespace
,
0
);
ncontext
=
sepgsql_compute_create
(
scontext
,
tcontext
,
SEPG_CLASS_DB_PROCEDURE
);
/*
* check db_procedure:{create} permission
*/
initStringInfo
(
&
audit_name
);
appendStringInfo
(
&
audit_name
,
"function %s("
,
NameStr
(
proForm
->
proname
));
for
(
i
=
0
;
i
<
proForm
->
pronargs
;
i
++
)
{
Oid
typeoid
=
proForm
->
proargtypes
.
values
[
i
];
if
(
i
>
0
)
appendStringInfoChar
(
&
audit_name
,
','
);
appendStringInfoString
(
&
audit_name
,
format_type_be
(
typeoid
));
}
appendStringInfoChar
(
&
audit_name
,
')'
);
sepgsql_avc_check_perms_label
(
ncontext
,
SEPG_CLASS_DB_PROCEDURE
,
SEPG_DB_PROCEDURE__CREATE
,
audit_name
.
data
,
true
);
/*
* Assign the default security label on a new procedure
*/
...
...
@@ -83,6 +119,13 @@ sepgsql_proc_post_create(Oid functionId)
object
.
objectSubId
=
0
;
SetSecurityLabel
(
&
object
,
SEPGSQL_LABEL_TAG
,
ncontext
);
/*
* Cleanup
*/
systable_endscan
(
sscan
);
heap_close
(
rel
,
AccessShareLock
);
pfree
(
audit_name
.
data
);
pfree
(
tcontext
);
pfree
(
ncontext
);
}
...
...
contrib/sepgsql/relation.c
View file @
e1042a34
...
...
@@ -36,10 +36,16 @@
void
sepgsql_attribute_post_create
(
Oid
relOid
,
AttrNumber
attnum
)
{
char
*
scontext
=
sepgsql_get_client_label
();
Relation
rel
;
ScanKeyData
skey
[
2
];
SysScanDesc
sscan
;
HeapTuple
tuple
;
char
*
scontext
;
char
*
tcontext
;
char
*
ncontext
;
char
audit_name
[
2
*
NAMEDATALEN
+
20
];
ObjectAddress
object
;
Form_pg_attribute
attForm
;
/*
* Only attributes within regular relation have individual security
...
...
@@ -49,13 +55,44 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
return
;
/*
* Compute a default security label
when we create a new procedure object
*
under the specified namespace
.
* Compute a default security label
of the new column underlying the
*
specified relation, and check permission to create it
.
*/
rel
=
heap_open
(
AttributeRelationId
,
AccessShareLock
);
ScanKeyInit
(
&
skey
[
0
],
Anum_pg_attribute_attrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
relOid
));
ScanKeyInit
(
&
skey
[
1
],
Anum_pg_attribute_attnum
,
BTEqualStrategyNumber
,
F_INT2EQ
,
Int16GetDatum
(
attnum
));
sscan
=
systable_beginscan
(
rel
,
AttributeRelidNumIndexId
,
true
,
SnapshotSelf
,
2
,
&
skey
[
0
]);
tuple
=
systable_getnext
(
sscan
);
if
(
!
HeapTupleIsValid
(
tuple
))
elog
(
ERROR
,
"catalog lookup failed for column %d of relation %u"
,
attnum
,
relOid
);
attForm
=
(
Form_pg_attribute
)
GETSTRUCT
(
tuple
);
scontext
=
sepgsql_get_client_label
();
tcontext
=
sepgsql_get_label
(
RelationRelationId
,
relOid
,
0
);
ncontext
=
sepgsql_compute_create
(
scontext
,
tcontext
,
SEPG_CLASS_DB_COLUMN
);
/*
* check db_column:{create} permission
*/
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"table %s column %s"
,
get_rel_name
(
relOid
),
NameStr
(
attForm
->
attname
));
sepgsql_avc_check_perms_label
(
ncontext
,
SEPG_CLASS_DB_COLUMN
,
SEPG_DB_COLUMN__CREATE
,
audit_name
,
true
);
/*
* Assign the default security label on a new procedure
...
...
@@ -65,6 +102,9 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
object
.
objectSubId
=
attnum
;
SetSecurityLabel
(
&
object
,
SEPGSQL_LABEL_TAG
,
ncontext
);
systable_endscan
(
sscan
);
heap_close
(
rel
,
AccessShareLock
);
pfree
(
tcontext
);
pfree
(
ncontext
);
}
...
...
@@ -127,10 +167,12 @@ sepgsql_relation_post_create(Oid relOid)
Form_pg_class
classForm
;
ObjectAddress
object
;
uint16
tclass
;
const
char
*
tclass_text
;
char
*
scontext
;
/* subject */
char
*
tcontext
;
/* schema */
char
*
rcontext
;
/* relation */
char
*
ccontext
;
/* column */
char
audit_name
[
2
*
NAMEDATALEN
+
20
];
/*
* Fetch catalog record of the new relation. Because pg_class entry is not
...
...
@@ -152,15 +194,35 @@ sepgsql_relation_post_create(Oid relOid)
classForm
=
(
Form_pg_class
)
GETSTRUCT
(
tuple
);
if
(
classForm
->
relkind
==
RELKIND_RELATION
)
tclass
=
SEPG_CLASS_DB_TABLE
;
else
if
(
classForm
->
relkind
==
RELKIND_SEQUENCE
)
tclass
=
SEPG_CLASS_DB_SEQUENCE
;
else
if
(
classForm
->
relkind
==
RELKIND_VIEW
)
tclass
=
SEPG_CLASS_DB_VIEW
;
else
goto
out
;
/* No need to assign individual labels */
switch
(
classForm
->
relkind
)
{
case
RELKIND_RELATION
:
tclass
=
SEPG_CLASS_DB_TABLE
;
tclass_text
=
"table"
;
break
;
case
RELKIND_SEQUENCE
:
tclass
=
SEPG_CLASS_DB_SEQUENCE
;
tclass_text
=
"sequence"
;
break
;
case
RELKIND_VIEW
:
tclass
=
SEPG_CLASS_DB_VIEW
;
tclass_text
=
"view"
;
break
;
default:
goto
out
;
}
/*
* check db_schema:{add_name} permission of the namespace
*/
object
.
classId
=
NamespaceRelationId
;
object
.
objectId
=
classForm
->
relnamespace
;
object
.
objectSubId
=
0
;
sepgsql_avc_check_perms
(
&
object
,
SEPG_CLASS_DB_SCHEMA
,
SEPG_DB_SCHEMA__ADD_NAME
,
getObjectDescription
(
&
object
),
true
);
/*
* Compute a default security label when we create a new relation object
* under the specified namespace.
...
...
@@ -170,6 +232,16 @@ sepgsql_relation_post_create(Oid relOid)
classForm
->
relnamespace
,
0
);
rcontext
=
sepgsql_compute_create
(
scontext
,
tcontext
,
tclass
);
/*
* check db_xxx:{create} permission
*/
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"%s %s"
,
tclass_text
,
NameStr
(
classForm
->
relname
));
sepgsql_avc_check_perms_label
(
rcontext
,
tclass
,
SEPG_DB_DATABASE__CREATE
,
audit_name
,
true
);
/*
* Assign the default security label on the new relation
*/
...
...
@@ -184,26 +256,52 @@ sepgsql_relation_post_create(Oid relOid)
*/
if
(
classForm
->
relkind
==
RELKIND_RELATION
)
{
AttrNumber
index
;
Relation
arel
;
ScanKeyData
akey
;
SysScanDesc
ascan
;
HeapTuple
atup
;
Form_pg_attribute
attForm
;
ccontext
=
sepgsql_compute_create
(
scontext
,
rcontext
,
SEPG_CLASS_DB_COLUMN
);
for
(
index
=
FirstLowInvalidHeapAttributeNumber
+
1
;
index
<=
classForm
->
relnatts
;
index
++
)
arel
=
heap_open
(
AttributeRelationId
,
AccessShareLock
);
ScanKeyInit
(
&
akey
,
Anum_pg_attribute_attrelid
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
relOid
));
ascan
=
systable_beginscan
(
arel
,
AttributeRelidNumIndexId
,
true
,
SnapshotSelf
,
1
,
&
akey
);
while
(
HeapTupleIsValid
(
atup
=
systable_getnext
(
ascan
)))
{
if
(
index
==
InvalidAttrNumber
)
continue
;
attForm
=
(
Form_pg_attribute
)
GETSTRUCT
(
atup
);
if
(
index
==
ObjectIdAttributeNumber
&&
!
classForm
->
relhasoids
)
continue
;
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"%s %s column %s"
,
tclass_text
,
NameStr
(
classForm
->
relname
),
NameStr
(
attForm
->
attname
));
ccontext
=
sepgsql_compute_create
(
scontext
,
rcontext
,
SEPG_CLASS_DB_COLUMN
);
/*
* check db_column:{create} permission
*/
sepgsql_avc_check_perms_label
(
ccontext
,
SEPG_CLASS_DB_COLUMN
,
SEPG_DB_COLUMN__CREATE
,
audit_name
,
true
);
object
.
classId
=
RelationRelationId
;
object
.
objectId
=
relOid
;
object
.
objectSubId
=
index
;
object
.
objectSubId
=
attForm
->
attnum
;
SetSecurityLabel
(
&
object
,
SEPGSQL_LABEL_TAG
,
ccontext
);
pfree
(
ccontext
);
}
pfree
(
ccontext
);
systable_endscan
(
ascan
);
heap_close
(
arel
,
AccessShareLock
);
}
pfree
(
rcontext
);
out:
...
...
contrib/sepgsql/schema.c
View file @
e1042a34
...
...
@@ -10,12 +10,18 @@
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "commands/seclabel.h"
#include "miscadmin.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/tqual.h"
#include "sepgsql.h"
...
...
@@ -28,19 +34,55 @@
void
sepgsql_schema_post_create
(
Oid
namespaceId
)
{
char
*
scontext
;
Relation
rel
;
ScanKeyData
skey
;
SysScanDesc
sscan
;
HeapTuple
tuple
;
char
*
tcontext
;
char
*
ncontext
;
ObjectAddress
object
;
char
audit_name
[
NAMEDATALEN
+
20
];
ObjectAddress
object
;
Form_pg_namespace
nspForm
;
/*
* Compute a default security label when we create a new schema object
* under the working database.
*
* XXX - uncoming version of libselinux supports to take object
* name to handle special treatment on default security label;
* such as special label on "pg_temp" schema.
*/
scontext
=
sepgsql_get_client_label
();
rel
=
heap_open
(
NamespaceRelationId
,
AccessShareLock
);
ScanKeyInit
(
&
skey
,
ObjectIdAttributeNumber
,
BTEqualStrategyNumber
,
F_OIDEQ
,
ObjectIdGetDatum
(
namespaceId
));
sscan
=
systable_beginscan
(
rel
,
NamespaceOidIndexId
,
true
,
SnapshotSelf
,
1
,
&
skey
);
tuple
=
systable_getnext
(
sscan
);
if
(
!
HeapTupleIsValid
(
tuple
))
elog
(
ERROR
,
"catalog lookup failed for namespace %u"
,
namespaceId
);
nspForm
=
(
Form_pg_namespace
)
GETSTRUCT
(
tuple
);
tcontext
=
sepgsql_get_label
(
DatabaseRelationId
,
MyDatabaseId
,
0
);
ncontext
=
sepgsql_compute_create
(
scontext
,
tcontext
,
ncontext
=
sepgsql_compute_create
(
sepgsql_get_client_label
(),
tcontext
,
SEPG_CLASS_DB_SCHEMA
);
/*
* check db_schema:{create}
*/
snprintf
(
audit_name
,
sizeof
(
audit_name
),
"schema %s"
,
NameStr
(
nspForm
->
nspname
));
sepgsql_avc_check_perms_label
(
ncontext
,
SEPG_CLASS_DB_SCHEMA
,
SEPG_DB_SCHEMA__CREATE
,
audit_name
,
true
);
systable_endscan
(
sscan
);
heap_close
(
rel
,
AccessShareLock
);
/*
* Assign the default security label on a new procedure
...
...
contrib/sepgsql/sepgsql.h
View file @
e1042a34
...
...
@@ -286,7 +286,8 @@ extern bool sepgsql_dml_privileges(List *rangeTabls, bool abort);
/*
* database.c
*/
extern
void
sepgsql_database_post_create
(
Oid
databaseId
);
extern
void
sepgsql_database_post_create
(
Oid
databaseId
,
const
char
*
dtemplate
);
extern
void
sepgsql_database_relabel
(
Oid
databaseId
,
const
char
*
seclabel
);
/*
...
...
contrib/sepgsql/sql/create.sql
0 → 100644
View file @
e1042a34
--
-- Regression Test for Creation of Object Permission Checks
--
-- confirm required permissions using audit messages
-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0
SET
sepgsql
.
debug_audit
=
true
;
SET
client_min_messages
=
LOG
;
CREATE
DATABASE
regtest_sepgsql_test_database
;
CREATE
SCHEMA
regtest_schema
;
SET
search_path
=
regtest_schema
,
public
;
CREATE
TABLE
regtest_table
(
x
serial
primary
key
,
y
text
);
ALTER
TABLE
regtest_table
ADD
COLUMN
z
int
;
CREATE
TABLE
regtest_table_2
(
a
int
)
WITH
OIDS
;
-- corresponding toast table should not have label and permission checks
ALTER
TABLE
regtest_table_2
ADD
COLUMN
b
text
;
-- VACUUM FULL internally create a new table and swap them later.
VACUUM
FULL
regtest_table
;
CREATE
VIEW
regtest_view
AS
SELECT
*
FROM
regtest_table
WHERE
x
<
100
;
CREATE
SEQUENCE
regtest_seq
;
CREATE
TYPE
regtest_comptype
AS
(
a
int
,
b
text
);
CREATE
FUNCTION
regtest_func
(
text
,
int
[])
RETURNS
bool
LANGUAGE
plpgsql
AS
'BEGIN RAISE NOTICE
''
regtest_func => %
''
, $1; RETURN true; END'
;
CREATE
AGGREGATE
regtest_agg
(
sfunc1
=
int4pl
,
basetype
=
int4
,
stype1
=
int4
,
initcond1
=
'0'
);
--
-- clean-up
--
DROP
DATABASE
IF
EXISTS
regtest_sepgsql_test_database
;
DROP
SCHEMA
IF
EXISTS
regtest_schema
CASCADE
;
contrib/sepgsql/test_sepgsql
View file @
e1042a34
...
...
@@ -259,6 +259,6 @@ echo "found ${NUM}"
echo
echo
"============== running sepgsql regression tests =============="
make
REGRESS
=
"label dml misc"
REGRESS_OPTS
=
"--launcher ./launcher"
installcheck
make
REGRESS
=
"label dml
create
misc"
REGRESS_OPTS
=
"--launcher ./launcher"
installcheck
# exit with the exit code provided by "make"
doc/src/sgml/sepgsql.sgml
View file @
e1042a34
...
...
@@ -420,6 +420,33 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
<sect3>
<title>DDL Permissions</title>
<para>
<productname>SELinux</> defines several permissions to control common
operations for each object types; such as creation, alter, drop and
relabel of security label. In addition, several object types has its
special permissions to control its characteristic operations; such as
addition or deletion of name entries underlying a particular schema.
</para>
<para>
When <literal>CREATE</> command is executed, <literal>create</> will
be checked on the object being constructed for each object types.
A default security label shall be assigned on the new database object,
and the <literal>create</> permission needs to be allowed on the pair
of security label of the client and the new object itself.
We consider <xref linkend="sql-createtable"> construct a table and
underlying columns at the same time, so it requires users permission
to create both of table and columns.
</para>
<para>
A few additional checks are applied depending on object types.
On <xref linkend="sql-createdatabase">, <literal>getattr</> permission
shall be checked on the source or template database of the new database,
not only <literal>create</> on the new database.
On creation of objects underlying a particula schema (tables, views,
sequences and procedures), <literal>add_name</> shall be also chechked
on the schema, not only <literal>create</> on the new object itself.
</para>
<para>
When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
and <literal>relabelfrom</> will be checked on the object being relabeled
...
...
@@ -509,7 +536,8 @@ postgres=# SELECT cid, cname, show_credit(cid) FROM customer;
<term>Data Definition Language (DDL) Permissions</term>
<listitem>
<para>
Due to implementation restrictions, DDL permissions are not checked.
Due to implementation restrictions, some of DDL permissions are not
checked.
</para>
</listitem>
</varlistentry>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment