Commit 4232c4b4 authored by Robert Haas's avatar Robert Haas

Userspace access vector cache for contrib/sepgsql.

KaiGai Kohei
parent 3d14bd25
......@@ -9481,9 +9481,9 @@ fi
# for contrib/sepgsql
if test "$with_selinux" = yes; then
{ $as_echo "$as_me:$LINENO: checking for selinux_sepgsql_context_path in -lselinux" >&5
$as_echo_n "checking for selinux_sepgsql_context_path in -lselinux... " >&6; }
if test "${ac_cv_lib_selinux_selinux_sepgsql_context_path+set}" = set; then
{ $as_echo "$as_me:$LINENO: checking for selinux_status_open in -lselinux" >&5
$as_echo_n "checking for selinux_status_open in -lselinux... " >&6; }
if test "${ac_cv_lib_selinux_selinux_status_open+set}" = set; then
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
......@@ -9501,11 +9501,11 @@ cat >>conftest.$ac_ext <<_ACEOF
#ifdef __cplusplus
extern "C"
#endif
char selinux_sepgsql_context_path ();
char selinux_status_open ();
int
main ()
{
return selinux_sepgsql_context_path ();
return selinux_status_open ();
;
return 0;
}
......@@ -9531,12 +9531,12 @@ $as_echo "$ac_try_echo") >&5
test "$cross_compiling" = yes ||
$as_test_x conftest$ac_exeext
}; then
ac_cv_lib_selinux_selinux_sepgsql_context_path=yes
ac_cv_lib_selinux_selinux_status_open=yes
else
$as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_lib_selinux_selinux_sepgsql_context_path=no
ac_cv_lib_selinux_selinux_status_open=no
fi
rm -rf conftest.dSYM
......@@ -9544,9 +9544,9 @@ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_selinux_sepgsql_context_path" >&5
$as_echo "$ac_cv_lib_selinux_selinux_sepgsql_context_path" >&6; }
if test "x$ac_cv_lib_selinux_selinux_sepgsql_context_path" = x""yes; then
{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_selinux_status_open" >&5
$as_echo "$ac_cv_lib_selinux_selinux_status_open" >&6; }
if test "x$ac_cv_lib_selinux_selinux_status_open" = x""yes; then
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBSELINUX 1
_ACEOF
......@@ -9554,8 +9554,8 @@ _ACEOF
LIBS="-lselinux $LIBS"
else
{ { $as_echo "$as_me:$LINENO: error: library 'libselinux', version 2.0.93 or newer, is required for SELinux support" >&5
$as_echo "$as_me: error: library 'libselinux', version 2.0.93 or newer, is required for SELinux support" >&2;}
{ { $as_echo "$as_me:$LINENO: error: library 'libselinux', version 2.0.99 or newer, is required for SELinux support" >&5
$as_echo "$as_me: error: library 'libselinux', version 2.0.99 or newer, is required for SELinux support" >&2;}
{ (exit 1); exit 1; }; }
fi
......
......@@ -964,8 +964,8 @@ fi
# for contrib/sepgsql
if test "$with_selinux" = yes; then
AC_CHECK_LIB(selinux, selinux_sepgsql_context_path, [],
[AC_MSG_ERROR([library 'libselinux', version 2.0.93 or newer, is required for SELinux support])])
AC_CHECK_LIB(selinux, selinux_status_open, [],
[AC_MSG_ERROR([library 'libselinux', version 2.0.99 or newer, is required for SELinux support])])
fi
# for contrib/uuid-ossp
......
# contrib/sepgsql/Makefile
MODULE_big = sepgsql
OBJS = hooks.o selinux.o label.o dml.o \
OBJS = hooks.o selinux.o uavc.o label.o dml.o \
schema.o relation.o proc.o
DATA_built = sepgsql.sql
......
......@@ -150,12 +150,11 @@ check_relation_privileges(Oid relOid,
uint32 required,
bool abort)
{
char relkind = get_rel_relkind(relOid);
char *scontext = sepgsql_get_client_label();
char *tcontext;
ObjectAddress object;
char *audit_name;
Bitmapset *columns;
int index;
char relkind = get_rel_relkind(relOid);
bool result = true;
/*
......@@ -184,45 +183,43 @@ check_relation_privileges(Oid relOid,
/*
* Check permissions on the relation
*/
tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
audit_name = getObjectDescriptionOids(RelationRelationId, relOid);
object.classId = RelationRelationId;
object.objectId = relOid;
object.objectSubId = 0;
audit_name = getObjectDescription(&object);
switch (relkind)
{
case RELKIND_RELATION:
result = sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_TABLE,
required,
audit_name,
abort);
result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_TABLE,
required,
audit_name,
abort);
break;
case RELKIND_SEQUENCE:
Assert((required & ~SEPG_DB_TABLE__SELECT) == 0);
if (required & SEPG_DB_TABLE__SELECT)
result = sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_SEQUENCE,
SEPG_DB_SEQUENCE__GET_VALUE,
audit_name,
abort);
result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SEQUENCE,
SEPG_DB_SEQUENCE__GET_VALUE,
audit_name,
abort);
break;
case RELKIND_VIEW:
result = sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_VIEW,
SEPG_DB_VIEW__EXPAND,
audit_name,
abort);
result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_VIEW,
SEPG_DB_VIEW__EXPAND,
audit_name,
abort);
break;
default:
/* nothing to be checked */
break;
}
pfree(tcontext);
pfree(audit_name);
/*
......@@ -242,7 +239,6 @@ check_relation_privileges(Oid relOid,
{
AttrNumber attnum;
uint32 column_perms = 0;
ObjectAddress object;
if (bms_is_member(index, selected))
column_perms |= SEPG_DB_COLUMN__SELECT;
......@@ -258,20 +254,17 @@ check_relation_privileges(Oid relOid,
/* obtain column's permission */
attnum = index + FirstLowInvalidHeapAttributeNumber;
tcontext = sepgsql_get_label(RelationRelationId, relOid, attnum);
object.classId = RelationRelationId;
object.objectId = relOid;
object.objectSubId = attnum;
audit_name = getObjectDescription(&object);
result = sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_COLUMN,
column_perms,
audit_name,
abort);
pfree(tcontext);
result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN,
column_perms,
audit_name,
abort);
pfree(audit_name);
if (!result)
......
......@@ -184,9 +184,7 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
static bool
sepgsql_needs_fmgr_hook(Oid functionId)
{
char *old_label;
char *new_label;
char *function_label;
ObjectAddress object;
if (next_needs_fmgr_hook &&
(*next_needs_fmgr_hook) (functionId))
......@@ -198,14 +196,8 @@ sepgsql_needs_fmgr_hook(Oid functionId)
* functions as trusted-procedure, if the security policy has a rule that
* switches security label of the client on execution.
*/
old_label = sepgsql_get_client_label();
new_label = sepgsql_proc_get_domtrans(functionId);
if (strcmp(old_label, new_label) != 0)
{
pfree(new_label);
if (sepgsql_avc_trusted_proc(functionId) != NULL)
return true;
}
pfree(new_label);
/*
* Even if not a trusted-procedure, this function should not be inlined
......@@ -213,17 +205,15 @@ sepgsql_needs_fmgr_hook(Oid functionId)
* that it shall be actually failed later because of same reason with
* ACL_EXECUTE.
*/
function_label = sepgsql_get_label(ProcedureRelationId, functionId, 0);
if (sepgsql_check_perms(sepgsql_get_client_label(),
function_label,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE,
NULL, false) != true)
{
pfree(function_label);
object.classId = ProcedureRelationId;
object.objectId = functionId;
object.objectSubId = 0;
if (!sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE,
SEPGSQL_AVC_NOAUDIT, false))
return true;
}
pfree(function_label);
return false;
}
......@@ -251,33 +241,31 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
if (!stack)
{
MemoryContext oldcxt;
const char *cur_label = sepgsql_get_client_label();
oldcxt = MemoryContextSwitchTo(flinfo->fn_mcxt);
stack = palloc(sizeof(*stack));
stack->old_label = NULL;
stack->new_label = sepgsql_proc_get_domtrans(flinfo->fn_oid);
stack->new_label = sepgsql_avc_trusted_proc(flinfo->fn_oid);
stack->next_private = 0;
MemoryContextSwitchTo(oldcxt);
if (strcmp(cur_label, stack->new_label) != 0)
{
/*
* process:transition permission between old and new
* label, when user tries to switch security label of the
* client on execution of trusted procedure.
*/
sepgsql_check_perms(cur_label, stack->new_label,
SEPG_CLASS_PROCESS,
SEPG_PROCESS__TRANSITION,
NULL, true);
}
/*
* process:transition permission between old and new label,
* when user tries to switch security label of the client
* on execution of trusted procedure.
*/
if (stack->new_label)
sepgsql_avc_check_perms_label(stack->new_label,
SEPG_CLASS_PROCESS,
SEPG_PROCESS__TRANSITION,
NULL, true);
*private = PointerGetDatum(stack);
}
Assert(!stack->old_label);
stack->old_label = sepgsql_set_client_label(stack->new_label);
if (stack->new_label)
stack->old_label = sepgsql_set_client_label(stack->new_label);
if (next_fmgr_hook)
(*next_fmgr_hook) (event, flinfo, &stack->next_private);
......@@ -290,7 +278,8 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
if (next_fmgr_hook)
(*next_fmgr_hook) (event, flinfo, &stack->next_private);
sepgsql_set_client_label(stack->old_label);
if (stack->old_label)
sepgsql_set_client_label(stack->old_label);
stack->old_label = NULL;
break;
......@@ -433,6 +422,9 @@ _PG_init(void)
errmsg("SELinux: failed to get server security label: %m")));
sepgsql_set_client_label(context);
/* Initialize userspace access vector cache */
sepgsql_avc_init();
/* Security label provider hook */
register_label_provider(SEPGSQL_LABEL_TAG,
sepgsql_object_relabel);
......
......@@ -96,64 +96,30 @@ sepgsql_proc_post_create(Oid functionId)
void
sepgsql_proc_relabel(Oid functionId, const char *seclabel)
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
char *audit_name;
ObjectAddress object;
char *audit_name;
audit_name = getObjectDescriptionOids(ProcedureRelationId, functionId);
object.classId = ProcedureRelationId;
object.objectId = functionId;
object.objectSubId = 0;
audit_name = getObjectDescription(&object);
/*
* check db_procedure:{setattr relabelfrom} permission
*/
tcontext = sepgsql_get_label(ProcedureRelationId, functionId, 0);
sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__SETATTR |
SEPG_DB_PROCEDURE__RELABELFROM,
audit_name,
true);
pfree(tcontext);
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__SETATTR |
SEPG_DB_PROCEDURE__RELABELFROM,
audit_name,
true);
/*
* check db_procedure:{relabelto} permission
*/
sepgsql_check_perms(scontext,
seclabel,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__RELABELTO,
audit_name,
true);
sepgsql_avc_check_perms_label(seclabel,
SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__RELABELTO,
audit_name,
true);
pfree(audit_name);
}
/*
* sepgsql_proc_get_domtrans
*
* It computes security label of the client that shall be applied when
* the current client invokes the supplied function.
* This computed label is either same or different from the current one.
* If security policy informed the function is a trusted-procedure,
* we need to switch security label of the client during execution of
* the function.
*
* Also note that the translated label shall be allocated using palloc().
* So, need to switch memory context, if you want to hold the string in
* someone except for CurrentMemoryContext.
*/
char *
sepgsql_proc_get_domtrans(Oid functionId)
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
char *ncontext;
tcontext = sepgsql_get_label(ProcedureRelationId, functionId, 0);
ncontext = sepgsql_compute_create(scontext,
tcontext,
SEPG_CLASS_PROCESS);
pfree(tcontext);
return ncontext;
}
......@@ -79,10 +79,8 @@ void
sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
const char *seclabel)
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
char *audit_name;
ObjectAddress object;
char *audit_name;
if (get_rel_relkind(relOid) != RELKIND_RELATION)
ereport(ERROR,
......@@ -97,26 +95,20 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
/*
* check db_column:{setattr relabelfrom} permission
*/
tcontext = sepgsql_get_label(RelationRelationId, relOid, attnum);
sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_COLUMN,
SEPG_DB_COLUMN__SETATTR |
SEPG_DB_COLUMN__RELABELFROM,
audit_name,
true);
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN,
SEPG_DB_COLUMN__SETATTR |
SEPG_DB_COLUMN__RELABELFROM,
audit_name,
true);
/*
* check db_column:{relabelto} permission
*/
sepgsql_check_perms(scontext,
seclabel,
SEPG_CLASS_DB_COLUMN,
SEPG_DB_PROCEDURE__RELABELTO,
audit_name,
true);
pfree(tcontext);
sepgsql_avc_check_perms_label(seclabel,
SEPG_CLASS_DB_COLUMN,
SEPG_DB_PROCEDURE__RELABELTO,
audit_name,
true);
pfree(audit_name);
}
......@@ -227,8 +219,7 @@ out:
void
sepgsql_relation_relabel(Oid relOid, const char *seclabel)
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
ObjectAddress object;
char *audit_name;
char relkind;
uint16_t tclass = 0;
......@@ -246,31 +237,27 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
errmsg("cannot set security labels on relations except "
"for tables, sequences or views")));
audit_name = getObjectDescriptionOids(RelationRelationId, relOid);
object.classId = RelationRelationId;
object.objectId = relOid;
object.objectSubId = 0;
audit_name = getObjectDescription(&object);
/*
* check db_xxx:{setattr relabelfrom} permission
*/
tcontext = sepgsql_get_label(RelationRelationId, relOid, 0);
sepgsql_check_perms(scontext,
tcontext,
tclass,
SEPG_DB_TABLE__SETATTR |
SEPG_DB_TABLE__RELABELFROM,
audit_name,
true);
sepgsql_avc_check_perms(&object,
tclass,
SEPG_DB_TABLE__SETATTR |
SEPG_DB_TABLE__RELABELFROM,
audit_name,
true);
/*
* check db_xxx:{relabelto} permission
*/
sepgsql_check_perms(scontext,
seclabel,
tclass,
SEPG_DB_TABLE__RELABELTO,
audit_name,
true);
pfree(tcontext);
sepgsql_avc_check_perms_label(seclabel,
tclass,
SEPG_DB_TABLE__RELABELTO,
audit_name,
true);
pfree(audit_name);
}
......@@ -65,35 +65,30 @@ sepgsql_schema_post_create(Oid namespaceId)
void
sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
char *audit_name;
ObjectAddress object;
char *audit_name;
audit_name = getObjectDescriptionOids(NamespaceRelationId, namespaceId);
object.classId = NamespaceRelationId;
object.objectId = namespaceId;
object.objectSubId = 0;
audit_name = getObjectDescription(&object);
/*
* check db_schema:{setattr relabelfrom} permission
*/
tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0);
sepgsql_check_perms(scontext,
tcontext,
SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__SETATTR |
SEPG_DB_SCHEMA__RELABELFROM,
audit_name,
true);
sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__SETATTR |
SEPG_DB_SCHEMA__RELABELFROM,
audit_name,
true);
/*
* check db_schema:{relabelto} permission
*/
sepgsql_check_perms(scontext,
seclabel,
SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__RELABELTO,
audit_name,
true);
pfree(tcontext);
sepgsql_avc_check_perms_label(seclabel,
SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__RELABELTO,
audit_name,
true);
pfree(audit_name);
}
......@@ -642,7 +642,7 @@ bool
sepgsql_getenforce(void)
{
if (sepgsql_mode == SEPGSQL_MODE_DEFAULT &&
security_getenforce() > 0)
selinux_status_getenforce() > 0)
return true;
return false;
......
......@@ -15,6 +15,7 @@
#include "fmgr.h"
#include <selinux/selinux.h>
#include <selinux/avc.h>
/*
* SE-PostgreSQL Label Tag
......@@ -245,6 +246,22 @@ extern bool sepgsql_check_perms(const char *scontext,
uint32 required,
const char *audit_name,
bool abort);
/*
* uavc.c
*/
#define SEPGSQL_AVC_NOAUDIT ((void *)(-1))
extern bool sepgsql_avc_check_perms_label(const char *tcontext,
uint16 tclass,
uint32 required,
const char *audit_name,
bool abort);
extern bool sepgsql_avc_check_perms(const ObjectAddress *tobject,
uint16 tclass,
uint32 required,
const char *audit_name,
bool abort);
extern char *sepgsql_avc_trusted_proc(Oid functionId);
extern void sepgsql_avc_init(void);
/*
* label.c
......@@ -286,6 +303,5 @@ extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
*/
extern void sepgsql_proc_post_create(Oid functionId);
extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
extern char *sepgsql_proc_get_domtrans(Oid functionId);
#endif /* SEPGSQL_H */
This diff is collapsed.
......@@ -64,7 +64,7 @@
or higher with <productname>SELinux</productname> enabled. It is not
available on any other platform, and must be explicitly enabled using
<literal>--with-selinux</>. You will also need <productname>libselinux</>
2.0.93 or higher and <productname>selinux-policy</> 3.9.13 or higher
2.0.99 or higher and <productname>selinux-policy</> 3.9.13 or higher
(some distributions may backport the necessary rules into older policy
versions).
</para>
......@@ -473,16 +473,6 @@ postgres=# SELECT cid, cname, show_credit(cid) FROM customer;
<title>Limitations</title>
<variablelist>
<varlistentry>
<term>Userspace access vector cache</term>
<listitem>
<para>
<productname>sepgsql</> does not yet support an access vector cache.
This would likely improve performance.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Data Definition Language (DDL) Permissions</term>
<listitem>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment