#include "postgres.h"#include "access/hash.h"#include "catalog/pg_proc.h"#include "commands/seclabel.h"#include "storage/ipc.h"#include "utils/guc.h"#include "utils/memutils.h"#include "sepgsql.h"
Go to the source code of this file.
Data Structures | |
| struct | avc_cache |
Defines | |
| #define | AVC_NUM_SLOTS 512 |
| #define | AVC_NUM_RECLAIM 16 |
| #define | AVC_DEF_THRESHOLD 384 |
Functions | |
| static uint32 | sepgsql_avc_hash (const char *scontext, const char *tcontext, uint16 tclass) |
| static void | sepgsql_avc_reset (void) |
| static void | sepgsql_avc_reclaim (void) |
| static bool | sepgsql_avc_check_valid (void) |
| static char * | sepgsql_avc_unlabeled (void) |
| static avc_cache * | sepgsql_avc_compute (const char *scontext, const char *tcontext, uint16 tclass) |
| static avc_cache * | sepgsql_avc_lookup (const char *scontext, const char *tcontext, uint16 tclass) |
| bool | sepgsql_avc_check_perms_label (const char *tcontext, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation) |
| bool | sepgsql_avc_check_perms (const ObjectAddress *tobject, uint16 tclass, uint32 required, const char *audit_name, bool abort_on_violation) |
| char * | sepgsql_avc_trusted_proc (Oid functionId) |
| static void | sepgsql_avc_exit (int code, Datum arg) |
| void | sepgsql_avc_init (void) |
Variables | |
| static MemoryContext | avc_mem_cxt |
| static List * | avc_slots [AVC_NUM_SLOTS] |
| static int | avc_num_caches |
| static int | avc_lru_hint |
| static int | avc_threshold |
| static char * | avc_unlabeled |
| #define AVC_NUM_RECLAIM 16 |
Definition at line 54 of file uavc.c.
Referenced by sepgsql_avc_reclaim().
| #define AVC_NUM_SLOTS 512 |
Definition at line 53 of file uavc.c.
Referenced by sepgsql_avc_reclaim(), and sepgsql_avc_reset().
| bool sepgsql_avc_check_perms | ( | const ObjectAddress * | tobject, | |
| uint16 | tclass, | |||
| uint32 | required, | |||
| const char * | audit_name, | |||
| bool | abort_on_violation | |||
| ) |
Definition at line 428 of file uavc.c.
References GetSecurityLabel(), pfree(), sepgsql_avc_check_perms_label(), and SEPGSQL_LABEL_TAG.
Referenced by check_relation_privileges(), check_schema_perms(), sepgsql_attribute_drop(), sepgsql_attribute_relabel(), sepgsql_attribute_setattr(), sepgsql_database_drop(), sepgsql_database_relabel(), sepgsql_database_setattr(), sepgsql_fmgr_hook(), sepgsql_needs_fmgr_hook(), sepgsql_proc_drop(), sepgsql_proc_execute(), sepgsql_proc_post_create(), sepgsql_proc_relabel(), sepgsql_proc_setattr(), sepgsql_relation_drop(), sepgsql_relation_post_create(), sepgsql_relation_relabel(), sepgsql_relation_setattr(), sepgsql_schema_drop(), and sepgsql_schema_relabel().
{
char *tcontext = GetSecurityLabel(tobject, SEPGSQL_LABEL_TAG);
bool rc;
rc = sepgsql_avc_check_perms_label(tcontext,
tclass, required,
audit_name, abort_on_violation);
if (tcontext)
pfree(tcontext);
return rc;
}
| bool sepgsql_avc_check_perms_label | ( | const char * | tcontext, | |
| uint16 | tclass, | |||
| uint32 | required, | |||
| const char * | audit_name, | |||
| bool | abort_on_violation | |||
| ) |
Definition at line 346 of file uavc.c.
References avc_cache::allowed, avc_cache::auditallow, avc_cache::auditdeny, ereport, errcode(), errmsg(), ERROR, avc_cache::permissive, avc_cache::scontext, sepgsql_audit_log(), sepgsql_avc_check_valid(), sepgsql_avc_lookup(), SEPGSQL_AVC_NOAUDIT, sepgsql_avc_unlabeled(), sepgsql_get_client_label(), sepgsql_get_debug_audit(), sepgsql_get_mode(), sepgsql_getenforce(), SEPGSQL_MODE_INTERNAL, avc_cache::tclass, avc_cache::tcontext, and avc_cache::tcontext_is_valid.
Referenced by sepgsql_attribute_post_create(), sepgsql_attribute_relabel(), sepgsql_avc_check_perms(), sepgsql_database_post_create(), sepgsql_database_relabel(), sepgsql_fmgr_hook(), sepgsql_proc_post_create(), sepgsql_proc_relabel(), sepgsql_relation_post_create(), sepgsql_relation_relabel(), sepgsql_schema_post_create(), sepgsql_schema_relabel(), and sepgsql_set_client_label().
{
char *scontext = sepgsql_get_client_label();
avc_cache *cache;
uint32 denied;
uint32 audited;
bool result;
sepgsql_avc_check_valid();
do
{
result = true;
/*
* If the target object is unlabeled, we perform the check using the
* label supplied by sepgsql_avc_unlabeled().
*/
if (tcontext)
cache = sepgsql_avc_lookup(scontext, tcontext, tclass);
else
cache = sepgsql_avc_lookup(scontext,
sepgsql_avc_unlabeled(), tclass);
denied = required & ~cache->allowed;
/*
* Compute permissions to be audited
*/
if (sepgsql_get_debug_audit())
audited = (denied ? (denied & ~0) : (required & ~0));
else
audited = denied ? (denied & cache->auditdeny)
: (required & cache->auditallow);
if (denied)
{
/*
* In permissive mode or permissive domain, violated permissions
* shall be audited to the log files at once, and then implicitly
* allowed to avoid a flood of access denied logs, because the
* purpose of permissive mode/domain is to collect a violation log
* that will make it possible to fix up the security policy.
*/
if (!sepgsql_getenforce() || cache->permissive)
cache->allowed |= required;
else
result = false;
}
} while (!sepgsql_avc_check_valid());
/*
* In the case when we have something auditable actions here,
* sepgsql_audit_log shall be called with text representation of security
* labels for both of subject and object. It records this access
* violation, so DBA will be able to find out unexpected security problems
* later.
*/
if (audited != 0 &&
audit_name != SEPGSQL_AVC_NOAUDIT &&
sepgsql_get_mode() != SEPGSQL_MODE_INTERNAL)
{
sepgsql_audit_log(!!denied,
cache->scontext,
cache->tcontext_is_valid ?
cache->tcontext : sepgsql_avc_unlabeled(),
cache->tclass,
audited,
audit_name);
}
if (abort_on_violation && !result)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("SELinux: security policy violation")));
return result;
}
| static bool sepgsql_avc_check_valid | ( | void | ) | [static] |
Definition at line 158 of file uavc.c.
References sepgsql_avc_reset().
Referenced by sepgsql_avc_check_perms_label(), and sepgsql_avc_trusted_proc().
{
if (selinux_status_updated() > 0)
{
sepgsql_avc_reset();
return false;
}
return true;
}
| static avc_cache* sepgsql_avc_compute | ( | const char * | scontext, | |
| const char * | tcontext, | |||
| uint16 | tclass | |||
| ) | [static] |
Definition at line 209 of file uavc.c.
References avc_cache::allowed, avc_cache::auditallow, avc_cache::auditdeny, avc_num_caches, avc_threshold, avc_cache::hash, avc_cache::hot_cache, lcons(), MemoryContextSwitchTo(), avc_cache::ncontext, NULL, palloc0(), avc_cache::permissive, pfree(), pstrdup(), avc_cache::scontext, SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_PROCESS, sepgsql_avc_hash(), sepgsql_avc_reclaim(), sepgsql_avc_unlabeled(), sepgsql_compute_avd(), sepgsql_compute_create(), avc_cache::tclass, avc_cache::tcontext, and avc_cache::tcontext_is_valid.
Referenced by sepgsql_avc_lookup().
{
char *ucontext = NULL;
char *ncontext = NULL;
MemoryContext oldctx;
avc_cache *cache;
uint32 hash;
int index;
struct av_decision avd;
hash = sepgsql_avc_hash(scontext, tcontext, tclass);
index = hash % AVC_NUM_SLOTS;
/*
* Validation check of the supplied security context. Because it always
* invoke system-call, frequent check should be avoided. Unless security
* policy is reloaded, validation status shall be kept, so we also cache
* whether the supplied security context was valid, or not.
*/
if (security_check_context_raw((security_context_t) tcontext) != 0)
ucontext = sepgsql_avc_unlabeled();
/*
* Ask SELinux its access control decision
*/
if (!ucontext)
sepgsql_compute_avd(scontext, tcontext, tclass, &avd);
else
sepgsql_compute_avd(scontext, ucontext, tclass, &avd);
/*
* It also caches a security label to be switched when a client labeled as
* 'scontext' executes a procedure labeled as 'tcontext', not only access
* control decision on the procedure. The security label to be switched
* shall be computed uniquely on a pair of 'scontext' and 'tcontext',
* thus, it is reasonable to cache the new label on avc, and enables to
* reduce unnecessary system calls. It shall be referenced at
* sepgsql_needs_fmgr_hook to check whether the supplied function is a
* trusted procedure, or not.
*/
if (tclass == SEPG_CLASS_DB_PROCEDURE)
{
if (!ucontext)
ncontext = sepgsql_compute_create(scontext, tcontext,
SEPG_CLASS_PROCESS, NULL);
else
ncontext = sepgsql_compute_create(scontext, ucontext,
SEPG_CLASS_PROCESS, NULL);
if (strcmp(scontext, ncontext) == 0)
{
pfree(ncontext);
ncontext = NULL;
}
}
/*
* Set up an avc_cache object
*/
oldctx = MemoryContextSwitchTo(avc_mem_cxt);
cache = palloc0(sizeof(avc_cache));
cache->hash = hash;
cache->scontext = pstrdup(scontext);
cache->tcontext = pstrdup(tcontext);
cache->tclass = tclass;
cache->allowed = avd.allowed;
cache->auditallow = avd.auditallow;
cache->auditdeny = avd.auditdeny;
cache->hot_cache = true;
if (avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE)
cache->permissive = true;
if (!ucontext)
cache->tcontext_is_valid = true;
if (ncontext)
cache->ncontext = pstrdup(ncontext);
avc_num_caches++;
if (avc_num_caches > avc_threshold)
sepgsql_avc_reclaim();
avc_slots[index] = lcons(cache, avc_slots[index]);
MemoryContextSwitchTo(oldctx);
return cache;
}
| static void sepgsql_avc_exit | ( | int | code, | |
| Datum | arg | |||
| ) | [static] |
Definition at line 485 of file uavc.c.
Referenced by sepgsql_avc_init().
{
selinux_status_close();
}
| static uint32 sepgsql_avc_hash | ( | const char * | scontext, | |
| const char * | tcontext, | |||
| uint16 | tclass | |||
| ) | [static] |
Definition at line 68 of file uavc.c.
References hash_any().
Referenced by sepgsql_avc_compute(), and sepgsql_avc_lookup().
| void sepgsql_avc_init | ( | void | ) |
Definition at line 496 of file uavc.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), avc_lru_hint, avc_num_caches, avc_threshold, ereport, errcode(), errmsg(), ERROR, LOG, on_proc_exit(), sepgsql_avc_exit(), and TopMemoryContext.
Referenced by _PG_init().
{
int rc;
/*
* All the avc stuff shall be allocated on avc_mem_cxt
*/
avc_mem_cxt = AllocSetContextCreate(TopMemoryContext,
"userspace access vector cache",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
memset(avc_slots, 0, sizeof(avc_slots));
avc_num_caches = 0;
avc_lru_hint = 0;
avc_threshold = AVC_DEF_THRESHOLD;
/*
* SELinux allows to mmap(2) its kernel status page in read-only mode to
* inform userspace applications its status updating (such as policy
* reloading) without system-call invocations. This feature is only
* supported in Linux-2.6.38 or later, however, libselinux provides a
* fallback mode to know its status using netlink sockets.
*/
rc = selinux_status_open(1);
if (rc < 0)
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("SELinux: could not open selinux status : %m")));
else if (rc > 0)
ereport(LOG,
(errmsg("SELinux: kernel status page uses fallback mode")));
/* Arrange to close selinux status page on process exit. */
on_proc_exit(sepgsql_avc_exit, 0);
}
| static avc_cache* sepgsql_avc_lookup | ( | const char * | scontext, | |
| const char * | tcontext, | |||
| uint16 | tclass | |||
| ) | [static] |
Definition at line 306 of file uavc.c.
References avc_cache::hash, avc_cache::hot_cache, lfirst, avc_cache::scontext, sepgsql_avc_compute(), sepgsql_avc_hash(), avc_cache::tclass, and avc_cache::tcontext.
Referenced by sepgsql_avc_check_perms_label(), and sepgsql_avc_trusted_proc().
{
avc_cache *cache;
ListCell *cell;
uint32 hash;
int index;
hash = sepgsql_avc_hash(scontext, tcontext, tclass);
index = hash % AVC_NUM_SLOTS;
foreach(cell, avc_slots[index])
{
cache = lfirst(cell);
if (cache->hash == hash &&
cache->tclass == tclass &&
strcmp(cache->tcontext, tcontext) == 0 &&
strcmp(cache->scontext, scontext) == 0)
{
cache->hot_cache = true;
return cache;
}
}
/* not found, so insert a new cache */
return sepgsql_avc_compute(scontext, tcontext, tclass);
}
| static void sepgsql_avc_reclaim | ( | void | ) | [static] |
Definition at line 93 of file uavc.c.
References avc_lru_hint, avc_num_caches, AVC_NUM_RECLAIM, AVC_NUM_SLOTS, avc_threshold, avc_cache::hot_cache, lfirst, list_delete_cell(), list_head(), lnext, avc_cache::ncontext, pfree(), avc_cache::scontext, and avc_cache::tcontext.
Referenced by sepgsql_avc_compute().
{
ListCell *cell;
ListCell *next;
ListCell *prev;
int index;
while (avc_num_caches >= avc_threshold - AVC_NUM_RECLAIM)
{
index = avc_lru_hint;
prev = NULL;
for (cell = list_head(avc_slots[index]); cell; cell = next)
{
avc_cache *cache = lfirst(cell);
next = lnext(cell);
if (!cache->hot_cache)
{
avc_slots[index]
= list_delete_cell(avc_slots[index], cell, prev);
pfree(cache->scontext);
pfree(cache->tcontext);
if (cache->ncontext)
pfree(cache->ncontext);
pfree(cache);
avc_num_caches--;
}
else
{
cache->hot_cache = false;
prev = cell;
}
}
avc_lru_hint = (avc_lru_hint + 1) % AVC_NUM_SLOTS;
}
}
| static void sepgsql_avc_reset | ( | void | ) | [static] |
Definition at line 79 of file uavc.c.
References avc_lru_hint, avc_num_caches, AVC_NUM_SLOTS, avc_unlabeled, and MemoryContextReset().
Referenced by sepgsql_avc_check_valid().
{
MemoryContextReset(avc_mem_cxt);
memset(avc_slots, 0, sizeof(List *) * AVC_NUM_SLOTS);
avc_num_caches = 0;
avc_lru_hint = 0;
avc_unlabeled = NULL;
}
| char* sepgsql_avc_trusted_proc | ( | Oid | functionId | ) |
Definition at line 453 of file uavc.c.
References ObjectAddress::classId, GetSecurityLabel(), avc_cache::ncontext, ObjectAddress::objectId, ObjectAddress::objectSubId, SEPG_CLASS_DB_PROCEDURE, sepgsql_avc_check_valid(), sepgsql_avc_lookup(), sepgsql_avc_unlabeled(), sepgsql_get_client_label(), and SEPGSQL_LABEL_TAG.
Referenced by sepgsql_fmgr_hook(), and sepgsql_needs_fmgr_hook().
{
char *scontext = sepgsql_get_client_label();
char *tcontext;
ObjectAddress tobject;
avc_cache *cache;
tobject.classId = ProcedureRelationId;
tobject.objectId = functionId;
tobject.objectSubId = 0;
tcontext = GetSecurityLabel(&tobject, SEPGSQL_LABEL_TAG);
sepgsql_avc_check_valid();
do
{
if (tcontext)
cache = sepgsql_avc_lookup(scontext, tcontext,
SEPG_CLASS_DB_PROCEDURE);
else
cache = sepgsql_avc_lookup(scontext, sepgsql_avc_unlabeled(),
SEPG_CLASS_DB_PROCEDURE);
} while (!sepgsql_avc_check_valid());
return cache->ncontext;
}
| static char* sepgsql_avc_unlabeled | ( | void | ) | [static] |
Definition at line 176 of file uavc.c.
References avc_unlabeled, ereport, errcode(), errmsg(), ERROR, MemoryContextStrdup(), PG_CATCH, PG_END_TRY, PG_RE_THROW, and PG_TRY.
Referenced by sepgsql_avc_check_perms_label(), sepgsql_avc_compute(), and sepgsql_avc_trusted_proc().
{
if (!avc_unlabeled)
{
security_context_t unlabeled;
if (security_get_initial_context_raw("unlabeled", &unlabeled) < 0)
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("SELinux: failed to get initial security label: %m")));
PG_TRY();
{
avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled);
}
PG_CATCH();
{
freecon(unlabeled);
PG_RE_THROW();
}
PG_END_TRY();
freecon(unlabeled);
}
return avc_unlabeled;
}
int avc_lru_hint [static] |
Definition at line 60 of file uavc.c.
Referenced by sepgsql_avc_init(), sepgsql_avc_reclaim(), and sepgsql_avc_reset().
MemoryContext avc_mem_cxt [static] |
int avc_num_caches [static] |
Definition at line 59 of file uavc.c.
Referenced by sepgsql_avc_compute(), sepgsql_avc_init(), sepgsql_avc_reclaim(), and sepgsql_avc_reset().
int avc_threshold [static] |
Definition at line 61 of file uavc.c.
Referenced by sepgsql_avc_compute(), sepgsql_avc_init(), and sepgsql_avc_reclaim().
char* avc_unlabeled [static] |
Definition at line 62 of file uavc.c.
Referenced by sepgsql_avc_reset(), and sepgsql_avc_unlabeled().
1.7.1