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
}