aboutsummaryrefslogtreecommitdiffstats
path: root/xen/xsm/flask/avc.c
diff options
context:
space:
mode:
Diffstat (limited to 'xen/xsm/flask/avc.c')
-rw-r--r--xen/xsm/flask/avc.c107
1 files changed, 82 insertions, 25 deletions
diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c
index 74f160d89a..b5486a3bd4 100644
--- a/xen/xsm/flask/avc.c
+++ b/xen/xsm/flask/avc.c
@@ -132,12 +132,54 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
}
+/* no use making this larger than the printk buffer */
+#define AVC_BUF_SIZE 1024
+static DEFINE_SPINLOCK(avc_emerg_lock);
+static char avc_emerg_buf[AVC_BUF_SIZE];
+
+struct avc_dump_buf {
+ char *start;
+ char *pos;
+ u32 free;
+};
+
+static void avc_printk(struct avc_dump_buf *buf, const char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ again:
+ va_start(args, fmt);
+ i = vsnprintf(buf->pos, buf->free, fmt, args);
+ va_end(args);
+ if ( i < buf->free )
+ {
+ buf->pos += i;
+ buf->free -= i;
+ }
+ else if ( buf->free < AVC_BUF_SIZE )
+ {
+ buf->pos[0] = 0;
+ printk("%s", buf->start);
+ buf->pos = buf->start;
+ buf->free = AVC_BUF_SIZE;
+ goto again;
+ }
+ else
+ {
+ printk("%s", buf->start);
+ printk("\navc_printk: overflow\n");
+ buf->pos = buf->start;
+ buf->free = AVC_BUF_SIZE;
+ }
+}
+
/**
* avc_dump_av - Display an access vector in human-readable form.
* @tclass: target security class
* @av: access vector
*/
-static void avc_dump_av(u16 tclass, u32 av)
+static void avc_dump_av(struct avc_dump_buf *buf, u16 tclass, u32 av)
{
const char **common_pts = NULL;
u32 common_base = 0;
@@ -145,7 +187,7 @@ static void avc_dump_av(u16 tclass, u32 av)
if ( av == 0 )
{
- printk(" null");
+ avc_printk(buf, " null");
return;
}
@@ -159,14 +201,14 @@ static void avc_dump_av(u16 tclass, u32 av)
}
}
- printk(" {");
+ avc_printk(buf, " {");
i = 0;
perm = 1;
while ( perm < common_base )
{
if (perm & av)
{
- printk(" %s", common_pts[i]);
+ avc_printk(buf, " %s", common_pts[i]);
av &= ~perm;
}
i++;
@@ -185,7 +227,7 @@ static void avc_dump_av(u16 tclass, u32 av)
}
if ( i2 < ARRAY_SIZE(av_perm_to_string) )
{
- printk(" %s", av_perm_to_string[i2].name);
+ avc_printk(buf, " %s", av_perm_to_string[i2].name);
av &= ~perm;
}
}
@@ -194,9 +236,9 @@ static void avc_dump_av(u16 tclass, u32 av)
}
if ( av )
- printk(" 0x%x", av);
+ avc_printk(buf, " 0x%x", av);
- printk(" }");
+ avc_printk(buf, " }");
}
/**
@@ -205,7 +247,7 @@ static void avc_dump_av(u16 tclass, u32 av)
* @tsid: target security identifier
* @tclass: target security class
*/
-static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
+static void avc_dump_query(struct avc_dump_buf *buf, u32 ssid, u32 tsid, u16 tclass)
{
int rc;
char *scontext;
@@ -213,23 +255,23 @@ static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
rc = security_sid_to_context(ssid, &scontext, &scontext_len);
if ( rc )
- printk("ssid=%d", ssid);
+ avc_printk(buf, "ssid=%d", ssid);
else
{
- printk("scontext=%s", scontext);
+ avc_printk(buf, "scontext=%s", scontext);
xfree(scontext);
}
rc = security_sid_to_context(tsid, &scontext, &scontext_len);
if ( rc )
- printk(" tsid=%d", tsid);
+ avc_printk(buf, " tsid=%d", tsid);
else
{
- printk(" tcontext=%s", scontext);
+ avc_printk(buf, " tcontext=%s", scontext);
xfree(scontext);
}
- printk(" tclass=%s", class_to_string[tclass]);
+ avc_printk(buf, " tclass=%s", class_to_string[tclass]);
}
/**
@@ -544,6 +586,7 @@ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
{
struct domain *cdom = current->domain;
u32 denied, audited;
+ struct avc_dump_buf buf;
denied = requested & ~avd->allowed;
if ( denied )
@@ -562,36 +605,50 @@ void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
if ( !(audited & avd->auditallow) )
return;
}
+ buf.start = xmalloc_bytes(AVC_BUF_SIZE);
+ if ( !buf.start )
+ {
+ spin_lock(&avc_emerg_lock);
+ buf.start = avc_emerg_buf;
+ }
+ buf.pos = buf.start;
+ buf.free = AVC_BUF_SIZE;
- printk("avc: %s ", denied ? "denied" : "granted");
- avc_dump_av(tclass, audited);
- printk(" for ");
+ avc_printk(&buf, "avc: %s ", denied ? "denied" : "granted");
+ avc_dump_av(&buf, tclass, audited);
+ avc_printk(&buf, " for ");
if ( a && (a->sdom || a->tdom) )
{
if ( a->sdom && a->tdom && a->sdom != a->tdom )
- printk("domid=%d target=%d ", a->sdom->domain_id, a->tdom->domain_id);
+ avc_printk(&buf, "domid=%d target=%d ", a->sdom->domain_id, a->tdom->domain_id);
else if ( a->sdom )
- printk("domid=%d ", a->sdom->domain_id);
+ avc_printk(&buf, "domid=%d ", a->sdom->domain_id);
else
- printk("target=%d ", a->tdom->domain_id);
+ avc_printk(&buf, "target=%d ", a->tdom->domain_id);
}
else if ( cdom )
- printk("domid=%d ", cdom->domain_id);
+ avc_printk(&buf, "domid=%d ", cdom->domain_id);
switch ( a ? a->type : 0 ) {
case AVC_AUDIT_DATA_DEV:
- printk("device=0x%lx ", a->device);
+ avc_printk(&buf, "device=0x%lx ", a->device);
break;
case AVC_AUDIT_DATA_IRQ:
- printk("irq=%d ", a->irq);
+ avc_printk(&buf, "irq=%d ", a->irq);
break;
case AVC_AUDIT_DATA_RANGE:
- printk("range=0x%lx-0x%lx ", a->range.start, a->range.end);
+ avc_printk(&buf, "range=0x%lx-0x%lx ", a->range.start, a->range.end);
break;
}
- avc_dump_query(ssid, tsid, tclass);
- printk("\n");
+ avc_dump_query(&buf, ssid, tsid, tclass);
+ avc_printk(&buf, "\n");
+ printk("%s", buf.start);
+
+ if ( buf.start == avc_emerg_buf )
+ spin_unlock(&avc_emerg_lock);
+ else
+ xfree(buf.start);
}
/**