#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().