Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions | Variables

uavc.c File Reference

#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"
Include dependency graph for uavc.c:

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_cachesepgsql_avc_compute (const char *scontext, const char *tcontext, uint16 tclass)
static avc_cachesepgsql_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 Listavc_slots [AVC_NUM_SLOTS]
static int avc_num_caches
static int avc_lru_hint
static int avc_threshold
static char * avc_unlabeled

Define Documentation

#define AVC_DEF_THRESHOLD   384

Definition at line 55 of file uavc.c.

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


Function Documentation

bool sepgsql_avc_check_perms ( const ObjectAddress tobject,
uint16  tclass,
uint32  required,
const char *  audit_name,
bool  abort_on_violation 
)
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().

{
    return hash_any((const unsigned char *) scontext, strlen(scontext))
        ^ hash_any((const unsigned char *) tcontext, strlen(tcontext))
        ^ tclass;
}

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]
char* sepgsql_avc_trusted_proc ( Oid  functionId  ) 
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;
}


Variable Documentation

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

Definition at line 57 of file uavc.c.

int avc_num_caches [static]
List* avc_slots[AVC_NUM_SLOTS] [static]

Definition at line 58 of file uavc.c.

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