|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Implementation of the userspace access vector cache (AVC).
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Derived from the kernel AVC implementation by
|
|
Chris PeBenito |
473ea7 |
* Stephen Smalley <sds@epoch.ncsc.mil> and
|
|
Chris PeBenito |
473ea7 |
* James Morris <jmorris@redhat.com>.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
#include <sys/types.h>
|
|
Chris PeBenito |
473ea7 |
#include <errno.h>
|
|
Chris PeBenito |
473ea7 |
#include <stddef.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdio.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdlib.h>
|
|
Chris PeBenito |
473ea7 |
#include <string.h>
|
|
Chris PeBenito |
473ea7 |
#include <unistd.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdint.h>
|
|
Chris PeBenito |
473ea7 |
#include <selinux/flask.h>
|
|
Chris PeBenito |
473ea7 |
#include "selinux_internal.h"
|
|
Chris PeBenito |
473ea7 |
#include <selinux/avc.h>
|
|
Chris PeBenito |
473ea7 |
#include "avc_sidtab.h"
|
|
Chris PeBenito |
473ea7 |
#include "avc_internal.h"
|
|
Chris PeBenito |
473ea7 |
#include <selinux/av_permissions.h>
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* The following code looks complicated, but it really is not. What it
|
|
Chris PeBenito |
473ea7 |
does is to generate two variables. The first is basically a struct
|
|
Chris PeBenito |
473ea7 |
of arrays. The second is the real array of structures which would
|
|
Chris PeBenito |
473ea7 |
have used string pointers. But instead it now uses an offset value
|
|
Chris PeBenito |
473ea7 |
into the first structure. Strings are accessed indirectly by an
|
|
Chris PeBenito |
473ea7 |
explicit addition of the string index and the base address of the
|
|
Chris PeBenito |
473ea7 |
structure with the strings (all type safe). The advantage is that
|
|
Chris PeBenito |
473ea7 |
there are no relocations necessary in the array with the data as it
|
|
Chris PeBenito |
473ea7 |
would be the case with string pointers. This has advantages at
|
|
Chris PeBenito |
473ea7 |
load time, the data section is smaller, and it is read-only. */
|
|
Chris PeBenito |
473ea7 |
#define L1(line) L2(line)
|
|
Chris PeBenito |
473ea7 |
#define L2(line) str##line
|
|
Chris PeBenito |
473ea7 |
static const union av_perm_to_string_data
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct {
|
|
Chris PeBenito |
473ea7 |
#define S_(c, v, s) char L1(__LINE__)[sizeof(s)];
|
|
Chris PeBenito |
473ea7 |
#include "av_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
char str[0];
|
|
Chris PeBenito |
473ea7 |
} av_perm_to_string_data =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define S_(c, v, s) s,
|
|
Chris PeBenito |
473ea7 |
#include "av_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
static const struct av_perm_to_string
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
u16 tclass;
|
|
Chris PeBenito |
473ea7 |
u16 nameidx;
|
|
Chris PeBenito |
473ea7 |
u32 value;
|
|
Chris PeBenito |
473ea7 |
} av_perm_to_string[] =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define S_(c, v, s) { c, offsetof(union av_perm_to_string_data, L1(__LINE__)), v },
|
|
Chris PeBenito |
473ea7 |
#include "av_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
#undef L1
|
|
Chris PeBenito |
473ea7 |
#undef L2
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
#define L1(line) L2(line)
|
|
Chris PeBenito |
473ea7 |
#define L2(line) str##line
|
|
Chris PeBenito |
473ea7 |
static const union class_to_string_data
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct {
|
|
Chris PeBenito |
473ea7 |
#define S_(s) char L1(__LINE__)[sizeof(s)];
|
|
Chris PeBenito |
473ea7 |
#include "class_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
char str[0];
|
|
Chris PeBenito |
473ea7 |
} class_to_string_data =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define S_(s) s,
|
|
Chris PeBenito |
473ea7 |
#include "class_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
static const u16 class_to_string[] =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define S_(s) offsetof(union class_to_string_data, L1(__LINE__)),
|
|
Chris PeBenito |
473ea7 |
#include "class_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
#undef L1
|
|
Chris PeBenito |
473ea7 |
#undef L2
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static const union common_perm_to_string_data
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct {
|
|
Chris PeBenito |
473ea7 |
#define L1(line) L2(line)
|
|
Chris PeBenito |
473ea7 |
#define L2(line) str##line
|
|
Chris PeBenito |
473ea7 |
#define S_(s) char L1(__LINE__)[sizeof(s)];
|
|
Chris PeBenito |
473ea7 |
#define TB_(s)
|
|
Chris PeBenito |
473ea7 |
#define TE_(s)
|
|
Chris PeBenito |
473ea7 |
#include "common_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
#undef L1
|
|
Chris PeBenito |
473ea7 |
#undef L2
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
char str[0];
|
|
Chris PeBenito |
473ea7 |
} common_perm_to_string_data =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define S_(s) s,
|
|
Chris PeBenito |
473ea7 |
#include "common_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
#undef TB_
|
|
Chris PeBenito |
473ea7 |
#undef TE_
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
static const union common_perm_to_string
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct {
|
|
Chris PeBenito |
473ea7 |
#define TB_(s) struct {
|
|
Chris PeBenito |
473ea7 |
#define TE_(s) } s##_part;
|
|
Chris PeBenito |
473ea7 |
#define S_(s) u16 L1(__LINE__)
|
|
Chris PeBenito |
473ea7 |
#define L1(l) L2(l)
|
|
Chris PeBenito |
473ea7 |
#define L2(l) field_##l;
|
|
Chris PeBenito |
473ea7 |
#include "common_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef TB_
|
|
Chris PeBenito |
473ea7 |
#undef TE_
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
#undef L1
|
|
Chris PeBenito |
473ea7 |
#undef L2
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
u16 data[0];
|
|
Chris PeBenito |
473ea7 |
} common_perm_to_string =
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
#define TB_(s) {
|
|
Chris PeBenito |
473ea7 |
#define TE_(s) },
|
|
Chris PeBenito |
473ea7 |
#define S_(s) offsetof(union common_perm_to_string_data, L1(__LINE__)),
|
|
Chris PeBenito |
473ea7 |
#define L1(line) L2(line)
|
|
Chris PeBenito |
473ea7 |
#define L2(line) str##line
|
|
Chris PeBenito |
473ea7 |
#include "common_perm_to_string.h"
|
|
Chris PeBenito |
473ea7 |
#undef TB_
|
|
Chris PeBenito |
473ea7 |
#undef TE_
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
#undef L1
|
|
Chris PeBenito |
473ea7 |
#undef L2
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static const struct av_inherit
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
u16 tclass;
|
|
Chris PeBenito |
473ea7 |
u16 common_pts_idx;
|
|
Chris PeBenito |
473ea7 |
u32 common_base;
|
|
Chris PeBenito |
473ea7 |
} av_inherit[] = {
|
|
Chris PeBenito |
473ea7 |
#define S_(c, i, b) { c, offsetof(union common_perm_to_string, common_##i##_perm_to_string_part)/sizeof(u16), b },
|
|
Chris PeBenito |
473ea7 |
#include "av_inherit.h"
|
|
Chris PeBenito |
473ea7 |
#undef S_
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
#define AVC_CACHE_SLOTS 512
|
|
Chris PeBenito |
473ea7 |
#define AVC_CACHE_MAXNODES 410
|
|
Chris PeBenito |
473ea7 |
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
struct avc_entry {
|
|
Chris PeBenito |
473ea7 |
security_id_t ssid;
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid;
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass;
|
|
Chris PeBenito |
473ea7 |
struct av_decision avd;
|
|
Chris PeBenito |
473ea7 |
int used; /* used recently */
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
struct avc_node {
|
|
Chris PeBenito |
473ea7 |
struct avc_entry ae;
|
|
Chris PeBenito |
473ea7 |
struct avc_node *next;
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
struct avc_cache {
|
|
Chris PeBenito |
473ea7 |
struct avc_node *slots[AVC_CACHE_SLOTS];
|
|
Chris PeBenito |
473ea7 |
u_int32_t lru_hint; /* LRU hint for reclaim scan */
|
|
Chris PeBenito |
473ea7 |
u_int32_t active_nodes;
|
|
Chris PeBenito |
473ea7 |
u_int32_t latest_notif; /* latest revocation notification */
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node {
|
|
Chris PeBenito |
473ea7 |
int (*callback) (u_int32_t event, security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
access_vector_t *out_retained);
|
|
Chris PeBenito |
473ea7 |
u_int32_t events;
|
|
Chris PeBenito |
473ea7 |
security_id_t ssid;
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid;
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass;
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms;
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node *next;
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void* avc_netlink_thread = NULL;
|
|
Chris PeBenito |
473ea7 |
static void* avc_lock = NULL;
|
|
Chris PeBenito |
473ea7 |
static void* avc_log_lock = NULL;
|
|
Chris PeBenito |
473ea7 |
static struct avc_node *avc_node_freelist = NULL;
|
|
Chris PeBenito |
473ea7 |
static struct avc_cache avc_cache;
|
|
Chris PeBenito |
473ea7 |
static char *avc_audit_buf = NULL;
|
|
Chris PeBenito |
473ea7 |
static struct avc_cache_stats cache_stats;
|
|
Chris PeBenito |
473ea7 |
static struct avc_callback_node *avc_callbacks = NULL;
|
|
Chris PeBenito |
473ea7 |
static struct sidtab avc_sidtab;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline int avc_hash(security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid, security_class_t tclass)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
return ((uintptr_t)ssid ^ ((uintptr_t)tsid<<2) ^ tclass)
|
|
Chris PeBenito |
473ea7 |
& (AVC_CACHE_SLOTS - 1);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_context_to_sid(security_context_t ctx, security_id_t *sid)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid);
|
|
Chris PeBenito |
473ea7 |
if (!rc)
|
|
Chris PeBenito |
473ea7 |
(*sid)->refcnt++;
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_sid_to_context(security_id_t sid, security_context_t *ctx)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
*ctx = NULL;
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
if (sid->refcnt > 0) {
|
|
Chris PeBenito |
473ea7 |
*ctx = strdup(sid->ctx); /* caller must free via freecon */
|
|
Chris PeBenito |
473ea7 |
rc = *ctx ? 0 : -1;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
errno = EINVAL; /* bad reference count */
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int sidget(security_id_t sid) {
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
rc = sid_inc_refcnt(sid);
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int sidput(security_id_t sid) {
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
rc = sid_dec_refcnt(sid);
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_init(const char *prefix,
|
|
Chris PeBenito |
473ea7 |
const struct avc_memory_callback *mem_cb,
|
|
Chris PeBenito |
473ea7 |
const struct avc_log_callback *log_cb,
|
|
Chris PeBenito |
473ea7 |
const struct avc_thread_callback *thread_cb,
|
|
Chris PeBenito |
473ea7 |
const struct avc_lock_callback *lock_cb)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *new;
|
|
Chris PeBenito |
473ea7 |
int i, rc = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (prefix)
|
|
Chris PeBenito |
473ea7 |
strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE-1);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
set_callbacks(mem_cb, log_cb, thread_cb, lock_cb);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_lock = avc_alloc_lock();
|
|
Chris PeBenito |
473ea7 |
avc_log_lock = avc_alloc_lock();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memset(&cache_stats, 0, sizeof(cache_stats));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_SLOTS; i++)
|
|
Chris PeBenito |
473ea7 |
avc_cache.slots[i] = 0;
|
|
Chris PeBenito |
473ea7 |
avc_cache.lru_hint = 0;
|
|
Chris PeBenito |
473ea7 |
avc_cache.active_nodes = 0;
|
|
Chris PeBenito |
473ea7 |
avc_cache.latest_notif = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
rc = sidtab_init(&avc_sidtab);
|
|
Chris PeBenito |
473ea7 |
if (rc) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: unable to initialize SID table\n", avc_prefix);
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE);
|
|
Chris PeBenito |
473ea7 |
if (!avc_audit_buf) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: unable to allocate audit buffer\n", avc_prefix);
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_MAXNODES; i++) {
|
|
Chris PeBenito |
473ea7 |
new = avc_malloc(sizeof(*new));
|
|
Chris PeBenito |
473ea7 |
if (!new) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: warning: only got %d av entries\n",
|
|
Chris PeBenito |
473ea7 |
avc_prefix, i);
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
memset(new, 0, sizeof(*new));
|
|
Chris PeBenito |
473ea7 |
new->next = avc_node_freelist;
|
|
Chris PeBenito |
473ea7 |
avc_node_freelist = new;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
rc = security_getenforce();
|
|
Chris PeBenito |
473ea7 |
if (rc < 0) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: could not determine enforcing mode\n", avc_prefix);
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_enforcing = rc;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
rc = avc_netlink_open(avc_using_threads);
|
|
Chris PeBenito |
473ea7 |
if (rc < 0) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: can't open netlink socket: %d (%s)\n", avc_prefix,
|
|
Chris PeBenito |
473ea7 |
errno, strerror(errno));
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (avc_using_threads) {
|
|
Chris PeBenito |
473ea7 |
avc_netlink_thread = avc_create_thread(&avc_netlink_loop);
|
|
Chris PeBenito |
473ea7 |
avc_netlink_trouble = 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_cache_stats(struct avc_cache_stats *p) {
|
|
Chris PeBenito |
473ea7 |
memcpy(p, &cache_stats, sizeof(cache_stats));
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_sid_stats(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_log_lock);
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE);
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
avc_log("%s", avc_audit_buf);
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_log_lock);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_av_stats(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i, chain_len, max_chain_len, slots_used;
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
slots_used = 0;
|
|
Chris PeBenito |
473ea7 |
max_chain_len = 0;
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
|
|
Chris PeBenito |
473ea7 |
node = avc_cache.slots[i];
|
|
Chris PeBenito |
473ea7 |
if (node) {
|
|
Chris PeBenito |
473ea7 |
slots_used++;
|
|
Chris PeBenito |
473ea7 |
chain_len = 0;
|
|
Chris PeBenito |
473ea7 |
while (node) {
|
|
Chris PeBenito |
473ea7 |
chain_len++;
|
|
Chris PeBenito |
473ea7 |
node = node->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (chain_len > max_chain_len)
|
|
Chris PeBenito |
473ea7 |
max_chain_len = chain_len;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: %d AV entries and %d/%d buckets used, "
|
|
Chris PeBenito |
473ea7 |
"longest chain length %d\n", avc_prefix,
|
|
Chris PeBenito |
473ea7 |
avc_cache.active_nodes,
|
|
Chris PeBenito |
473ea7 |
slots_used, AVC_CACHE_SLOTS, max_chain_len);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(avc_av_stats)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline struct avc_node *avc_reclaim_node(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *prev, *cur;
|
|
Chris PeBenito |
473ea7 |
int try;
|
|
Chris PeBenito |
473ea7 |
u_int32_t hvalue;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
hvalue = avc_cache.lru_hint;
|
|
Chris PeBenito |
473ea7 |
for (try = 0; try < 2; try++) {
|
|
Chris PeBenito |
473ea7 |
do {
|
|
Chris PeBenito |
473ea7 |
prev = NULL;
|
|
Chris PeBenito |
473ea7 |
cur = avc_cache.slots[hvalue];
|
|
Chris PeBenito |
473ea7 |
while (cur) {
|
|
Chris PeBenito |
473ea7 |
if (!cur->ae.used)
|
|
Chris PeBenito |
473ea7 |
goto found;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
cur->ae.used = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
prev = cur;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1);
|
|
Chris PeBenito |
473ea7 |
} while (hvalue != avc_cache.lru_hint);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
errno = ENOMEM; /* this was a panic in the kernel... */
|
|
Chris PeBenito |
473ea7 |
return NULL;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
found:
|
|
Chris PeBenito |
473ea7 |
avc_cache.lru_hint = hvalue;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (prev == NULL)
|
|
Chris PeBenito |
473ea7 |
avc_cache.slots[hvalue] = cur->next;
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
prev->next = cur->next;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return cur;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline struct avc_node *avc_claim_node(security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *new;
|
|
Chris PeBenito |
473ea7 |
int hvalue;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!avc_node_freelist)
|
|
Chris PeBenito |
473ea7 |
avc_cleanup();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (avc_node_freelist) {
|
|
Chris PeBenito |
473ea7 |
new = avc_node_freelist;
|
|
Chris PeBenito |
473ea7 |
avc_node_freelist = avc_node_freelist->next;
|
|
Chris PeBenito |
473ea7 |
avc_cache.active_nodes++;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
new = avc_reclaim_node();
|
|
Chris PeBenito |
473ea7 |
if (!new)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
hvalue = avc_hash(ssid, tsid, tclass);
|
|
Chris PeBenito |
473ea7 |
new->ae.used = 1;
|
|
Chris PeBenito |
473ea7 |
new->ae.ssid = ssid;
|
|
Chris PeBenito |
473ea7 |
new->ae.tsid = tsid;
|
|
Chris PeBenito |
473ea7 |
new->ae.tclass = tclass;
|
|
Chris PeBenito |
473ea7 |
new->next = avc_cache.slots[hvalue];
|
|
Chris PeBenito |
473ea7 |
avc_cache.slots[hvalue] = new;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return new;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline struct avc_node *avc_search_node(security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
int *probes)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *cur;
|
|
Chris PeBenito |
473ea7 |
int hvalue;
|
|
Chris PeBenito |
473ea7 |
int tprobes = 1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
hvalue = avc_hash(ssid, tsid, tclass);
|
|
Chris PeBenito |
473ea7 |
cur = avc_cache.slots[hvalue];
|
|
Chris PeBenito |
473ea7 |
while (cur != NULL &&
|
|
Chris PeBenito |
473ea7 |
(ssid != cur->ae.ssid ||
|
|
Chris PeBenito |
473ea7 |
tclass != cur->ae.tclass ||
|
|
Chris PeBenito |
473ea7 |
tsid != cur->ae.tsid)) {
|
|
Chris PeBenito |
473ea7 |
tprobes++;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (cur == NULL) {
|
|
Chris PeBenito |
473ea7 |
/* cache miss */
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* cache hit */
|
|
Chris PeBenito |
473ea7 |
if (probes)
|
|
Chris PeBenito |
473ea7 |
*probes = tprobes;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
cur->ae.used = 1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return cur;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_lookup - Look up an AVC entry.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @requested: requested permissions, interpreted based on @tclass
|
|
Chris PeBenito |
473ea7 |
* @aeref: AVC entry reference
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Look up an AVC entry that is valid for the
|
|
Chris PeBenito |
473ea7 |
* @requested permissions between the SID pair
|
|
Chris PeBenito |
473ea7 |
* (@ssid, @tsid), interpreting the permissions
|
|
Chris PeBenito |
473ea7 |
* based on @tclass. If a valid AVC entry exists,
|
|
Chris PeBenito |
473ea7 |
* then this function updates @aeref to refer to the
|
|
Chris PeBenito |
473ea7 |
* entry and returns %0. Otherwise, -1 is returned.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static int avc_lookup(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t requested, struct avc_entry_ref *aeref)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node;
|
|
Chris PeBenito |
473ea7 |
int probes, rc = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(cav_lookups);
|
|
Chris PeBenito |
473ea7 |
node = avc_search_node(ssid, tsid, tclass,&probes);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (node && ((node->ae.avd.decided & requested) == requested)) {
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(cav_hits);
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_add(cav_probes,probes);
|
|
Chris PeBenito |
473ea7 |
aeref->ae = &node->ae;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(cav_misses);
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_insert - Insert an AVC entry.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @ae: AVC entry
|
|
Chris PeBenito |
473ea7 |
* @aeref: AVC entry reference
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Insert an AVC entry for the SID pair
|
|
Chris PeBenito |
473ea7 |
* (@ssid, @tsid) and class @tclass.
|
|
Chris PeBenito |
473ea7 |
* The access vectors and the sequence number are
|
|
Chris PeBenito |
473ea7 |
* normally provided by the security server in
|
|
Chris PeBenito |
473ea7 |
* response to a security_compute_av() call. If the
|
|
Chris PeBenito |
473ea7 |
* sequence number @ae->avd.seqno is not less than the latest
|
|
Chris PeBenito |
473ea7 |
* revocation notification, then the function copies
|
|
Chris PeBenito |
473ea7 |
* the access vectors into a cache entry, updates
|
|
Chris PeBenito |
473ea7 |
* @aeref to refer to the entry, and returns %0.
|
|
Chris PeBenito |
473ea7 |
* Otherwise, this function returns -%1 with @errno set to %EAGAIN.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static int avc_insert(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
struct avc_entry *ae, struct avc_entry_ref *aeref)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node;
|
|
Chris PeBenito |
473ea7 |
int rc = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ae->avd.seqno < avc_cache.latest_notif) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: seqno %d < latest_notif %d\n", avc_prefix,
|
|
Chris PeBenito |
473ea7 |
ae->avd.seqno, avc_cache.latest_notif);
|
|
Chris PeBenito |
473ea7 |
errno = EAGAIN;
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
node = avc_claim_node(ssid, tsid, tclass);
|
|
Chris PeBenito |
473ea7 |
if (!node) {
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.allowed = ae->avd.allowed;
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.decided = ae->avd.decided;
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditallow = ae->avd.auditallow;
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditdeny = ae->avd.auditdeny;
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.seqno = ae->avd.seqno;
|
|
Chris PeBenito |
473ea7 |
aeref->ae = &node->ae;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_remove - Remove AVC and sidtab entries for SID.
|
|
Chris PeBenito |
473ea7 |
* @sid: security identifier to be removed
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Remove all AVC entries containing @sid as source
|
|
Chris PeBenito |
473ea7 |
* or target, and remove @sid from the SID table.
|
|
Chris PeBenito |
473ea7 |
* Free the memory allocated for the structure corresponding
|
|
Chris PeBenito |
473ea7 |
* to @sid. After this function has been called, @sid must
|
|
Chris PeBenito |
473ea7 |
* not be used until another call to avc_context_to_sid() has
|
|
Chris PeBenito |
473ea7 |
* been made for this SID.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static void avc_remove(security_id_t sid)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *prev, *cur, *tmp;
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i=0; i < AVC_CACHE_SLOTS; i++) {
|
|
Chris PeBenito |
473ea7 |
cur = avc_cache.slots[i];
|
|
Chris PeBenito |
473ea7 |
prev = NULL;
|
|
Chris PeBenito |
473ea7 |
while (cur) {
|
|
Chris PeBenito |
473ea7 |
if (sid == cur->ae.ssid || sid == cur->ae.tsid) {
|
|
Chris PeBenito |
473ea7 |
if (prev)
|
|
Chris PeBenito |
473ea7 |
prev->next = cur->next;
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
avc_cache.slots[i] = cur->next;
|
|
Chris PeBenito |
473ea7 |
tmp = cur;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.ssid = tmp->ae.tsid = NULL;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.tclass = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.avd.allowed = tmp->ae.avd.decided = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.avd.auditallow = tmp->ae.avd.auditdeny = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.used = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->next = avc_node_freelist;
|
|
Chris PeBenito |
473ea7 |
avc_node_freelist = tmp;
|
|
Chris PeBenito |
473ea7 |
avc_cache.active_nodes--;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
prev = cur;
|
|
Chris PeBenito |
473ea7 |
cur = cur->next;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
sidtab_remove(&avc_sidtab, sid);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_cleanup(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
security_id_t sid;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while (NULL != (sid = sidtab_claim_sid(&avc_sidtab)))
|
|
Chris PeBenito |
473ea7 |
avc_remove(sid);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(avc_cleanup)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_reset(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node *c;
|
|
Chris PeBenito |
473ea7 |
int i, ret, rc = 0, errsave = 0;
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node, *tmp;
|
|
Chris PeBenito |
473ea7 |
errno = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
|
|
Chris PeBenito |
473ea7 |
node = avc_cache.slots[i];
|
|
Chris PeBenito |
473ea7 |
while (node) {
|
|
Chris PeBenito |
473ea7 |
tmp = node;
|
|
Chris PeBenito |
473ea7 |
node = node->next;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.ssid = tmp->ae.tsid = NULL;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.tclass = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.avd.allowed = tmp->ae.avd.decided = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.avd.auditallow = tmp->ae.avd.auditdeny = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->ae.used = 0;
|
|
Chris PeBenito |
473ea7 |
tmp->next = avc_node_freelist;
|
|
Chris PeBenito |
473ea7 |
avc_node_freelist = tmp;
|
|
Chris PeBenito |
473ea7 |
avc_cache.active_nodes--;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_cache.slots[i] = 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_cache.lru_hint = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memset(&cache_stats, 0, sizeof(cache_stats));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (c = avc_callbacks; c; c = c->next) {
|
|
Chris PeBenito |
473ea7 |
if (c->events & AVC_CALLBACK_RESET) {
|
|
Chris PeBenito |
473ea7 |
ret = c->callback(AVC_CALLBACK_RESET,
|
|
Chris PeBenito |
473ea7 |
0, 0, 0, 0, 0);
|
|
Chris PeBenito |
473ea7 |
if (ret && !rc) {
|
|
Chris PeBenito |
473ea7 |
rc = ret;
|
|
Chris PeBenito |
473ea7 |
errsave = errno;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
errno = errsave;
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(avc_reset)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_destroy(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node *c;
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node, *tmp;
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (avc_using_threads)
|
|
Chris PeBenito |
473ea7 |
avc_stop_thread(avc_netlink_thread);
|
|
Chris PeBenito |
473ea7 |
avc_netlink_close();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
|
|
Chris PeBenito |
473ea7 |
node = avc_cache.slots[i];
|
|
Chris PeBenito |
473ea7 |
while (node) {
|
|
Chris PeBenito |
473ea7 |
tmp = node;
|
|
Chris PeBenito |
473ea7 |
node = node->next;
|
|
Chris PeBenito |
473ea7 |
avc_free(tmp);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
while (avc_node_freelist) {
|
|
Chris PeBenito |
473ea7 |
tmp = avc_node_freelist;
|
|
Chris PeBenito |
473ea7 |
avc_node_freelist = tmp->next;
|
|
Chris PeBenito |
473ea7 |
avc_free(tmp);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while (avc_callbacks) {
|
|
Chris PeBenito |
473ea7 |
c = avc_callbacks;
|
|
Chris PeBenito |
473ea7 |
avc_callbacks = c->next;
|
|
Chris PeBenito |
473ea7 |
avc_free(c);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
sidtab_destroy(&avc_sidtab);
|
|
Chris PeBenito |
473ea7 |
avc_free_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
avc_free_lock(avc_log_lock);
|
|
Chris PeBenito |
473ea7 |
avc_free(avc_audit_buf);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* ratelimit stuff put aside for now --EFW */
|
|
Chris PeBenito |
473ea7 |
#if 0
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Copied from net/core/utils.c:net_ratelimit and modified for
|
|
Chris PeBenito |
473ea7 |
* use by the AVC audit facility.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
#define AVC_MSG_COST 5*HZ
|
|
Chris PeBenito |
473ea7 |
#define AVC_MSG_BURST 10*5*HZ
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* This enforces a rate limit: not more than one kernel message
|
|
Chris PeBenito |
473ea7 |
* every 5secs to make a denial-of-service attack impossible.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static int avc_ratelimit(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
static unsigned long toks = 10*5*HZ;
|
|
Chris PeBenito |
473ea7 |
static unsigned long last_msg;
|
|
Chris PeBenito |
473ea7 |
static int missed, rc = 0;
|
|
Chris PeBenito |
473ea7 |
unsigned long now = jiffies;
|
|
Chris PeBenito |
473ea7 |
void *ratelimit_lock = avc_alloc_lock();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(ratelimit_lock);
|
|
Chris PeBenito |
473ea7 |
toks += now - last_msg;
|
|
Chris PeBenito |
473ea7 |
last_msg = now;
|
|
Chris PeBenito |
473ea7 |
if (toks > AVC_MSG_BURST)
|
|
Chris PeBenito |
473ea7 |
toks = AVC_MSG_BURST;
|
|
Chris PeBenito |
473ea7 |
if (toks >= AVC_MSG_COST) {
|
|
Chris PeBenito |
473ea7 |
int lost = missed;
|
|
Chris PeBenito |
473ea7 |
missed = 0;
|
|
Chris PeBenito |
473ea7 |
toks -= AVC_MSG_COST;
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(ratelimit_lock);
|
|
Chris PeBenito |
473ea7 |
if (lost) {
|
|
Chris PeBenito |
473ea7 |
avc_log("%s: %d messages suppressed.\n", avc_prefix, lost);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
rc = 1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
missed++;
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(ratelimit_lock);
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
avc_free_lock(ratelimit_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline int check_avc_ratelimit(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (avc_enforcing)
|
|
Chris PeBenito |
473ea7 |
return avc_ratelimit();
|
|
Chris PeBenito |
473ea7 |
else {
|
|
Chris PeBenito |
473ea7 |
/* If permissive, then never suppress messages. */
|
|
Chris PeBenito |
473ea7 |
return 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
#endif /* ratelimit stuff */
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_dump_av - Display an access vector in human-readable form.
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @av: access vector
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static void avc_dump_av(security_class_t tclass, access_vector_t av)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
const u16 *common_pts_idx = 0;
|
|
Chris PeBenito |
473ea7 |
u_int32_t common_base = 0, perm;
|
|
Chris PeBenito |
473ea7 |
unsigned int i, i2;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (av == 0) {
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " null");
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
|
|
Chris PeBenito |
473ea7 |
if (av_inherit[i].tclass == tclass) {
|
|
Chris PeBenito |
473ea7 |
common_pts_idx = &common_perm_to_string.data[av_inherit[i].common_pts_idx];
|
|
Chris PeBenito |
473ea7 |
common_base = av_inherit[i].common_base;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " {");
|
|
Chris PeBenito |
473ea7 |
i = 0;
|
|
Chris PeBenito |
473ea7 |
perm = 1;
|
|
Chris PeBenito |
473ea7 |
while (perm < common_base) {
|
|
Chris PeBenito |
473ea7 |
if (perm & av) {
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " %s",
|
|
Chris PeBenito |
473ea7 |
common_perm_to_string_data.str + common_pts_idx[i]);
|
|
Chris PeBenito |
473ea7 |
av &= ~perm;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
i++;
|
|
Chris PeBenito |
473ea7 |
perm <<= 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while (i < sizeof(av) * 8) {
|
|
Chris PeBenito |
473ea7 |
if (perm & av) {
|
|
Chris PeBenito |
473ea7 |
for (i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++) {
|
|
Chris PeBenito |
473ea7 |
if ((av_perm_to_string[i2].tclass == tclass) &&
|
|
Chris PeBenito |
473ea7 |
(av_perm_to_string[i2].value == perm))
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (i2 < ARRAY_SIZE(av_perm_to_string)) {
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " %s",
|
|
Chris PeBenito |
473ea7 |
av_perm_to_string_data.str + av_perm_to_string[i2].nameidx);
|
|
Chris PeBenito |
473ea7 |
av &= ~perm;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
i++;
|
|
Chris PeBenito |
473ea7 |
perm <<= 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (av)
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " 0x%x", av);
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " }");
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_dump_query - Display a SID pair and a class in human-readable form.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static void avc_dump_query(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ssid->refcnt > 0)
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, "scontext=%s", ssid->ctx);
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, "ssid=%p", ssid);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (tsid->refcnt > 0)
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " tcontext=%s", tsid->ctx);
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " tsid=%p", tsid);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " tclass=%s",
|
|
Chris PeBenito |
473ea7 |
class_to_string_data.str + class_to_string[tclass]);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void avc_audit(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t requested,
|
|
Chris PeBenito |
473ea7 |
struct av_decision *avd, int result, void *a)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
access_vector_t denied, audited;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
denied = requested & ~avd->allowed;
|
|
Chris PeBenito |
473ea7 |
if (denied) {
|
|
Chris PeBenito |
473ea7 |
audited = denied;
|
|
Chris PeBenito |
473ea7 |
if (!(audited & avd->auditdeny))
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
} else if (result) {
|
|
Chris PeBenito |
473ea7 |
audited = denied = requested;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
audited = requested;
|
|
Chris PeBenito |
473ea7 |
if (!(audited & avd->auditallow))
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
#if 0
|
|
Chris PeBenito |
473ea7 |
if (!check_avc_ratelimit())
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
#endif
|
|
Chris PeBenito |
473ea7 |
/* prevent overlapping buffer writes */
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_log_lock);
|
|
Chris PeBenito |
473ea7 |
snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE,
|
|
Chris PeBenito |
473ea7 |
"%s: %s ", avc_prefix, denied ? "denied" : "granted");
|
|
Chris PeBenito |
473ea7 |
avc_dump_av(tclass,audited);
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " for ");
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* get any extra information printed by the callback */
|
|
Chris PeBenito |
473ea7 |
avc_suppl_audit(a, tclass, avc_audit_buf+strlen(avc_audit_buf),
|
|
Chris PeBenito |
473ea7 |
AVC_AUDIT_BUFSIZE-strlen(avc_audit_buf));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, " ");
|
|
Chris PeBenito |
473ea7 |
avc_dump_query(ssid, tsid, tclass);
|
|
Chris PeBenito |
473ea7 |
log_append(avc_audit_buf, "\n");
|
|
Chris PeBenito |
473ea7 |
avc_log("%s", avc_audit_buf);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_log_lock);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(avc_audit)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_has_perm_noaudit(security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t requested,
|
|
Chris PeBenito |
473ea7 |
struct avc_entry_ref *aeref,
|
|
Chris PeBenito |
473ea7 |
struct av_decision *avd)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_entry *ae;
|
|
Chris PeBenito |
473ea7 |
int rc = 0;
|
|
Chris PeBenito |
473ea7 |
struct avc_entry entry;
|
|
Chris PeBenito |
473ea7 |
access_vector_t denied;
|
|
Chris PeBenito |
473ea7 |
struct avc_entry_ref ref;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!avc_using_threads) {
|
|
Chris PeBenito |
473ea7 |
(void) avc_netlink_check_nb();
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!aeref) {
|
|
Chris PeBenito |
473ea7 |
avc_entry_ref_init(&ref;;
|
|
Chris PeBenito |
473ea7 |
aeref = &ref;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(entry_lookups);
|
|
Chris PeBenito |
473ea7 |
ae = aeref->ae;
|
|
Chris PeBenito |
473ea7 |
if (ae) {
|
|
Chris PeBenito |
473ea7 |
if (ae->ssid == ssid &&
|
|
Chris PeBenito |
473ea7 |
ae->tsid == tsid &&
|
|
Chris PeBenito |
473ea7 |
ae->tclass == tclass &&
|
|
Chris PeBenito |
473ea7 |
((ae->avd.decided & requested) == requested)) {
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(entry_hits);
|
|
Chris PeBenito |
473ea7 |
ae->used = 1;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(entry_discards);
|
|
Chris PeBenito |
473ea7 |
ae = 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!ae) {
|
|
Chris PeBenito |
473ea7 |
avc_cache_stats_incr(entry_misses);
|
|
Chris PeBenito |
473ea7 |
rc = avc_lookup(ssid, tsid, tclass, requested, aeref);
|
|
Chris PeBenito |
473ea7 |
if (rc) {
|
|
Chris PeBenito |
473ea7 |
if ((ssid->refcnt <= 0) || (tsid->refcnt <= 0)) {
|
|
Chris PeBenito |
473ea7 |
errno = EINVAL;
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
rc = security_compute_av(ssid->ctx, tsid->ctx, tclass,
|
|
Chris PeBenito |
473ea7 |
requested, &entry.avd);
|
|
Chris PeBenito |
473ea7 |
if (rc)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
rc = avc_insert(ssid,tsid,tclass,&entry,aeref);
|
|
Chris PeBenito |
473ea7 |
if (rc)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
ae = aeref->ae;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (avd)
|
|
Chris PeBenito |
473ea7 |
memcpy(avd, &ae->avd, sizeof(*avd));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
denied = requested & ~(ae->avd.allowed);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if ((!requested || denied) && avc_enforcing) {
|
|
Chris PeBenito |
473ea7 |
errno = EACCES;
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(avc_has_perm_noaudit)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_has_perm(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t requested,
|
|
Chris PeBenito |
473ea7 |
struct avc_entry_ref *aeref, void *auditdata)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct av_decision avd = {0,0,0,0,0};
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
|
|
Chris PeBenito |
473ea7 |
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int avc_add_callback(int (*callback)(u_int32_t event, security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
access_vector_t *out_retained),
|
|
Chris PeBenito |
473ea7 |
u_int32_t events, security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node *c;
|
|
Chris PeBenito |
473ea7 |
int rc = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
c = avc_malloc(sizeof(*c));
|
|
Chris PeBenito |
473ea7 |
if (!c) {
|
|
Chris PeBenito |
473ea7 |
rc = -1;
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
c->callback = callback;
|
|
Chris PeBenito |
473ea7 |
c->events = events;
|
|
Chris PeBenito |
473ea7 |
c->ssid = ssid;
|
|
Chris PeBenito |
473ea7 |
c->tsid = tsid;
|
|
Chris PeBenito |
473ea7 |
c->tclass = tclass;
|
|
Chris PeBenito |
473ea7 |
c->perms = perms;
|
|
Chris PeBenito |
473ea7 |
c->next = avc_callbacks;
|
|
Chris PeBenito |
473ea7 |
avc_callbacks = c;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline int avc_sidcmp(security_id_t x, security_id_t y)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
return (x == y || x == SECSID_WILD || y == SECSID_WILD);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static inline void avc_update_node(u_int32_t event, struct avc_node *node,
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
switch (event) {
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_GRANT:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.allowed |= perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_TRY_REVOKE:
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_REVOKE:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.allowed &= ~perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_AUDITALLOW_ENABLE:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditallow |= perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_AUDITALLOW_DISABLE:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditallow &= ~perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_AUDITDENY_ENABLE:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditdeny |= perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case AVC_CALLBACK_AUDITDENY_DISABLE:
|
|
Chris PeBenito |
473ea7 |
node->ae.avd.auditdeny &= ~perms;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static int avc_update_cache(u_int32_t event, security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid, security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_node *node;
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
|
|
Chris PeBenito |
473ea7 |
/* apply to all matching nodes */
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
|
|
Chris PeBenito |
473ea7 |
for (node = avc_cache.slots[i]; node;
|
|
Chris PeBenito |
473ea7 |
node = node->next) {
|
|
Chris PeBenito |
473ea7 |
if (avc_sidcmp(ssid, node->ae.ssid) &&
|
|
Chris PeBenito |
473ea7 |
avc_sidcmp(tsid, node->ae.tsid) &&
|
|
Chris PeBenito |
473ea7 |
tclass == node->ae.tclass) {
|
|
Chris PeBenito |
473ea7 |
avc_update_node(event,node,perms);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
/* apply to one node */
|
|
Chris PeBenito |
473ea7 |
node = avc_search_node(ssid, tsid, tclass, 0);
|
|
Chris PeBenito |
473ea7 |
if (node) {
|
|
Chris PeBenito |
473ea7 |
avc_update_node(event,node,perms);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* avc_control - update cache and call callbacks
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* This should not be called directly; use the individual event
|
|
Chris PeBenito |
473ea7 |
* functions instead.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static int avc_control(u_int32_t event, security_id_t ssid,
|
|
Chris PeBenito |
473ea7 |
security_id_t tsid, security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
u_int32_t seqno, access_vector_t *out_retained)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_callback_node *c;
|
|
Chris PeBenito |
473ea7 |
access_vector_t tretained = 0, cretained = 0;
|
|
Chris PeBenito |
473ea7 |
int ret, rc = 0, errsave = 0;
|
|
Chris PeBenito |
473ea7 |
errno = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* try_revoke only removes permissions from the cache
|
|
Chris PeBenito |
473ea7 |
* state if they are not retained by the object manager.
|
|
Chris PeBenito |
473ea7 |
* Hence, try_revoke must wait until after the callbacks have
|
|
Chris PeBenito |
473ea7 |
* been invoked to update the cache state.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
if (event != AVC_CALLBACK_TRY_REVOKE)
|
|
Chris PeBenito |
473ea7 |
avc_update_cache(event,ssid,tsid,tclass,perms);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (c = avc_callbacks; c; c = c->next)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if ((c->events & event) &&
|
|
Chris PeBenito |
473ea7 |
avc_sidcmp(c->ssid, ssid) &&
|
|
Chris PeBenito |
473ea7 |
avc_sidcmp(c->tsid, tsid) &&
|
|
Chris PeBenito |
473ea7 |
c->tclass == tclass &&
|
|
Chris PeBenito |
473ea7 |
(c->perms & perms)) {
|
|
Chris PeBenito |
473ea7 |
cretained = 0;
|
|
Chris PeBenito |
473ea7 |
ret = c->callback(event, ssid, tsid, tclass,
|
|
Chris PeBenito |
473ea7 |
(c->perms & perms),
|
|
Chris PeBenito |
473ea7 |
&cretained);
|
|
Chris PeBenito |
473ea7 |
if (ret && !rc) {
|
|
Chris PeBenito |
473ea7 |
rc = ret;
|
|
Chris PeBenito |
473ea7 |
errsave = errno;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (!ret)
|
|
Chris PeBenito |
473ea7 |
tretained |= cretained;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (event == AVC_CALLBACK_TRY_REVOKE) {
|
|
Chris PeBenito |
473ea7 |
/* revoke any unretained permissions */
|
|
Chris PeBenito |
473ea7 |
perms &= ~tretained;
|
|
Chris PeBenito |
473ea7 |
avc_update_cache(event,ssid,tsid,tclass,perms);
|
|
Chris PeBenito |
473ea7 |
*out_retained = tretained;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
if (seqno > avc_cache.latest_notif)
|
|
Chris PeBenito |
473ea7 |
avc_cache.latest_notif = seqno;
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
errno = errsave;
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_grant - Grant previously denied permissions.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @perms: permissions to grant
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_grant(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
u_int32_t seqno)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_GRANT,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_try_revoke - Try to revoke previously granted permissions.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @perms: permissions to grant
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
* @out_retained: subset of @perms that are retained
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Try to revoke previously granted permissions, but
|
|
Chris PeBenito |
473ea7 |
* only if they are not retained as migrated permissions.
|
|
Chris PeBenito |
473ea7 |
* Return the subset of permissions that are retained via @out_retained.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t perms, u_int32_t seqno,
|
|
Chris PeBenito |
473ea7 |
access_vector_t *out_retained)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_TRY_REVOKE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, out_retained);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_revoke - Revoke previously granted permissions.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @perms: permissions to grant
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Revoke previously granted permissions, even if
|
|
Chris PeBenito |
473ea7 |
* they are retained as migrated permissions.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_revoke(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
u_int32_t seqno)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_REVOKE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_reset(u_int32_t seqno)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int rc;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_av_stats();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
rc = avc_reset();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
avc_get_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
if (seqno > avc_cache.latest_notif)
|
|
Chris PeBenito |
473ea7 |
avc_cache.latest_notif = seqno;
|
|
Chris PeBenito |
473ea7 |
avc_release_lock(avc_lock);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_set_auditallow - Enable or disable auditing of granted permissions.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @perms: permissions to grant
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
* @enable: enable flag.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
u_int32_t seqno, u_int32_t enable)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (enable)
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/**
|
|
Chris PeBenito |
473ea7 |
* avc_ss_set_auditdeny - Enable or disable auditing of denied permissions.
|
|
Chris PeBenito |
473ea7 |
* @ssid: source security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tsid: target security identifier or %SECSID_WILD
|
|
Chris PeBenito |
473ea7 |
* @tclass: target security class
|
|
Chris PeBenito |
473ea7 |
* @perms: permissions to grant
|
|
Chris PeBenito |
473ea7 |
* @seqno: policy sequence number
|
|
Chris PeBenito |
473ea7 |
* @enable: enable flag.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid,
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass, access_vector_t perms,
|
|
Chris PeBenito |
473ea7 |
u_int32_t seqno, u_int32_t enable)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (enable)
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE,
|
|
Chris PeBenito |
473ea7 |
ssid, tsid, tclass, perms, seqno, 0);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Other exported functions that use the string tables,
|
|
Chris PeBenito |
473ea7 |
formerly in helpers.c. */
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
#include <ctype.h>
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
#define NCLASSES ARRAY_SIZE(class_to_string)
|
|
Chris PeBenito |
473ea7 |
#define NVECTORS ARRAY_SIZE(av_perm_to_string)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
security_class_t string_to_security_class(const char *s)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
unsigned int val;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (isdigit(s[0])) {
|
|
Chris PeBenito |
473ea7 |
val = atoi(s);
|
|
Chris PeBenito |
473ea7 |
if (val > 0 && val < NCLASSES)
|
|
Chris PeBenito |
473ea7 |
return val;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
for (val = 0; val < NCLASSES; val++) {
|
|
Chris PeBenito |
473ea7 |
if (strcmp(s, (class_to_string_data.str
|
|
Chris PeBenito |
473ea7 |
+ class_to_string[val])) == 0)
|
|
Chris PeBenito |
473ea7 |
return val;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
access_vector_t string_to_av_perm(
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
const char *s)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
const u16 *common_pts_idx = 0;
|
|
Chris PeBenito |
473ea7 |
access_vector_t perm, common_base = 0;
|
|
Chris PeBenito |
473ea7 |
unsigned int i;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
|
|
Chris PeBenito |
473ea7 |
if (av_inherit[i].tclass == tclass) {
|
|
Chris PeBenito |
473ea7 |
common_pts_idx = &common_perm_to_string.data[av_inherit[i].common_pts_idx];
|
|
Chris PeBenito |
473ea7 |
common_base = av_inherit[i].common_base;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
i = 0;
|
|
Chris PeBenito |
473ea7 |
perm = 1;
|
|
Chris PeBenito |
473ea7 |
while (perm < common_base) {
|
|
Chris PeBenito |
473ea7 |
if (strcmp(s, common_perm_to_string_data.str + common_pts_idx[i]) == 0)
|
|
Chris PeBenito |
473ea7 |
return perm;
|
|
Chris PeBenito |
473ea7 |
perm <<= 1;
|
|
Chris PeBenito |
473ea7 |
i++;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < NVECTORS; i++) {
|
|
Chris PeBenito |
473ea7 |
if ((av_perm_to_string[i].tclass == tclass) &&
|
|
Chris PeBenito |
473ea7 |
(strcmp(s, (av_perm_to_string_data.str
|
|
Chris PeBenito |
473ea7 |
+ av_perm_to_string[i].nameidx)) == 0))
|
|
Chris PeBenito |
473ea7 |
return av_perm_to_string[i].value;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void print_access_vector(
|
|
Chris PeBenito |
473ea7 |
security_class_t tclass,
|
|
Chris PeBenito |
473ea7 |
access_vector_t av)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
const u16 *common_pts_idx = 0;
|
|
Chris PeBenito |
473ea7 |
access_vector_t common_base = 0;
|
|
Chris PeBenito |
473ea7 |
unsigned int i, i2, perm;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (av == 0) {
|
|
Chris PeBenito |
473ea7 |
printf(" null");
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < ARRAY_SIZE(av_inherit); i++) {
|
|
Chris PeBenito |
473ea7 |
if (av_inherit[i].tclass == tclass) {
|
|
Chris PeBenito |
473ea7 |
common_pts_idx = &common_perm_to_string.data[av_inherit[i].common_pts_idx];
|
|
Chris PeBenito |
473ea7 |
common_base = av_inherit[i].common_base;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
printf(" {");
|
|
Chris PeBenito |
473ea7 |
i = 0;
|
|
Chris PeBenito |
473ea7 |
perm = 1;
|
|
Chris PeBenito |
473ea7 |
while (perm < common_base) {
|
|
Chris PeBenito |
473ea7 |
if (perm & av)
|
|
Chris PeBenito |
473ea7 |
printf(" %s", common_perm_to_string_data.str + common_pts_idx[i]);
|
|
Chris PeBenito |
473ea7 |
i++;
|
|
Chris PeBenito |
473ea7 |
perm <<= 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while (i < sizeof(access_vector_t) * 8) {
|
|
Chris PeBenito |
473ea7 |
if (perm & av) {
|
|
Chris PeBenito |
473ea7 |
for (i2 = 0; i2 < NVECTORS; i2++) {
|
|
Chris PeBenito |
473ea7 |
if ((av_perm_to_string[i2].tclass == tclass) &&
|
|
Chris PeBenito |
473ea7 |
(av_perm_to_string[i2].value == perm))
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (i2 < NVECTORS)
|
|
Chris PeBenito |
473ea7 |
printf(" %s",
|
|
Chris PeBenito |
473ea7 |
av_perm_to_string_data.str
|
|
Chris PeBenito |
473ea7 |
+ av_perm_to_string[i2].nameidx);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
i++;
|
|
Chris PeBenito |
473ea7 |
perm <<= 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
printf(" }");
|
|
Chris PeBenito |
473ea7 |
}
|