PERFORCE change 108822 for review
Todd Miller
millert at FreeBSD.org
Tue Oct 31 14:28:13 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=108822
Change 108822 by millert at millert_macbook on 2006/10/31 14:27:28
Update to latest selinux kernel code, binary policy version 21.
Adds support for range transitions on object classes.
We don't compile linux-specific netlabel or audit code.
Based on kernel/git/jmorris/selinux-2.6.20.git as of 26 Oct. 2006.
Affected files ...
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/avc/avc-selinux.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/avc/avc.c#5 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/linux-compat.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/sebsd_alloc.c#3 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/sebsd_alloc.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/context.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/ebitmap.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/ebitmap.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/init.c#3 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/mls.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/mls.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/policydb.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/policydb.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/security.h#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/services.c#2 edit
.. //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/ss/services.h#3 edit
Differences ...
==== //depot/projects/trustedbsd/sedarwin8/policies/sedarwin/sedarwin/avc/avc-selinux.c#2 (text+ko) ====
@@ -4,6 +4,9 @@
* Authors: Stephen Smalley, <sds at epoch.ncsc.mil>
* James Morris <jmorris at redhat.com>
*
+ * Update: KaiGai, Kohei <kaigai at ak.jp.nec.com>
+ * Replaced the avc_lock spinlock by RCU.
+ *
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris at redhat.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +21,7 @@
#include <linux/dcache.h>
#include <linux/init.h>
#include <linux/skbuff.h>
+#include <linux/percpu.h>
#include <net/sock.h>
#include <linux/un.h>
#include <net/af_unix.h>
@@ -27,35 +31,77 @@
#include <net/ipv6.h>
#include "avc.h"
#include "avc_ss.h"
-#ifdef CONFIG_AUDIT
+
+static const struct av_perm_to_string
+{
+ u16 tclass;
+ u32 value;
+ const char *name;
+} av_perm_to_string[] = {
+#define S_(c, v, s) { c, v, s },
+#include "av_perm_to_string.h"
+#undef S_
+};
+
+static const char *class_to_string[] = {
+#define S_(s) s,
#include "class_to_string.h"
-#endif
+#undef S_
+};
+
+#define TB_(s) static const char * s [] = {
+#define TE_(s) };
+#define S_(s) s,
#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+static const struct av_inherit
+{
+ u16 tclass;
+ const char **common_pts;
+ u32 common_base;
+} av_inherit[] = {
+#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
#include "av_inherit.h"
-#include "av_perm_to_string.h"
-#include "objsec.h"
+#undef S_
+};
+
+#define AVC_CACHE_SLOTS 512
+#define AVC_DEF_CACHE_THRESHOLD 512
+#define AVC_CACHE_RECLAIM 16
-#define AVC_CACHE_SLOTS 512
-#define AVC_CACHE_MAXNODES 410
+#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
+#define avc_cache_stats_incr(field) \
+do { \
+ per_cpu(avc_cache_stats, get_cpu()).field++; \
+ put_cpu(); \
+} while (0)
+#else
+#define avc_cache_stats_incr(field) do {} while (0)
+#endif
struct avc_entry {
u32 ssid;
u32 tsid;
u16 tclass;
struct av_decision avd;
- int used; /* used recently */
+ atomic_t used; /* used recently */
};
struct avc_node {
struct avc_entry ae;
- struct avc_node *next;
+ struct list_head list;
+ struct rcu_head rhead;
};
struct avc_cache {
- struct avc_node *slots[AVC_CACHE_SLOTS];
- u32 lru_hint; /* LRU hint for reclaim scan */
- u32 active_nodes;
- u32 latest_notif; /* latest revocation notification */
+ struct list_head slots[AVC_CACHE_SLOTS];
+ spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
+ atomic_t lru_hint; /* LRU hint for reclaim scan */
+ atomic_t active_nodes;
+ u32 latest_notif; /* latest revocation notification */
};
struct avc_callback_node {
@@ -70,43 +116,30 @@
struct avc_callback_node *next;
};
-static spinlock_t avc_lock = SPIN_LOCK_UNLOCKED;
-static struct avc_node *avc_node_freelist;
+/* Exported via selinufs */
+unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+
+#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
+DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
+#endif
+
static struct avc_cache avc_cache;
-static unsigned avc_cache_stats[AVC_NSTATS];
static struct avc_callback_node *avc_callbacks;
+static kmem_cache_t *avc_node_cachep;
static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
{
return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
}
-#ifdef AVC_CACHE_STATS
-static inline void avc_cache_stats_incr(int type)
-{
- avc_cache_stats[type]++;
-}
-
-static inline void avc_cache_stats_add(int type, unsigned val)
-{
- avc_cache_stats[type] += val;
-}
-#else
-static inline void avc_cache_stats_incr(int type)
-{ }
-
-static inline void avc_cache_stats_add(int type, unsigned val)
-{ }
-#endif
-
/**
* avc_dump_av - Display an access vector in human-readable form.
* @tclass: target security class
* @av: access vector
*/
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
{
- char **common_pts = NULL;
+ const char **common_pts = NULL;
u32 common_base = 0;
int i, i2, perm;
@@ -127,8 +160,10 @@
i = 0;
perm = 1;
while (perm < common_base) {
- if (perm & av)
+ if (perm & av) {
audit_log_format(ab, " %s", common_pts[i]);
+ av &= ~perm;
+ }
i++;
perm <<= 1;
}
@@ -140,14 +175,19 @@
(av_perm_to_string[i2].value == perm))
break;
}
- if (i2 < ARRAY_SIZE(av_perm_to_string))
+ if (i2 < ARRAY_SIZE(av_perm_to_string)) {
audit_log_format(ab, " %s",
av_perm_to_string[i2].name);
+ av &= ~perm;
+ }
}
i++;
perm <<= 1;
}
+ if (av)
+ audit_log_format(ab, " 0x%x", av);
+
audit_log_format(ab, " }");
}
@@ -157,7 +197,7 @@
* @tsid: target security identifier
* @tclass: target security class
*/
-void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
+static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass)
{
int rc;
char *scontext;
@@ -188,155 +228,161 @@
*/
void __init avc_init(void)
{
- struct avc_node *new;
int i;
- for (i = 0; i < AVC_CACHE_MAXNODES; i++) {
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
- if (!new) {
- printk(KERN_WARNING "avc: only able to allocate "
- "%d entries\n", i);
- break;
- }
- memset(new, 0, sizeof(*new));
- new->next = avc_node_freelist;
- avc_node_freelist = new;
+ for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+ INIT_LIST_HEAD(&avc_cache.slots[i]);
+ spin_lock_init(&avc_cache.slots_lock[i]);
}
+ atomic_set(&avc_cache.active_nodes, 0);
+ atomic_set(&avc_cache.lru_hint, 0);
- audit_log(current->audit_context, "AVC INITIALIZED\n");
+ avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
+ 0, SLAB_PANIC, NULL, NULL);
+
+ audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
}
-#if 0
-static void avc_hash_eval(char *tag)
+int avc_get_hash_stats(char *page)
{
int i, chain_len, max_chain_len, slots_used;
struct avc_node *node;
- unsigned long flags;
- spin_lock_irqsave(&avc_lock,flags);
+ rcu_read_lock();
slots_used = 0;
max_chain_len = 0;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- node = avc_cache.slots[i];
- if (node) {
+ if (!list_empty(&avc_cache.slots[i])) {
slots_used++;
chain_len = 0;
- while (node) {
+ list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
chain_len++;
- node = node->next;
- }
if (chain_len > max_chain_len)
max_chain_len = chain_len;
}
}
- spin_unlock_irqrestore(&avc_lock,flags);
+ rcu_read_unlock();
- printk(KERN_INFO "\n");
- printk(KERN_INFO "%s avc: %d entries and %d/%d buckets used, longest "
- "chain length %d\n", tag, avc_cache.active_nodes, slots_used,
- AVC_CACHE_SLOTS, max_chain_len);
+ return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
+ "longest chain: %d\n",
+ atomic_read(&avc_cache.active_nodes),
+ slots_used, AVC_CACHE_SLOTS, max_chain_len);
}
-#else
-static inline void avc_hash_eval(char *tag)
-{ }
-#endif
-static inline struct avc_node *avc_reclaim_node(void)
+static void avc_node_free(struct rcu_head *rhead)
{
- struct avc_node *prev, *cur;
- int hvalue, try;
+ struct avc_node *node = container_of(rhead, struct avc_node, rhead);
+ kmem_cache_free(avc_node_cachep, node);
+ avc_cache_stats_incr(frees);
+}
- hvalue = avc_cache.lru_hint;
- for (try = 0; try < 2; try++) {
- do {
- prev = NULL;
- cur = avc_cache.slots[hvalue];
- while (cur) {
- if (!cur->ae.used)
- goto found;
+static void avc_node_delete(struct avc_node *node)
+{
+ list_del_rcu(&node->list);
+ call_rcu(&node->rhead, avc_node_free);
+ atomic_dec(&avc_cache.active_nodes);
+}
- cur->ae.used = 0;
+static void avc_node_kill(struct avc_node *node)
+{
+ kmem_cache_free(avc_node_cachep, node);
+ avc_cache_stats_incr(frees);
+ atomic_dec(&avc_cache.active_nodes);
+}
- prev = cur;
- cur = cur->next;
- }
- hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1);
- } while (hvalue != avc_cache.lru_hint);
- }
+static void avc_node_replace(struct avc_node *new, struct avc_node *old)
+{
+ list_replace_rcu(&old->list, &new->list);
+ call_rcu(&old->rhead, avc_node_free);
+ atomic_dec(&avc_cache.active_nodes);
+}
- panic("avc_reclaim_node");
+static inline int avc_reclaim_node(void)
+{
+ struct avc_node *node;
+ int hvalue, try, ecx;
+ unsigned long flags;
-found:
- avc_cache.lru_hint = hvalue;
+ for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ ) {
+ hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
- if (prev == NULL)
- avc_cache.slots[hvalue] = cur->next;
- else
- prev->next = cur->next;
+ if (!spin_trylock_irqsave(&avc_cache.slots_lock[hvalue], flags))
+ continue;
- return cur;
+ list_for_each_entry(node, &avc_cache.slots[hvalue], list) {
+ if (atomic_dec_and_test(&node->ae.used)) {
+ /* Recently Unused */
+ avc_node_delete(node);
+ avc_cache_stats_incr(reclaims);
+ ecx++;
+ if (ecx >= AVC_CACHE_RECLAIM) {
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+ goto out;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+ }
+out:
+ return ecx;
}
-static inline struct avc_node *avc_claim_node(u32 ssid,
- u32 tsid, u16 tclass)
+static struct avc_node *avc_alloc_node(void)
{
- struct avc_node *new;
- int hvalue;
+ struct avc_node *node;
+
+ node = kmem_cache_alloc(avc_node_cachep, SLAB_ATOMIC);
+ if (!node)
+ goto out;
- hvalue = avc_hash(ssid, tsid, tclass);
- if (avc_node_freelist) {
- new = avc_node_freelist;
- avc_node_freelist = avc_node_freelist->next;
- avc_cache.active_nodes++;
- } else {
- new = avc_reclaim_node();
- if (!new)
- goto out;
- }
+ memset(node, 0, sizeof(*node));
+ INIT_RCU_HEAD(&node->rhead);
+ INIT_LIST_HEAD(&node->list);
+ atomic_set(&node->ae.used, 1);
+ avc_cache_stats_incr(allocations);
- new->ae.used = 1;
- new->ae.ssid = ssid;
- new->ae.tsid = tsid;
- new->ae.tclass = tclass;
- new->next = avc_cache.slots[hvalue];
- avc_cache.slots[hvalue] = new;
+ if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold)
+ avc_reclaim_node();
out:
- return new;
+ return node;
+}
+
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+ node->ae.ssid = ssid;
+ node->ae.tsid = tsid;
+ node->ae.tclass = tclass;
+ memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
}
-static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid,
- u16 tclass, int *probes)
+static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
{
- struct avc_node *cur;
+ struct avc_node *node, *ret = NULL;
int hvalue;
- int tprobes = 1;
hvalue = avc_hash(ssid, tsid, tclass);
- cur = avc_cache.slots[hvalue];
- while (cur != NULL &&
- (ssid != cur->ae.ssid ||
- tclass != cur->ae.tclass ||
- tsid != cur->ae.tsid)) {
- tprobes++;
- cur = cur->next;
+ list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list) {
+ if (ssid == node->ae.ssid &&
+ tclass == node->ae.tclass &&
+ tsid == node->ae.tsid) {
+ ret = node;
+ break;
+ }
}
- if (cur == NULL) {
+ if (ret == NULL) {
/* cache miss */
goto out;
}
/* cache hit */
- if (probes)
- *probes = tprobes;
-
- cur->ae.used = 1;
-
+ if (atomic_read(&ret->ae.used) != 1)
+ atomic_set(&ret->ae.used, 1);
out:
- return cur;
+ return ret;
}
/**
@@ -345,36 +391,52 @@
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
- * @aeref: AVC entry reference
*
* Look up an AVC entry that is valid for the
* @requested permissions between the SID pair
* (@ssid, @tsid), interpreting the permissions
* based on @tclass. If a valid AVC entry exists,
- * then this function updates @aeref to refer to the
- * entry and returns %0. Otherwise, this function
- * returns -%ENOENT.
+ * then this function return the avc_node.
+ * Otherwise, this function returns NULL.
*/
-int avc_lookup(u32 ssid, u32 tsid, u16 tclass,
- u32 requested, struct avc_entry_ref *aeref)
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
{
struct avc_node *node;
- int probes, rc = 0;
- avc_cache_stats_incr(AVC_CAV_LOOKUPS);
- node = avc_search_node(ssid, tsid, tclass,&probes);
+ avc_cache_stats_incr(lookups);
+ node = avc_search_node(ssid, tsid, tclass);
if (node && ((node->ae.avd.decided & requested) == requested)) {
- avc_cache_stats_incr(AVC_CAV_HITS);
- avc_cache_stats_add(AVC_CAV_PROBES,probes);
- aeref->ae = &node->ae;
+ avc_cache_stats_incr(hits);
goto out;
}
- avc_cache_stats_incr(AVC_CAV_MISSES);
- rc = -ENOENT;
+ node = NULL;
+ avc_cache_stats_incr(misses);
out:
- return rc;
+ return node;
+}
+
+static int avc_latest_notif_update(int seqno, int is_insert)
+{
+ int ret = 0;
+ static DEFINE_SPINLOCK(notif_lock);
+ unsigned long flag;
+
+ spin_lock_irqsave(¬if_lock, flag);
+ if (is_insert) {
+ if (seqno < avc_cache.latest_notif) {
+ printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
+ seqno, avc_cache.latest_notif);
+ ret = -EAGAIN;
+ }
+ } else {
+ if (seqno > avc_cache.latest_notif)
+ avc_cache.latest_notif = seqno;
+ }
+ spin_unlock_irqrestore(¬if_lock, flag);
+
+ return ret;
}
/**
@@ -383,7 +445,6 @@
* @tsid: target security identifier
* @tclass: target security class
* @ae: AVC entry
- * @aeref: AVC entry reference
*
* Insert an AVC entry for the SID pair
* (@ssid, @tsid) and class @tclass.
@@ -392,55 +453,55 @@
* response to a security_compute_av() call. If the
* sequence number @ae->avd.seqno is not less than the latest
* revocation notification, then the function copies
- * the access vectors into a cache entry, updates
- * @aeref to refer to the entry, and returns %0.
- * Otherwise, this function returns -%EAGAIN.
+ * the access vectors into a cache entry, returns
+ * avc_node inserted. Otherwise, this function returns NULL.
*/
-int avc_insert(u32 ssid, u32 tsid, u16 tclass,
- struct avc_entry *ae, struct avc_entry_ref *aeref)
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
{
- struct avc_node *node;
- int rc = 0;
+ struct avc_node *pos, *node = NULL;
+ int hvalue;
+ unsigned long flag;
- if (ae->avd.seqno < avc_cache.latest_notif) {
- printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
- ae->avd.seqno, avc_cache.latest_notif);
- rc = -EAGAIN;
+ if (avc_latest_notif_update(ae->avd.seqno, 1))
goto out;
- }
+
+ node = avc_alloc_node();
+ if (node) {
+ hvalue = avc_hash(ssid, tsid, tclass);
+ avc_node_populate(node, ssid, tsid, tclass, ae);
- node = avc_claim_node(ssid, tsid, tclass);
- if (!node) {
- rc = -ENOMEM;
- goto out;
+ spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+ list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+ if (pos->ae.ssid == ssid &&
+ pos->ae.tsid == tsid &&
+ pos->ae.tclass == tclass) {
+ avc_node_replace(node, pos);
+ goto found;
+ }
+ }
+ list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+found:
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
}
-
- node->ae.avd.allowed = ae->avd.allowed;
- node->ae.avd.decided = ae->avd.decided;
- node->ae.avd.auditallow = ae->avd.auditallow;
- node->ae.avd.auditdeny = ae->avd.auditdeny;
- node->ae.avd.seqno = ae->avd.seqno;
- aeref->ae = &node->ae;
out:
- return rc;
+ return node;
}
static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
- struct in6_addr *addr, u16 port,
+ struct in6_addr *addr, __be16 port,
char *name1, char *name2)
{
if (!ipv6_addr_any(addr))
- audit_log_format(ab, " %s=%04x:%04x:%04x:%04x:%04x:"
- "%04x:%04x:%04x", name1, NIP6(*addr));
+ audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr));
if (port)
audit_log_format(ab, " %s=%d", name2, ntohs(port));
}
static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
- u16 port, char *name1, char *name2)
+ __be16 port, char *name1, char *name2)
{
if (addr)
- audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
+ audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr));
if (port)
audit_log_format(ab, " %s=%d", name2, ntohs(port));
}
@@ -486,7 +547,7 @@
return;
}
- ab = audit_log_start(current->audit_context);
+ ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
if (!ab)
return; /* audit_panic has been called */
audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted");
@@ -495,33 +556,8 @@
if (a && a->tsk)
tsk = a->tsk;
if (tsk && tsk->pid) {
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- audit_log_format(ab, " pid=%d", tsk->pid);
- if (tsk == current)
- mm = current->mm;
- else
- mm = get_task_mm(tsk);
- if (mm) {
- if (down_read_trylock(&mm->mmap_sem)) {
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) &&
- vma->vm_file) {
- audit_log_d_path(ab, "exe=",
- vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
- break;
- }
- vma = vma->vm_next;
- }
- up_read(&mm->mmap_sem);
- }
- if (tsk != current)
- mmput(mm);
- } else {
- audit_log_format(ab, " comm=%s", tsk->comm);
- }
+ audit_log_format(ab, " pid=%d comm=", tsk->pid);
+ audit_log_untrustedstring(ab, tsk->comm);
}
if (a) {
switch (a->type) {
@@ -534,21 +570,18 @@
case AVC_AUDIT_DATA_FS:
if (a->u.fs.dentry) {
struct dentry *dentry = a->u.fs.dentry;
- if (a->u.fs.mnt) {
- audit_log_d_path(ab, "path=", dentry,
- a->u.fs.mnt);
- } else {
- audit_log_format(ab, " name=%s",
- dentry->d_name.name);
- }
+ if (a->u.fs.mnt)
+ audit_avc_path(dentry, a->u.fs.mnt);
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, dentry->d_name.name);
inode = dentry->d_inode;
} else if (a->u.fs.inode) {
struct dentry *dentry;
inode = a->u.fs.inode;
dentry = d_find_alias(inode);
if (dentry) {
- audit_log_format(ab, " name=%s",
- dentry->d_name.name);
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, dentry->d_name.name);
dput(dentry);
}
}
@@ -566,7 +599,7 @@
switch (sk->sk_family) {
case AF_INET: {
- struct inet_opt *inet = inet_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
avc_print_ipv4_addr(ab, inet->rcv_saddr,
inet->sport,
@@ -577,7 +610,7 @@
break;
}
case AF_INET6: {
- struct inet_opt *inet = inet_sk(sk);
+ struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *inet6 = inet6_sk(sk);
avc_print_ipv6_addr(ab, &inet6->rcv_saddr,
@@ -591,22 +624,20 @@
case AF_UNIX:
u = unix_sk(sk);
if (u->dentry) {
- audit_log_d_path(ab, "path=",
- u->dentry, u->mnt);
+ audit_avc_path(u->dentry, u->mnt);
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, u->dentry->d_name.name);
break;
}
if (!u->addr)
break;
len = u->addr->len-sizeof(short);
p = &u->addr->name->sun_path[0];
+ audit_log_format(ab, " path=");
if (*p)
- audit_log_format(ab,
- "path=%*.*s", len,
- len, p);
+ audit_log_untrustedstring(ab, p);
else
- audit_log_format(ab,
- "path=@%*.*s", len-1,
- len-1, p+1);
+ audit_log_hex(ab, p, len);
break;
}
}
@@ -686,8 +717,54 @@
return (x == y || x == SECSID_WILD || y == SECSID_WILD);
}
-static inline void avc_update_node(u32 event, struct avc_node *node, u32 perms)
+/**
+ * avc_update_node Update an AVC entry
+ * @event : Updating event
+ * @perms : Permission mask bits
+ * @ssid, at tsid, at tclass : identifier of an AVC entry
+ *
+ * if a valid AVC entry doesn't exist,this function returns -ENOENT.
+ * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
+ * otherwise, this function update the AVC entry. The original AVC-entry object
+ * will release later by RCU.
+ */
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
{
+ int hvalue, rc = 0;
+ unsigned long flag;
+ struct avc_node *pos, *node, *orig = NULL;
+
+ node = avc_alloc_node();
+ if (!node) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /* Lock the target slot */
+ hvalue = avc_hash(ssid, tsid, tclass);
+ spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+
+ list_for_each_entry(pos, &avc_cache.slots[hvalue], list){
+ if ( ssid==pos->ae.ssid &&
+ tsid==pos->ae.tsid &&
+ tclass==pos->ae.tclass ){
+ orig = pos;
+ break;
+ }
+ }
+
+ if (!orig) {
+ rc = -ENOENT;
+ avc_node_kill(node);
+ goto out_unlock;
+ }
+
+ /*
+ * Copy and replace original node.
+ */
+
+ avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+
switch (event) {
case AVC_CALLBACK_GRANT:
node->ae.avd.allowed |= perms;
@@ -709,255 +786,58 @@
node->ae.avd.auditdeny &= ~perms;
break;
}
-}
-
-static int avc_update_cache(u32 event, u32 ssid, u32 tsid,
- u16 tclass, u32 perms)
-{
- struct avc_node *node;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&avc_lock,flags);
-
- if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
- /* apply to all matching nodes */
- for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- for (node = avc_cache.slots[i]; node;
- node = node->next) {
- if (avc_sidcmp(ssid, node->ae.ssid) &&
- avc_sidcmp(tsid, node->ae.tsid) &&
- tclass == node->ae.tclass) {
- avc_update_node(event,node,perms);
- }
- }
- }
- } else {
- /* apply to one node */
- node = avc_search_node(ssid, tsid, tclass, NULL);
- if (node) {
- avc_update_node(event,node,perms);
- }
- }
-
- spin_unlock_irqrestore(&avc_lock,flags);
-
- return 0;
-}
-
-static int avc_control(u32 event, u32 ssid, u32 tsid,
- u16 tclass, u32 perms,
- u32 seqno, u32 *out_retained)
-{
- struct avc_callback_node *c;
- u32 tretained = 0, cretained = 0;
- int rc = 0;
- unsigned long flags;
-
- /*
- * try_revoke only removes permissions from the cache
- * state if they are not retained by the object manager.
- * Hence, try_revoke must wait until after the callbacks have
- * been invoked to update the cache state.
- */
- if (event != AVC_CALLBACK_TRY_REVOKE)
- avc_update_cache(event,ssid,tsid,tclass,perms);
-
- for (c = avc_callbacks; c; c = c->next)
- {
- if ((c->events & event) &&
- avc_sidcmp(c->ssid, ssid) &&
- avc_sidcmp(c->tsid, tsid) &&
- c->tclass == tclass &&
- (c->perms & perms)) {
- cretained = 0;
- rc = c->callback(event, ssid, tsid, tclass,
- (c->perms & perms),
- &cretained);
- if (rc)
- goto out;
- tretained |= cretained;
- }
- }
-
- if (event == AVC_CALLBACK_TRY_REVOKE) {
- /* revoke any unretained permissions */
- perms &= ~tretained;
- avc_update_cache(event,ssid,tsid,tclass,perms);
- *out_retained = tretained;
- }
-
- spin_lock_irqsave(&avc_lock,flags);
- if (seqno > avc_cache.latest_notif)
- avc_cache.latest_notif = seqno;
- spin_unlock_irqrestore(&avc_lock,flags);
-
+ avc_node_replace(node, orig);
+out_unlock:
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
out:
return rc;
}
/**
- * avc_ss_grant - Grant previously denied permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- */
-int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno)
-{
- return avc_control(AVC_CALLBACK_GRANT,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
- * avc_ss_try_revoke - Try to revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- * @out_retained: subset of @perms that are retained
- *
- * Try to revoke previously granted permissions, but
- * only if they are not retained as migrated permissions.
- * Return the subset of permissions that are retained via @out_retained.
- */
-int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno, u32 *out_retained)
-{
- return avc_control(AVC_CALLBACK_TRY_REVOKE,
- ssid, tsid, tclass, perms, seqno, out_retained);
-}
-
-/**
- * avc_ss_revoke - Revoke previously granted permissions.
- * @ssid: source security identifier or %SECSID_WILD
- * @tsid: target security identifier or %SECSID_WILD
- * @tclass: target security class
- * @perms: permissions to grant
- * @seqno: policy sequence number
- *
- * Revoke previously granted permissions, even if
- * they are retained as migrated permissions.
- */
-int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass,
- u32 perms, u32 seqno)
-{
- return avc_control(AVC_CALLBACK_REVOKE,
- ssid, tsid, tclass, perms, seqno, NULL);
-}
-
-/**
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
* @seqno: policy sequence number
*/
int avc_ss_reset(u32 seqno)
{
struct avc_callback_node *c;
- int i, rc = 0;
- struct avc_node *node, *tmp;
- unsigned long flags;
-
- avc_hash_eval("reset");
+ int i, rc = 0, tmprc;
+ unsigned long flag;
+ struct avc_node *node;
- spin_lock_irqsave(&avc_lock,flags);
-
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- node = avc_cache.slots[i];
- while (node) {
- tmp = node;
- node = node->next;
- tmp->ae.ssid = tmp->ae.tsid = SECSID_NULL;
- tmp->ae.tclass = SECCLASS_NULL;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the trustedbsd-cvs
mailing list