|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/4] flask: Update flask_op hypercall structure
Instead of placing string parsing inside the hypervisor, use binary
structures like other Xen hypercalls do.
This patch also removes libflask; if the old flask_* namespace is needed
for longer backwards compatability (it was noted as deprecated in July
2010), a shim redirecting to the proper xc_flask_* calls can be created.
Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
---
tools/libxc/xc_flask.c | 471 +++++++---------
tools/libxc/xc_private.h | 2 +
tools/libxc/xenctrl.h | 4 +-
xen/include/public/xsm/flask_op.h | 146 +++++-
xen/xsm/flask/avc.c | 13 +-
xen/xsm/flask/flask_op.c | 1128 +++++++++++--------------------------
xen/xsm/flask/include/avc.h | 3 +-
xen/xsm/flask/include/security.h | 4 +-
xen/xsm/flask/ss/services.c | 11 +-
9 files changed, 683 insertions(+), 1099 deletions(-)
diff --git a/tools/libxc/xc_flask.c b/tools/libxc/xc_flask.c
index d268098..80c5a2d 100644
--- a/tools/libxc/xc_flask.c
+++ b/tools/libxc/xc_flask.c
@@ -30,18 +30,21 @@
#include <sys/ioctl.h>
#include <stdint.h>
-#define OCON_PIRQ_STR "pirq"
-#define OCON_IOPORT_STR "ioport"
-#define OCON_IOMEM_STR "iomem"
-#define OCON_DEVICE_STR "pcidevice"
+#define OCON_ISID 0 /* initial SIDs */
+#define OCON_PIRQ 1 /* physical irqs */
+#define OCON_IOPORT 2 /* io ports */
+#define OCON_IOMEM 3 /* io memory */
+#define OCON_DEVICE 4 /* pci devices */
#define INITCONTEXTLEN 256
-int xc_flask_op(xc_interface *xch, flask_op_t *op)
+int xc_flask_op(xc_interface *xch, xen_flask_op_t *op)
{
int ret = -1;
DECLARE_HYPERCALL;
DECLARE_HYPERCALL_BOUNCE(op, sizeof(*op), XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
+ op->interface_version = XEN_FLASK_INTERFACE_VERSION;
+
if ( xc_hypercall_bounce_pre(xch, op) )
{
PERROR("Could not bounce memory for flask op hypercall");
@@ -63,402 +66,360 @@ int xc_flask_op(xc_interface *xch, flask_op_t *op)
return ret;
}
-int xc_flask_load(xc_interface *xc_handle, char *buf, uint32_t size)
+int xc_flask_load(xc_interface *xch, char *buf, uint32_t size)
{
int err;
- flask_op_t op;
-
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+ if ( xc_hypercall_bounce_pre(xch, buf) )
+ {
+ PERROR("Could not bounce memory for flask op hypercall");
+ return -1;
+ }
+
op.cmd = FLASK_LOAD;
- op.buf = buf;
- op.size = size;
+ op.u.load.size = size;
+ set_xen_guest_handle(op.u.load.buffer, buf);
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
+ err = xc_flask_op(xch, &op);
- return 0;
+ xc_hypercall_bounce_post(xch, buf);
+
+ return err;
}
-int xc_flask_context_to_sid(xc_interface *xc_handle, char *buf, uint32_t size,
uint32_t *sid)
+int xc_flask_context_to_sid(xc_interface *xch, char *buf, uint32_t size,
uint32_t *sid)
{
int err;
- flask_op_t op;
-
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+ if ( xc_hypercall_bounce_pre(xch, buf) )
+ {
+ PERROR("Could not bounce memory for flask op hypercall");
+ return -1;
+ }
+
op.cmd = FLASK_CONTEXT_TO_SID;
- op.buf = buf;
- op.size = size;
+ op.u.sid_context.size = size;
+ set_xen_guest_handle(op.u.sid_context.context, buf);
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- sscanf(buf, "%u", sid);
+ err = xc_flask_op(xch, &op);
- return 0;
+ if ( !err )
+ *sid = op.u.sid_context.sid;
+
+ xc_hypercall_bounce_post(xch, buf);
+
+ return err;
}
-int xc_flask_sid_to_context(xc_interface *xc_handle, int sid, char *buf,
uint32_t size)
+int xc_flask_sid_to_context(xc_interface *xch, int sid, char *buf, uint32_t
size)
{
int err;
- flask_op_t op;
-
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(buf, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+
+ if ( xc_hypercall_bounce_pre(xch, buf) )
+ {
+ PERROR("Could not bounce memory for flask op hypercall");
+ return -1;
+ }
+
op.cmd = FLASK_SID_TO_CONTEXT;
- op.buf = buf;
- op.size = size;
+ op.u.sid_context.sid = sid;
+ op.u.sid_context.size = size;
+ set_xen_guest_handle(op.u.sid_context.context, buf);
- snprintf(buf, size, "%u", sid);
+ err = xc_flask_op(xch, &op);
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- return 0;
+ xc_hypercall_bounce_post(xch, buf);
+
+ return err;
}
-int xc_flask_getenforce(xc_interface *xc_handle)
+int xc_flask_getenforce(xc_interface *xch)
{
- int err;
- flask_op_t op;
- char buf[20];
- int size = 20;
- int mode;
-
+ DECLARE_FLASK_OP;
op.cmd = FLASK_GETENFORCE;
- op.buf = buf;
- op.size = size;
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- sscanf(buf, "%i", &mode);
-
- return mode;
+ return xc_flask_op(xch, &op);
}
-int xc_flask_setenforce(xc_interface *xc_handle, int mode)
+int xc_flask_setenforce(xc_interface *xch, int mode)
{
- int err;
- flask_op_t op;
- char buf[20];
- int size = 20;
-
+ DECLARE_FLASK_OP;
op.cmd = FLASK_SETENFORCE;
- op.buf = buf;
- op.size = size;
+ op.u.enforce.enforcing = mode;
- snprintf(buf, size, "%i", mode);
-
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- return 0;
+ return xc_flask_op(xch, &op);
}
-int xc_flask_getbool_byid(xc_interface *xc_handle, int id, char *name,
uint32_t size, int *curr, int *pend)
+int xc_flask_getbool_byid(xc_interface *xch, int id, char *name, uint32_t
size, int *curr, int *pend)
{
- flask_op_t op;
- char buf[255];
int rv;
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(name, size, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+
+ if ( xc_hypercall_bounce_pre(xch, name) )
+ {
+ PERROR("Could not bounce memory for flask op hypercall");
+ return -1;
+ }
- op.cmd = FLASK_GETBOOL2;
- op.buf = buf;
- op.size = 255;
+ op.cmd = FLASK_GETBOOL;
+ op.u.boolean.bool_id = id;
+ op.u.boolean.size = size;
+ set_xen_guest_handle(op.u.boolean.name, name);
- snprintf(buf, sizeof buf, "%i", id);
+ rv = xc_flask_op(xch, &op);
- rv = xc_flask_op(xc_handle, &op);
+ xc_hypercall_bounce_post(xch, name);
if ( rv )
return rv;
- sscanf(buf, "%i %i %s", curr, pend, name);
+ if ( curr )
+ *curr = op.u.boolean.enforcing;
+ if ( pend )
+ *pend = op.u.boolean.pending;
return rv;
}
-int xc_flask_getbool_byname(xc_interface *xc_handle, char *name, int *curr,
int *pend)
+int xc_flask_getbool_byname(xc_interface *xch, char *name, int *curr, int
*pend)
{
- flask_op_t op;
- char buf[255];
int rv;
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(name, strlen(name),
XC_HYPERCALL_BUFFER_BOUNCE_IN);
- op.cmd = FLASK_GETBOOL_NAMED;
- op.buf = buf;
- op.size = 255;
+ op.cmd = FLASK_GETBOOL;
+ op.u.boolean.bool_id = -1;
+ op.u.boolean.size = strlen(name);
+ set_xen_guest_handle(op.u.boolean.name, name);
- strncpy(buf, name, op.size);
+ rv = xc_flask_op(xch, &op);
- rv = xc_flask_op(xc_handle, &op);
+ xc_hypercall_bounce_post(xch, name);
if ( rv )
return rv;
- sscanf(buf, "%i %i", curr, pend);
+ if ( curr )
+ *curr = op.u.boolean.enforcing;
+ if ( pend )
+ *pend = op.u.boolean.pending;
return rv;
}
-int xc_flask_setbool(xc_interface *xc_handle, char *name, int value, int
commit)
+int xc_flask_setbool(xc_interface *xch, char *name, int value, int commit)
{
- flask_op_t op;
- char buf[255];
- int size = 255;
+ int rv;
+ DECLARE_FLASK_OP;
+ DECLARE_HYPERCALL_BOUNCE(name, strlen(name),
XC_HYPERCALL_BUFFER_BOUNCE_IN);
- op.cmd = FLASK_SETBOOL_NAMED;
- op.buf = buf;
- op.size = size;
+ op.cmd = FLASK_SETBOOL;
+ op.u.boolean.bool_id = -1;
+ op.u.boolean.new_value = value;
+ op.u.boolean.commit = 1;
+ op.u.boolean.size = strlen(name);
+ set_xen_guest_handle(op.u.boolean.name, name);
- snprintf(buf, size, "%s %i %i", name, value, commit);
+ rv = xc_flask_op(xch, &op);
- return xc_flask_op(xc_handle, &op);
+ xc_hypercall_bounce_post(xch, name);
+
+ return rv;
}
-static int xc_flask_add(xc_interface *xc_handle, char *cat, char *arg, char
*scontext)
+
+static int xc_flask_add(xc_interface *xch, uint32_t ocon, uint64_t low,
uint64_t high, char *scontext)
{
- char buf[512];
- flask_op_t op;
+ uint32_t sid;
+ int err;
+ DECLARE_FLASK_OP;
+
+ err = xc_flask_context_to_sid(xch, scontext, strlen(scontext), &sid);
+ if ( err )
+ return err;
- memset(buf, 0, 512);
- snprintf(buf, 512, "%s %255s %s", cat, scontext, arg);
op.cmd = FLASK_ADD_OCONTEXT;
- op.buf = buf;
- op.size = 512;
+ op.u.ocontext.ocon = ocon;
+ op.u.ocontext.sid = sid;
+ op.u.ocontext.low = low;
+ op.u.ocontext.high = high;
- return xc_flask_op(xc_handle, &op);
+ return xc_flask_op(xch, &op);
}
-int xc_flask_add_pirq(xc_interface *xc_handle, unsigned int pirq, char
*scontext)
+int xc_flask_add_pirq(xc_interface *xch, unsigned int pirq, char *scontext)
{
- char arg[16];
-
- snprintf(arg, 16, "%u", pirq);
- return xc_flask_add(xc_handle, OCON_PIRQ_STR, arg, scontext);
+ return xc_flask_add(xch, OCON_PIRQ, pirq, pirq, scontext);
}
-int xc_flask_add_ioport(xc_interface *xc_handle, unsigned long low, unsigned
long high,
+int xc_flask_add_ioport(xc_interface *xch, unsigned long low, unsigned long
high,
char *scontext)
{
- char arg[64];
-
- snprintf(arg, 64, "%lu %lu", low, high);
- return xc_flask_add(xc_handle, OCON_IOPORT_STR, arg, scontext);
+ return xc_flask_add(xch, OCON_IOPORT, low, high, scontext);
}
-int xc_flask_add_iomem(xc_interface *xc_handle, unsigned long low, unsigned
long high,
+int xc_flask_add_iomem(xc_interface *xch, unsigned long low, unsigned long
high,
char *scontext)
{
- char arg[64];
-
- snprintf(arg, 64, "%lu %lu", low, high);
- return xc_flask_add(xc_handle, OCON_IOMEM_STR, arg, scontext);
+ return xc_flask_add(xch, OCON_IOMEM, low, high, scontext);
}
-int xc_flask_add_device(xc_interface *xc_handle, unsigned long device, char
*scontext)
+int xc_flask_add_device(xc_interface *xch, unsigned long device, char
*scontext)
{
- char arg[32];
-
- snprintf(arg, 32, "%lu", device);
- return xc_flask_add(xc_handle, OCON_DEVICE_STR, arg, scontext);
+ return xc_flask_add(xch, OCON_DEVICE, device, device, scontext);
}
-static int xc_flask_del(xc_interface *xc_handle, char *cat, char *arg)
+static int xc_flask_del(xc_interface *xch, uint32_t ocon, uint64_t low,
uint64_t high)
{
- char buf[256];
- flask_op_t op;
+ DECLARE_FLASK_OP;
- memset(buf, 0, 256);
- snprintf(buf, 256, "%s %s", cat, arg);
op.cmd = FLASK_DEL_OCONTEXT;
- op.buf = buf;
- op.size = 256;
+ op.u.ocontext.ocon = ocon;
+ op.u.ocontext.low = low;
+ op.u.ocontext.high = high;
- return xc_flask_op(xc_handle, &op);
+ return xc_flask_op(xch, &op);
}
-int xc_flask_del_pirq(xc_interface *xc_handle, unsigned int pirq)
+int xc_flask_del_pirq(xc_interface *xch, unsigned int pirq)
{
- char arg[16];
-
- snprintf(arg, 16, "%u", pirq);
- return xc_flask_del(xc_handle, OCON_PIRQ_STR, arg);
+ return xc_flask_del(xch, OCON_PIRQ, pirq, pirq);
}
-int xc_flask_del_ioport(xc_interface *xc_handle, unsigned long low, unsigned
long high)
+int xc_flask_del_ioport(xc_interface *xch, unsigned long low, unsigned long
high)
{
- char arg[64];
-
- snprintf(arg, 64, "%lu %lu", low, high);
- return xc_flask_del(xc_handle, OCON_IOPORT_STR, arg);
+ return xc_flask_del(xch, OCON_IOPORT, low, high);
}
-int xc_flask_del_iomem(xc_interface *xc_handle, unsigned long low, unsigned
long high)
+int xc_flask_del_iomem(xc_interface *xch, unsigned long low, unsigned long
high)
{
- char arg[64];
-
- snprintf(arg, 64, "%lu %lu", low, high);
- return xc_flask_del(xc_handle, OCON_IOMEM_STR, arg);
+ return xc_flask_del(xch, OCON_IOMEM, low, high);
}
-int xc_flask_del_device(xc_interface *xc_handle, unsigned long device)
+int xc_flask_del_device(xc_interface *xch, unsigned long device)
{
- char arg[32];
-
- snprintf(arg, 32, "%lu", device);
- return xc_flask_del(xc_handle, OCON_DEVICE_STR, arg);
+ return xc_flask_del(xch, OCON_DEVICE, device, device);
}
-int xc_flask_access(xc_interface *xc_handle, const char *scon, const char
*tcon,
+int xc_flask_access(xc_interface *xch, const char *scon, const char *tcon,
uint16_t tclass, uint32_t req,
uint32_t *allowed, uint32_t *decided,
uint32_t *auditallow, uint32_t *auditdeny,
uint32_t *seqno)
{
-/* maximum number of digits in a 16-bit decimal number: */
-#define MAX_SHORT_DEC_LEN 5
-
- char *buf;
- int bufLen;
+ DECLARE_FLASK_OP;
int err;
- flask_op_t op;
- uint32_t dummy_allowed;
- uint32_t dummy_decided;
- uint32_t dummy_auditallow;
- uint32_t dummy_auditdeny;
- uint32_t dummy_seqno;
-
- if (!allowed)
- allowed = &dummy_allowed;
- if (!decided)
- decided = &dummy_decided;
- if (!auditallow)
- auditallow = &dummy_auditallow;
- if (!auditdeny)
- auditdeny = &dummy_auditdeny;
- if (!seqno)
- seqno = &dummy_seqno;
-
- if (!scon)
- return -EINVAL;
- if (!tcon)
- return -EINVAL;
-
- bufLen = strlen(scon) + 1 + strlen(tcon) + 1 +
- MAX_SHORT_DEC_LEN + 1 +
- sizeof(req)*2 + 1;
- buf = malloc(bufLen);
- snprintf(buf, bufLen, "%s %s %hu %x", scon, tcon, tclass, req);
+
+ err = xc_flask_context_to_sid(xch, (char*)scon, strlen(scon),
&op.u.access.ssid);
+ if ( err )
+ return err;
+ err = xc_flask_context_to_sid(xch, (char*)tcon, strlen(tcon),
&op.u.access.tsid);
+ if ( err )
+ return err;
op.cmd = FLASK_ACCESS;
- op.buf = buf;
- op.size = strlen(buf)+1;
+ op.u.access.tclass = tclass;
+ op.u.access.req = req;
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- {
- free(buf);
+ err = xc_flask_op(xch, &op);
+
+ if ( err )
return err;
- }
-
- if (sscanf(op.buf, "%x %x %x %x %u",
- allowed, decided,
- auditallow, auditdeny,
- seqno) != 5) {
- err = -EILSEQ;
- }
- err = ((*allowed & req) == req)? 0 : -EPERM;
+ if ( allowed )
+ *allowed = op.u.access.allowed;
+ if ( decided )
+ *decided = 0xffffffff;
+ if ( auditallow )
+ *auditallow = op.u.access.audit_allow;
+ if ( auditdeny )
+ *auditdeny = op.u.access.audit_deny;
+ if ( seqno )
+ *seqno = op.u.access.seqno;
- return err;
+ if ( (op.u.access.allowed & req) != req )
+ err = -EPERM;
+ return err;
}
-int xc_flask_avc_hashstats(xc_interface *xc_handle, char *buf, int size)
+int xc_flask_avc_hashstats(xc_interface *xch, char *buf, int size)
{
int err;
- flask_op_t op;
+ DECLARE_FLASK_OP;
op.cmd = FLASK_AVC_HASHSTATS;
- op.buf = buf;
- op.size = size;
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- {
- free(buf);
- return err;
- }
+ err = xc_flask_op(xch, &op);
- return 0;
+ snprintf(buf, size,
+ "entries: %d\nbuckets used: %d/%d\nlongest chain: %d\n",
+ op.u.hash_stats.entries, op.u.hash_stats.buckets_used,
+ op.u.hash_stats.buckets_total, op.u.hash_stats.max_chain_len);
+
+ return err;
}
-int xc_flask_avc_cachestats(xc_interface *xc_handle, char *buf, int size)
+int xc_flask_avc_cachestats(xc_interface *xch, char *buf, int size)
{
- int err;
- flask_op_t op;
+ int err, n;
+ int i = 0;
+ DECLARE_FLASK_OP;
+
+ n = snprintf(buf, size, "lookups hits misses allocations reclaims
frees\n");
+ buf += n;
+ size -= n;
op.cmd = FLASK_AVC_CACHESTATS;
- op.buf = buf;
- op.size = size;
-
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ while ( size > 0 )
{
- free(buf);
- return err;
+ op.u.cache_stats.cpu = i;
+ err = xc_flask_op(xch, &op);
+ if ( err && errno == ENOENT )
+ return 0;
+ if ( err )
+ return err;
+ n = snprintf(buf, size, "%u %u %u %u %u %u\n",
+ op.u.cache_stats.lookups, op.u.cache_stats.hits,
+ op.u.cache_stats.misses, op.u.cache_stats.allocations,
+ op.u.cache_stats.reclaims, op.u.cache_stats.frees);
+ buf += n;
+ size -= n;
+ i++;
}
return 0;
}
-int xc_flask_policyvers(xc_interface *xc_handle, char *buf, int size)
+int xc_flask_policyvers(xc_interface *xch)
{
- int err;
- flask_op_t op;
-
+ DECLARE_FLASK_OP;
op.cmd = FLASK_POLICYVERS;
- op.buf = buf;
- op.size = size;
-
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- {
- free(buf);
- return err;
- }
- return 0;
+ return xc_flask_op(xch, &op);
}
-int xc_flask_getavc_threshold(xc_interface *xc_handle)
+int xc_flask_getavc_threshold(xc_interface *xch)
{
- int err;
- flask_op_t op;
- char buf[20];
- int size = 20;
- int threshold;
-
+ DECLARE_FLASK_OP;
op.cmd = FLASK_GETAVC_THRESHOLD;
- op.buf = buf;
- op.size = size;
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- sscanf(buf, "%i", &threshold);
-
- return threshold;
+ return xc_flask_op(xch, &op);
}
-int xc_flask_setavc_threshold(xc_interface *xc_handle, int threshold)
+int xc_flask_setavc_threshold(xc_interface *xch, int threshold)
{
- int err;
- flask_op_t op;
- char buf[20];
- int size = 20;
-
+ DECLARE_FLASK_OP;
op.cmd = FLASK_SETAVC_THRESHOLD;
- op.buf = buf;
- op.size = size;
+ op.u.setavc_threshold.threshold = threshold;
- snprintf(buf, size, "%i", threshold);
-
- if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
- return err;
-
- return 0;
+ return xc_flask_op(xch, &op);
}
/*
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 3687561..7b83ef3 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -42,11 +42,13 @@
#define DECLARE_DOMCTL struct xen_domctl domctl = { 0 }
#define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 }
#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op = { 0 }
+#define DECLARE_FLASK_OP struct xen_flask_op op = { 0 }
#else
#define DECLARE_HYPERCALL privcmd_hypercall_t hypercall
#define DECLARE_DOMCTL struct xen_domctl domctl
#define DECLARE_SYSCTL struct xen_sysctl sysctl
#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op
+#define DECLARE_FLASK_OP struct xen_flask_op op
#endif
#undef PAGE_SHIFT
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 1e7c32b..6b3202e 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1328,7 +1328,7 @@ int xc_sysctl(xc_interface *xch, struct xen_sysctl
*sysctl);
int xc_version(xc_interface *xch, int cmd, void *arg);
-int xc_flask_op(xc_interface *xch, flask_op_t *op);
+int xc_flask_op(xc_interface *xch, xen_flask_op_t *op);
/*
* Subscribe to state changes in a domain via evtchn.
@@ -1976,7 +1976,7 @@ int xc_flask_access(xc_interface *xc_handle, const char
*scon, const char *tcon,
uint32_t *auditallow, uint32_t *auditdeny,
uint32_t *seqno);
int xc_flask_avc_cachestats(xc_interface *xc_handle, char *buf, int size);
-int xc_flask_policyvers(xc_interface *xc_handle, char *buf, int size);
+int xc_flask_policyvers(xc_interface *xc_handle);
int xc_flask_avc_hashstats(xc_interface *xc_handle, char *buf, int size);
int xc_flask_getavc_threshold(xc_interface *xc_handle);
int xc_flask_setavc_threshold(xc_interface *xc_handle, int threshold);
diff --git a/xen/include/public/xsm/flask_op.h
b/xen/include/public/xsm/flask_op.h
index 416ac08..83dcd99 100644
--- a/xen/include/public/xsm/flask_op.h
+++ b/xen/include/public/xsm/flask_op.h
@@ -25,6 +25,118 @@
#ifndef __FLASK_OP_H__
#define __FLASK_OP_H__
+#define XEN_FLASK_INTERFACE_VERSION 1
+
+struct xen_flask_load {
+ XEN_GUEST_HANDLE(char) buffer;
+ uint32_t size;
+};
+
+struct xen_flask_setenforce {
+ uint32_t enforcing;
+};
+
+struct xen_flask_sid_context {
+ /* IN/OUT: sid to convert to/from string */
+ uint32_t sid;
+ /* IN: size of the context buffer
+ * OUT: actual size of the output context string
+ */
+ uint32_t size;
+ XEN_GUEST_HANDLE(char) context;
+};
+
+struct xen_flask_access {
+ /* IN: access request */
+ uint32_t ssid;
+ uint32_t tsid;
+ uint32_t tclass;
+ uint32_t req;
+ /* OUT: AVC data */
+ uint32_t allowed;
+ uint32_t audit_allow;
+ uint32_t audit_deny;
+ uint32_t seqno;
+};
+
+struct xen_flask_transition {
+ /* IN: transition SIDs and class */
+ uint32_t ssid;
+ uint32_t tsid;
+ uint32_t tclass;
+ /* OUT: new SID */
+ uint32_t newsid;
+};
+
+struct xen_flask_userlist {
+ /* IN: starting SID for list */
+ uint32_t start_sid;
+ /* IN: size of user string and output buffer
+ * OUT: number of SIDs returned */
+ uint32_t size;
+ union {
+ /* IN: user to enumerate SIDs */
+ XEN_GUEST_HANDLE(char) user;
+ /* OUT: SID list */
+ XEN_GUEST_HANDLE(uint32) sids;
+ } u;
+};
+
+struct xen_flask_boolean {
+ /* IN/OUT: numeric identifier for boolean [GET/SET]
+ * If -1, name will be used and bool_id will be filled in. */
+ uint32_t bool_id;
+ /* OUT: current enforcing value of boolean [GET/SET] */
+ uint8_t enforcing;
+ /* OUT: pending value of boolean [GET/SET] */
+ uint8_t pending;
+ /* IN: new value of boolean [SET] */
+ uint8_t new_value;
+ /* IN: commit new value instead of only setting pending [SET] */
+ uint8_t commit;
+ /* IN: size of boolean name buffer [GET/SET]
+ * OUT: actual size of name [GET only] */
+ uint32_t size;
+ /* IN: if bool_id is -1, used to find boolean [GET/SET]
+ * OUT: textual name of boolean [GET only]
+ */
+ XEN_GUEST_HANDLE(char) name;
+};
+
+struct xen_flask_setavc_threshold {
+ /* IN */
+ uint32_t threshold;
+};
+
+struct xen_flask_hash_stats {
+ /* OUT */
+ uint32_t entries;
+ uint32_t buckets_used;
+ uint32_t buckets_total;
+ uint32_t max_chain_len;
+};
+
+struct xen_flask_cache_stats {
+ /* IN */
+ uint32_t cpu;
+ /* OUT */
+ uint32_t lookups;
+ uint32_t hits;
+ uint32_t misses;
+ uint32_t allocations;
+ uint32_t reclaims;
+ uint32_t frees;
+};
+
+struct xen_flask_ocontext {
+ /* IN */
+ uint32_t ocon;
+ uint32_t sid;
+ uint64_t low, high;
+};
+
+struct xen_flask_op {
+ uint32_t cmd;
#define FLASK_LOAD 1
#define FLASK_GETENFORCE 2
#define FLASK_SETENFORCE 3
@@ -47,18 +159,26 @@
#define FLASK_MEMBER 20
#define FLASK_ADD_OCONTEXT 21
#define FLASK_DEL_OCONTEXT 22
-#define FLASK_GETBOOL_NAMED 23
-#define FLASK_GETBOOL2 24
-#define FLASK_SETBOOL_NAMED 25
-
-#define FLASK_LAST FLASK_SETBOOL_NAMED
-
-typedef struct flask_op {
- uint32_t cmd;
- uint32_t size;
- char *buf;
-} flask_op_t;
-
-DEFINE_XEN_GUEST_HANDLE(flask_op_t);
+ uint32_t interface_version; /* XEN_FLASK_INTERFACE_VERSION */
+ union {
+ struct xen_flask_load load;
+ struct xen_flask_setenforce enforce;
+ /* FLASK_CONTEXT_TO_SID and FLASK_SID_TO_CONTEXT */
+ struct xen_flask_sid_context sid_context;
+ struct xen_flask_access access;
+ /* FLASK_CREATE, FLASK_RELABEL, FLASK_MEMBER */
+ struct xen_flask_transition transition;
+ struct xen_flask_userlist userlist;
+ /* FLASK_GETBOOL, FLASK_SETBOOL */
+ struct xen_flask_boolean boolean;
+ struct xen_flask_setavc_threshold setavc_threshold;
+ struct xen_flask_hash_stats hash_stats;
+ struct xen_flask_cache_stats cache_stats;
+ /* FLASK_ADD_OCONTEXT, FLASK_DEL_OCONTEXT */
+ struct xen_flask_ocontext ocontext;
+ } u;
+};
+typedef struct xen_flask_op xen_flask_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_flask_op_t);
#endif
diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c
index 3a60a3a..74f160d 100644
--- a/xen/xsm/flask/avc.c
+++ b/xen/xsm/flask/avc.c
@@ -28,6 +28,7 @@
#include <xen/rcupdate.h>
#include <asm/atomic.h>
#include <asm/current.h>
+#include <public/xsm/flask_op.h>
#include "avc.h"
#include "avc_ss.h"
@@ -251,7 +252,7 @@ void __init avc_init(void)
printk("AVC INITIALIZED\n");
}
-int avc_get_hash_stats(char *buf, uint32_t size)
+int avc_get_hash_stats(struct xen_flask_hash_stats *arg)
{
int i, chain_len, max_chain_len, slots_used;
struct avc_node *node;
@@ -279,10 +280,12 @@ int avc_get_hash_stats(char *buf, uint32_t size)
rcu_read_unlock(&avc_rcu_lock);
- return snprintf(buf, 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);
+ arg->entries = atomic_read(&avc_cache.active_nodes);
+ arg->buckets_used = slots_used;
+ arg->buckets_total = AVC_CACHE_SLOTS;
+ arg->max_chain_len = max_chain_len;
+
+ return 0;
}
static void avc_node_free(struct rcu_head *rhead)
diff --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c
index 64d9ec5..00a0af2 100644
--- a/xen/xsm/flask/flask_op.c
+++ b/xen/xsm/flask/flask_op.c
@@ -30,48 +30,21 @@ integer_param("flask_enabled", flask_enabled);
#endif
#define MAX_POLICY_SIZE 0x4000000
-#define FLASK_COPY_IN \
- ( \
- 1UL<<FLASK_LOAD | \
- 1UL<<FLASK_SETENFORCE | \
- 1UL<<FLASK_CONTEXT_TO_SID | \
- 1UL<<FLASK_SID_TO_CONTEXT | \
- 1UL<<FLASK_ACCESS | \
- 1UL<<FLASK_CREATE | \
- 1UL<<FLASK_RELABEL | \
- 1UL<<FLASK_USER | \
- 1UL<<FLASK_GETBOOL | \
- 1UL<<FLASK_SETBOOL | \
- 1UL<<FLASK_COMMITBOOLS | \
- 1UL<<FLASK_DISABLE | \
- 1UL<<FLASK_SETAVC_THRESHOLD | \
- 1UL<<FLASK_MEMBER | \
- 1UL<<FLASK_ADD_OCONTEXT | \
- 1UL<<FLASK_DEL_OCONTEXT | \
- 1UL<<FLASK_GETBOOL_NAMED | \
- 1UL<<FLASK_GETBOOL2 | \
- 1UL<<FLASK_SETBOOL_NAMED \
- )
#define FLASK_COPY_OUT \
( \
- 1UL<<FLASK_GETENFORCE | \
1UL<<FLASK_CONTEXT_TO_SID | \
1UL<<FLASK_SID_TO_CONTEXT | \
1UL<<FLASK_ACCESS | \
1UL<<FLASK_CREATE | \
1UL<<FLASK_RELABEL | \
1UL<<FLASK_USER | \
- 1UL<<FLASK_POLICYVERS | \
1UL<<FLASK_GETBOOL | \
- 1UL<<FLASK_MLS | \
- 1UL<<FLASK_GETAVC_THRESHOLD | \
+ 1UL<<FLASK_SETBOOL | \
1UL<<FLASK_AVC_HASHSTATS | \
1UL<<FLASK_AVC_CACHESTATS | \
1UL<<FLASK_MEMBER | \
- 1UL<<FLASK_GETBOOL_NAMED | \
- 1UL<<FLASK_GETBOOL2 \
- )
+ 0)
static DEFINE_SPINLOCK(sel_sem);
@@ -96,412 +69,186 @@ static int domain_has_security(struct domain *d, u32
perms)
perms, NULL);
}
-static int flask_security_user(char *buf, uint32_t size)
-{
- char *page = NULL;
- char *con, *user, *ptr;
- u32 sid, *sids;
- int length;
- char *newcon;
- int i, rc;
- u32 len, nsids;
-
- length = domain_has_security(current->domain, SECURITY__COMPUTE_USER);
- if ( length )
- return length;
-
- length = -ENOMEM;
- con = xmalloc_array(char, size+1);
- if ( !con )
- return length;
- memset(con, 0, size+1);
-
- user = xmalloc_array(char, size+1);
- if ( !user )
- goto out;
- memset(user, 0, size+1);
-
- length = -ENOMEM;
- page = xmalloc_bytes(PAGE_SIZE);
- if ( !page )
- goto out2;
- memset(page, 0, PAGE_SIZE);
-
- length = -EINVAL;
- if ( sscanf(buf, "%s %s", con, user) != 2 )
- goto out2;
-
- length = security_context_to_sid(con, strlen(con)+1, &sid);
- if ( length < 0 )
- goto out2;
-
- length = security_get_user_sids(sid, user, &sids, &nsids);
- if ( length < 0 )
- goto out2;
-
- length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
- ptr = page + length;
- for ( i = 0; i < nsids; i++ )
- {
- rc = security_sid_to_context(sids[i], &newcon, &len);
- if ( rc )
- {
- length = rc;
- goto out3;
- }
- if ( (length + len) >= PAGE_SIZE )
- {
- xfree(newcon);
- length = -ERANGE;
- goto out3;
- }
- memcpy(ptr, newcon, len);
- xfree(newcon);
- ptr += len;
- length += len;
- }
-
- if ( length > size )
- {
- printk( "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, length);
- length = -ERANGE;
- goto out3;
- }
-
- memset(buf, 0, size);
- memcpy(buf, page, length);
-
- out3:
- xfree(sids);
- out2:
- if ( page )
- xfree(page);
- xfree(user);
- out:
- xfree(con);
- return length;
-}
-
-static int flask_security_relabel(char *buf, uint32_t size)
+static int flask_copyin_string(XEN_GUEST_HANDLE(char) u_buf, char **buf,
uint32_t size)
{
- char *scon, *tcon;
- u32 ssid, tsid, newsid;
- u16 tclass;
- int length;
- char *newcon;
- u32 len;
+ char *tmp = xmalloc_bytes(size + 1);
+ if ( !tmp )
+ return -ENOMEM;
- length = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
- if ( length )
- return length;
-
- length = -ENOMEM;
- scon = xmalloc_array(char, size+1);
- if ( !scon )
- return length;
- memset(scon, 0, size+1);
-
- tcon = xmalloc_array(char, size+1);
- if ( !tcon )
- goto out;
- memset(tcon, 0, size+1);
-
- length = -EINVAL;
- if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
- goto out2;
-
- length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
- if ( length < 0 )
- goto out2;
- length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
- if ( length < 0 )
- goto out2;
-
- length = security_change_sid(ssid, tsid, tclass, &newsid);
- if ( length < 0 )
- goto out2;
-
- length = security_sid_to_context(newsid, &newcon, &len);
- if ( length < 0 )
- goto out2;
-
- if ( len > size )
+ if ( copy_from_guest(tmp, u_buf, size) )
{
- printk( "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
- length = -ERANGE;
- goto out3;
+ xfree(tmp);
+ return -EFAULT;
}
+ tmp[size] = 0;
- memset(buf, 0, size);
- memcpy(buf, newcon, len);
- length = len;
-
- out3:
- xfree(newcon);
- out2:
- xfree(tcon);
- out:
- xfree(scon);
- return length;
+ *buf = tmp;
+ return 0;
}
-static int flask_security_create(char *buf, uint32_t size)
+static int flask_security_user(struct xen_flask_userlist *arg)
{
- char *scon, *tcon;
- u32 ssid, tsid, newsid;
- u16 tclass;
- int length;
- char *newcon;
- u32 len;
+ char *user;
+ u32 *sids;
+ u32 nsids;
+ int rv;
- length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
- if ( length )
- return length;
+ rv = domain_has_security(current->domain, SECURITY__COMPUTE_USER);
+ if ( rv )
+ return rv;
- length = -ENOMEM;
- scon = xmalloc_array(char, size+1);
- if ( !scon )
- return length;
- memset(scon, 0, size+1);
+ rv = flask_copyin_string(arg->u.user, &user, arg->size);
+ if ( rv )
+ return rv;
- tcon = xmalloc_array(char, size+1);
- if ( !tcon )
+ rv = security_get_user_sids(arg->start_sid, user, &sids, &nsids);
+ if ( rv < 0 )
goto out;
- memset(tcon, 0, size+1);
-
- length = -EINVAL;
- if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
- goto out2;
-
- length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
- if ( length < 0 )
- goto out2;
- length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
- if ( length < 0 )
- goto out2;
+ if ( nsids * sizeof(sids[0]) > arg->size )
+ nsids = arg->size / sizeof(sids[0]);
- length = security_transition_sid(ssid, tsid, tclass, &newsid);
- if ( length < 0 )
- goto out2;
+ arg->size = nsids;
- length = security_sid_to_context(newsid, &newcon, &len);
- if ( length < 0 )
- goto out2;
-
- if ( len > size )
- {
- printk( "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
- length = -ERANGE;
- goto out3;
- }
+ if ( copy_to_guest(arg->u.sids, sids, nsids) )
+ rv = -EFAULT;
- memset(buf, 0, size);
- memcpy(buf, newcon, len);
- length = len;
-
- out3:
- xfree(newcon);
- out2:
- xfree(tcon);
+ xfree(sids);
out:
- xfree(scon);
- return length;
+ xfree(user);
+ return rv;
}
-static int flask_security_access(char *buf, uint32_t size)
+static int flask_security_relabel(struct xen_flask_transition *arg)
{
- char *scon, *tcon;
- u32 ssid, tsid;
- u16 tclass;
- u32 req;
- struct av_decision avd;
- int length;
+ int rv;
- length = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
- if ( length )
- return length;
-
- length = -ENOMEM;
- scon = xmalloc_array(char, size+1);
- if (!scon)
- return length;
- memset(scon, 0, size+1);
-
- tcon = xmalloc_array(char, size+1);
- if ( !tcon )
- goto out;
- memset( tcon, 0, size+1 );
-
- length = -EINVAL;
- if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
- goto out2;
-
- length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
- if ( length < 0 )
- goto out2;
-
- length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
- if ( length < 0 )
- goto out2;
+ rv = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
+ if ( rv )
+ return rv;
- length = security_compute_av(ssid, tsid, tclass, req, &avd);
- if ( length < 0 )
- goto out2;
+ rv = security_change_sid(arg->ssid, arg->tsid, arg->tclass, &arg->newsid);
- memset(buf, 0, size);
- length = snprintf(buf, size, "%x %x %x %x %u",
- avd.allowed, 0xffffffff,
- avd.auditallow, avd.auditdeny,
- avd.seqno);
-
- out2:
- xfree(tcon);
- out:
- xfree(scon);
- return length;
+ return rv;
}
-static int flask_security_member(char *buf, uint32_t size)
+static int flask_security_create(struct xen_flask_transition *arg)
{
- char *scon, *tcon;
- u32 ssid, tsid, newsid;
- u16 tclass;
- int length;
- char *newcon;
- u32 len;
+ int rv;
- length = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
- if ( length )
- return length;
+ rv = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
+ if ( rv )
+ return rv;
- length = -ENOMEM;
- scon = xmalloc_array(char, size+1);
- if ( !scon )
- return length;
- memset(scon, 0, size+1);
+ rv = security_transition_sid(arg->ssid, arg->tsid, arg->tclass,
&arg->newsid);
- tcon = xmalloc_array(char, size+1);
- if ( !tcon )
- goto out;
- memset(tcon, 0, size+1);
+ return rv;
+}
- length = -EINVAL;
- if ( sscanf(buf, "%s, %s, %hu", scon, tcon, &tclass) != 3 )
- goto out2;
+static int flask_security_access(struct xen_flask_access *arg)
+{
+ struct av_decision avd;
+ int rv;
- length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
- if ( length < 0 )
- goto out2;
+ rv = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
+ if ( rv )
+ return rv;
- length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
- if ( length < 0 )
- goto out2;
+ rv = security_compute_av(arg->ssid, arg->tsid, arg->tclass, arg->req,
&avd);
+ if ( rv < 0 )
+ return rv;
- length = security_member_sid(ssid, tsid, tclass, &newsid);
- if ( length < 0 )
- goto out2;
+ arg->allowed = avd.allowed;
+ arg->audit_allow = avd.auditallow;
+ arg->audit_deny = avd.auditdeny;
+ arg->seqno = avd.seqno;
+
+ return rv;
+}
- length = security_sid_to_context(newsid, &newcon, &len);
- if ( length < 0 )
- goto out2;
+static int flask_security_member(struct xen_flask_transition *arg)
+{
+ int rv;
- if ( len > size )
- {
- printk("%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
- length = -ERANGE;
- goto out3;
- }
+ rv = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
+ if ( rv )
+ return rv;
- memset(buf, 0, size);
- memcpy(buf, newcon, len);
- length = len;
+ rv = security_member_sid(arg->ssid, arg->tsid, arg->tclass, &arg->newsid);
- out3:
- xfree(newcon);
- out2:
- xfree(tcon);
- out:
- xfree(scon);
- return length;
+ return rv;
}
-static int flask_security_setenforce(char *buf, uint32_t count)
+static int flask_security_setenforce(struct xen_flask_setenforce *arg)
{
- int length;
- int new_value;
+ int enforce = !!(arg->enforcing);
+ int rv;
- if ( sscanf(buf, "%d", &new_value) != 1 )
- return -EINVAL;
+ if ( enforce == flask_enforcing )
+ return 0;
- if ( new_value != flask_enforcing )
- {
- length = domain_has_security(current->domain, SECURITY__SETENFORCE);
- if ( length )
- goto out;
- flask_enforcing = new_value;
- if ( flask_enforcing )
- avc_ss_reset(0);
- }
- length = count;
+ rv = domain_has_security(current->domain, SECURITY__SETENFORCE);
+ if ( rv )
+ return rv;
- out:
- return length;
+ flask_enforcing = enforce;
+
+ if ( flask_enforcing )
+ avc_ss_reset(0);
+
+ return 0;
}
-static int flask_security_context(char *buf, uint32_t count)
+static int flask_security_context(struct xen_flask_sid_context *arg)
{
- u32 sid;
- int length;
+ int rv;
+ char *buf;
- length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
- if ( length )
- goto out;
+ rv = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+ if ( rv )
+ return rv;
- length = security_context_to_sid(buf, count, &sid);
- if ( length < 0 )
- goto out;
+ rv = flask_copyin_string(arg->context, &buf, arg->size);
+ if ( rv )
+ return rv;
- memset(buf, 0, count);
- length = snprintf(buf, count, "%u", sid);
+ rv = security_context_to_sid(buf, arg->size, &arg->sid);
+ if ( rv < 0 )
+ goto out;
out:
- return length;
+ xfree(buf);
+
+ return rv;
}
-static int flask_security_sid(char *buf, uint32_t count)
+static int flask_security_sid(struct xen_flask_sid_context *arg)
{
+ int rv;
char *context;
- u32 sid;
u32 len;
- int length;
- length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
- if ( length )
- goto out;
+ rv = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+ if ( rv )
+ return rv;
- if ( sscanf(buf, "%u", &sid) != 1 )
- goto out;
+ rv = security_sid_to_context(arg->sid, &context, &len);
+ if ( rv < 0 )
+ return rv;
- length = security_sid_to_context(sid, &context, &len);
- if ( length < 0 )
- goto out;
+ rv = 0;
- if ( len > count )
- return -ERANGE;
+ if ( len > arg->size )
+ rv = -ERANGE;
- memset(buf, 0, count);
- memcpy(buf, context, len);
- length = len;
+ arg->size = len;
+
+ if ( !rv && copy_to_guest(arg->context, context, len) )
+ rv = -EFAULT;
xfree(context);
- out:
- return length;
+ return rv;
}
int flask_disable(void)
@@ -530,229 +277,154 @@ int flask_disable(void)
return 0;
}
-static int flask_security_disable(char *buf, uint32_t count)
-{
- int length;
- int new_value;
-
- length = -EINVAL;
- if ( sscanf(buf, "%d", &new_value) != 1 )
- goto out;
-
- if ( new_value )
- {
- length = flask_disable();
- if ( length < 0 )
- goto out;
- }
-
- length = count;
-
- out:
- return length;
-}
-
-static int flask_security_setavc_threshold(char *buf, uint32_t count)
+static int flask_security_setavc_threshold(struct xen_flask_setavc_threshold
*arg)
{
- int ret;
- int new_value;
-
- if ( sscanf(buf, "%u", &new_value) != 1 )
- {
- ret = -EINVAL;
- goto out;
- }
+ int rv = 0;
- if ( new_value != avc_cache_threshold )
+ if ( arg->threshold != avc_cache_threshold )
{
- ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
- if ( ret )
+ rv = domain_has_security(current->domain, SECURITY__SETSECPARAM);
+ if ( rv )
goto out;
- avc_cache_threshold = new_value;
+ avc_cache_threshold = arg->threshold;
}
- ret = count;
out:
- return ret;
+ return rv;
}
-static int flask_security_set_bool(char *buf, uint32_t count)
+static int flask_security_resolve_bool(struct xen_flask_boolean *arg)
{
- int length = -EFAULT;
- unsigned int i, new_value;
-
- spin_lock(&sel_sem);
-
- length = domain_has_security(current->domain, SECURITY__SETBOOL);
- if ( length )
- goto out;
-
- length = -EINVAL;
- if ( sscanf(buf, "%d %d", &i, &new_value) != 2 )
- goto out;
+ char *name;
+ int rv;
- if (!bool_pending_values)
- flask_security_make_bools();
+ if ( arg->bool_id != -1 )
+ return 0;
- if ( i >= bool_num )
- goto out;
+ rv = flask_copyin_string(arg->name, &name, arg->size);
+ if ( rv )
+ return rv;
- if ( new_value )
- new_value = 1;
+ arg->bool_id = security_find_bool(name);
+ arg->size = 0;
- bool_pending_values[i] = new_value;
- length = count;
+ xfree(name);
- out:
- spin_unlock(&sel_sem);
- return length;
+ return 0;
}
-static int flask_security_set_bool_name(char *buf, uint32_t count)
+static int flask_security_set_bool(struct xen_flask_boolean *arg)
{
- int rv, num;
- int i, new_value, commit;
- int *values = NULL;
- char *name;
-
- name = xmalloc_bytes(count);
- if ( name == NULL )
- return -ENOMEM;
+ int rv;
- spin_lock(&sel_sem);
+ rv = flask_security_resolve_bool(arg);
+ if ( rv )
+ return rv;
rv = domain_has_security(current->domain, SECURITY__SETBOOL);
if ( rv )
- goto out;
-
- rv = -EINVAL;
- if ( sscanf(buf, "%s %d %d", name, &new_value, &commit) != 3 )
- goto out;
+ return rv;
- i = security_find_bool(name);
- if ( i < 0 )
- goto out;
+ spin_lock(&sel_sem);
- if ( new_value )
- new_value = 1;
+ if ( arg->commit )
+ {
+ int num;
+ int *values;
- if ( commit ) {
rv = security_get_bools(&num, NULL, &values);
if ( rv != 0 )
goto out;
- values[i] = new_value;
- if (bool_pending_values)
- bool_pending_values[i] = new_value;
+
+ if ( arg->bool_id >= num )
+ {
+ rv = -ENOENT;
+ goto out;
+ }
+ values[arg->bool_id] = !!(arg->new_value);
+
+ arg->enforcing = arg->pending = !!(arg->new_value);
+
+ if ( bool_pending_values )
+ bool_pending_values[arg->bool_id] = !!(arg->new_value);
+
rv = security_set_bools(num, values);
xfree(values);
- } else {
- if (!bool_pending_values)
+ }
+ else
+ {
+ if ( !bool_pending_values )
flask_security_make_bools();
- bool_pending_values[i] = new_value;
- rv = count;
+ if ( arg->bool_id >= bool_num )
+ goto out;
+
+ bool_pending_values[arg->bool_id] = !!(arg->new_value);
+ arg->pending = !!(arg->new_value);
+ arg->enforcing = security_get_bool_value(arg->bool_id);
+
+ rv = 0;
}
out:
- xfree(name);
spin_unlock(&sel_sem);
return rv;
}
-static int flask_security_commit_bools(char *buf, uint32_t count)
+static int flask_security_commit_bools(void)
{
- int length = -EFAULT;
- int new_value;
+ int rv;
spin_lock(&sel_sem);
- length = domain_has_security(current->domain, SECURITY__SETBOOL);
- if ( length )
- goto out;
-
- length = -EINVAL;
- if ( sscanf(buf, "%d", &new_value) != 1 )
+ rv = domain_has_security(current->domain, SECURITY__SETBOOL);
+ if ( rv )
goto out;
- if ( new_value && bool_pending_values )
- security_set_bools(bool_num, bool_pending_values);
+ if ( bool_pending_values )
+ rv = security_set_bools(bool_num, bool_pending_values);
- length = count;
-
out:
spin_unlock(&sel_sem);
- return length;
+ return rv;
}
-static int flask_security_get_bool(char *buf, uint32_t count, int named)
+static int flask_security_get_bool(struct xen_flask_boolean *arg)
{
- int length;
- int i, cur_enforcing, pend_enforcing;
- char* name = NULL;
-
- spin_lock(&sel_sem);
-
- length = -EINVAL;
- if ( sscanf(buf, "%d", &i) != 1 )
- goto out;
+ int rv;
- cur_enforcing = security_get_bool_value(i);
- if ( cur_enforcing < 0 )
- {
- length = cur_enforcing;
- goto out;
- }
+ rv = flask_security_resolve_bool(arg);
+ if ( rv )
+ return rv;
- if ( bool_pending_values )
- pend_enforcing = bool_pending_values[i];
- else
- pend_enforcing = cur_enforcing;
+ spin_lock(&sel_sem);
- if ( named )
- name = security_get_bool_name(i);
- if ( named && !name )
+ rv = security_get_bool_value(arg->bool_id);
+ if ( rv < 0 )
goto out;
- memset(buf, 0, count);
- if ( named )
- length = snprintf(buf, count, "%d %d %s", cur_enforcing,
- pend_enforcing, name);
- else
- length = snprintf(buf, count, "%d %d", cur_enforcing,
- pend_enforcing);
+ arg->enforcing = rv;
- out:
- xfree(name);
- spin_unlock(&sel_sem);
- return length;
-}
+ if ( bool_pending_values )
+ arg->pending = bool_pending_values[arg->bool_id];
+ else
+ arg->pending = rv;
-static int flask_security_get_bool_name(char *buf, uint32_t count)
-{
- int rv = -ENOENT;
- int i, cur_enforcing, pend_enforcing;
-
- spin_lock(&sel_sem);
-
- i = security_find_bool(buf);
- if ( i < 0 )
- goto out;
+ rv = 0;
- cur_enforcing = security_get_bool_value(i);
- if ( cur_enforcing < 0 )
+ if ( arg->size )
{
- rv = cur_enforcing;
- goto out;
+ char *nameout = security_get_bool_name(arg->bool_id);
+ size_t nameout_len = strlen(nameout);
+ if ( nameout_len > arg->size )
+ rv = -ERANGE;
+ arg->size = nameout_len;
+
+ if ( !rv && copy_to_guest(arg->name, nameout, nameout_len) )
+ rv = -EFAULT;
+ xfree(nameout);
}
- if ( bool_pending_values )
- pend_enforcing = bool_pending_values[i];
- else
- pend_enforcing = cur_enforcing;
-
- memset(buf, 0, count);
- rv = snprintf(buf, count, "%d %d", cur_enforcing, pend_enforcing);
-
out:
spin_unlock(&sel_sem);
return rv;
@@ -779,380 +451,212 @@ static int flask_security_make_bools(void)
#ifdef FLASK_AVC_STATS
-static int flask_security_avc_cachestats(char *buf, uint32_t count)
+static int flask_security_avc_cachestats(struct xen_flask_cache_stats *arg)
{
- char *page = NULL;
- int len = 0;
- int length = 0;
- int cpu;
struct avc_cache_stats *st;
- page = (char *)xmalloc_bytes(PAGE_SIZE);
- if ( !page )
- return -ENOMEM;
- memset(page, 0, PAGE_SIZE);
+ if ( arg->cpu > nr_cpu_ids )
+ return -ENOENT;
+ if ( !cpu_online(arg->cpu) )
+ return -ENOENT;
- len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
- "frees\n");
- if ( len > count ) {
- length = -EINVAL;
- goto out;
- }
-
- memcpy(buf, page, len);
- buf += len;
- length += len;
- count -= len;
+ st = &per_cpu(avc_cache_stats, arg->cpu);
- for_each_online_cpu ( cpu )
- {
- st = &per_cpu(avc_cache_stats, cpu);
+ arg->lookups = st->lookups;
+ arg->hits = st->hits;
+ arg->misses = st->misses;
+ arg->allocations = st->allocations;
+ arg->reclaims = st->reclaims;
+ arg->frees = st->frees;
- len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
- st->hits, st->misses, st->allocations,
- st->reclaims, st->frees);
- if ( len > count ) {
- length = -EINVAL;
- goto out;
- }
- memcpy(buf, page, len);
- buf += len;
- length += len;
- count -= len;
- }
-
- out:
- xfree(page);
- return length;
+ return 0;
}
#endif
-static int flask_security_load(char *buf, uint32_t count)
+static int flask_security_load(struct xen_flask_load *load)
{
int ret;
- int length;
-
- spin_lock(&sel_sem);
+ void *buf = NULL;
- length = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
- if ( length )
- goto out;
-
- length = security_load_policy(buf, count);
- if ( length )
- goto out;
-
- ret = flask_security_make_bools();
+ ret = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
if ( ret )
- length = ret;
- else
- length = count;
+ return ret;
- out:
- spin_unlock(&sel_sem);
- return length;
-}
-
-static int flask_ocontext_del(char *buf, uint32_t size)
-{
- int len = 0;
- char *ocontext;
- unsigned long low = 0;
- unsigned long high = 0;
-
- len = domain_has_security(current->domain, SECURITY__DEL_OCONTEXT);
- if ( len )
- return len;
+ if ( load->size > MAX_POLICY_SIZE )
+ return -EINVAL;
- if ( (ocontext = xmalloc_bytes(size) ) == NULL )
+ buf = xmalloc_bytes(load->size);
+ if ( !buf )
return -ENOMEM;
- len = sscanf(buf, "%s %lu %lu", ocontext, &low, &high);
- if ( len < 2 )
+ if ( copy_from_guest(buf, load->buffer, load->size) )
{
- len = -EINVAL;
- goto out;
+ ret = -EFAULT;
+ goto out_free;
}
- else if ( len == 2 )
- high = low;
- if ( low > high )
- {
- len = -EINVAL;
+ spin_lock(&sel_sem);
+
+ ret = security_load_policy(buf, load->size);
+ if ( ret )
goto out;
- }
- len = security_ocontext_del(ocontext, low, high);
+ xfree(bool_pending_values);
+ bool_pending_values = NULL;
+ ret = 0;
+
out:
- xfree(ocontext);
- return len;
+ spin_unlock(&sel_sem);
+ out_free:
+ xfree(buf);
+ return ret;
}
-static int flask_ocontext_add(char *buf, uint32_t size)
+static int flask_ocontext_del(struct xen_flask_ocontext *arg)
{
- int len = 0;
- u32 sid = 0;
- unsigned long low = 0;
- unsigned long high = 0;
- char *scontext;
- char *ocontext;
-
- len = domain_has_security(current->domain, SECURITY__ADD_OCONTEXT);
- if ( len )
- return len;
-
- if ( (scontext = xmalloc_bytes(size) ) == NULL )
- return -ENOMEM;
+ int rv;
- if ( (ocontext = xmalloc_bytes(size) ) == NULL )
- {
- xfree(scontext);
- return -ENOMEM;
- }
-
- memset(scontext, 0, size);
- memset(ocontext, 0, size);
+ if ( arg->low > arg->high )
+ return -EINVAL;
- len = sscanf(buf, "%s %s %lu %lu", ocontext, scontext, &low, &high);
- if ( len < 3 )
- {
- len = -EINVAL;
- goto out;
- }
- else if ( len == 3 )
- high = low;
+ rv = domain_has_security(current->domain, SECURITY__DEL_OCONTEXT);
+ if ( rv )
+ return rv;
- if ( low > high )
- {
- len = -EINVAL;
- goto out;
- }
- len = security_context_to_sid(scontext, strlen(scontext)+1, &sid);
- if ( len < 0 )
- {
- len = -EINVAL;
- goto out;
- }
- len = security_ocontext_add(ocontext, low, high, sid);
- out:
- xfree(ocontext);
- xfree(scontext);
- return len;
+ return security_ocontext_del(arg->ocon, arg->low, arg->high);
}
-long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
+static int flask_ocontext_add(struct xen_flask_ocontext *arg)
{
- flask_op_t curop, *op = &curop;
- int rc = 0;
- int length = 0;
- char *arg = NULL;
+ int rv;
- if ( copy_from_guest(op, u_flask_op, 1) )
- return -EFAULT;
-
- if ( op->cmd > FLASK_LAST)
+ if ( arg->low > arg->high )
return -EINVAL;
- if ( op->size > MAX_POLICY_SIZE )
- return -EINVAL;
+ rv = domain_has_security(current->domain, SECURITY__ADD_OCONTEXT);
+ if ( rv )
+ return rv;
- if ( (op->buf == NULL && op->size != 0) ||
- (op->buf != NULL && op->size == 0) )
- return -EINVAL;
+ return security_ocontext_add(arg->ocon, arg->low, arg->high, arg->sid);
+}
- arg = xmalloc_bytes(op->size + 1);
- if ( !arg )
- return -ENOMEM;
+long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
+{
+ xen_flask_op_t op;
+ int rv;
- memset(arg, 0, op->size + 1);
+ if ( copy_from_guest(&op, u_flask_op, 1) )
+ return -EFAULT;
- if ( (FLASK_COPY_IN&(1UL<<op->cmd)) && op->buf != NULL &&
- copy_from_guest(arg, guest_handle_from_ptr(op->buf, char), op->size) )
- {
- rc = -EFAULT;
- goto out;
- }
+ if ( op.interface_version != XEN_FLASK_INTERFACE_VERSION )
+ return -ENOSYS;
- switch ( op->cmd )
+ switch ( op.cmd )
{
-
case FLASK_LOAD:
- {
- length = flask_security_load(arg, op->size);
- }
- break;
-
+ rv = flask_security_load(&op.u.load);
+ break;
+
case FLASK_GETENFORCE:
- {
- length = snprintf(arg, op->size, "%d", flask_enforcing);
- }
- break;
+ rv = flask_enforcing;
+ break;
case FLASK_SETENFORCE:
- {
- length = flask_security_setenforce(arg, op->size);
- }
- break;
+ rv = flask_security_setenforce(&op.u.enforce);
+ break;
case FLASK_CONTEXT_TO_SID:
- {
- length = flask_security_context(arg, op->size);
- }
- break;
+ rv = flask_security_context(&op.u.sid_context);
+ break;
case FLASK_SID_TO_CONTEXT:
- {
- length = flask_security_sid(arg, op->size);
- }
- break;
+ rv = flask_security_sid(&op.u.sid_context);
+ break;
case FLASK_ACCESS:
- {
- length = flask_security_access(arg, op->size);
- }
- break;
+ rv = flask_security_access(&op.u.access);
+ break;
case FLASK_CREATE:
- {
- length = flask_security_create(arg, op->size);
- }
- break;
+ rv = flask_security_create(&op.u.transition);
+ break;
case FLASK_RELABEL:
- {
- length = flask_security_relabel(arg, op->size);
- }
- break;
+ rv = flask_security_relabel(&op.u.transition);
+ break;
case FLASK_USER:
- {
- length = flask_security_user(arg, op->size);
- }
- break;
+ rv = flask_security_user(&op.u.userlist);
+ break;
case FLASK_POLICYVERS:
- {
- length = snprintf(arg, op->size, "%d", POLICYDB_VERSION_MAX);
- }
- break;
+ rv = POLICYDB_VERSION_MAX;
+ break;
case FLASK_GETBOOL:
- {
- length = flask_security_get_bool(arg, op->size, 0);
- }
- break;
+ rv = flask_security_get_bool(&op.u.boolean);
+ break;
case FLASK_SETBOOL:
- {
- length = flask_security_set_bool(arg, op->size);
- }
- break;
+ rv = flask_security_set_bool(&op.u.boolean);
+ break;
case FLASK_COMMITBOOLS:
- {
- length = flask_security_commit_bools(arg, op->size);
- }
- break;
+ rv = flask_security_commit_bools();
+ break;
case FLASK_MLS:
- {
- length = snprintf(arg, op->size, "%d", flask_mls_enabled);
- }
- break;
+ rv = flask_mls_enabled;
+ break;
case FLASK_DISABLE:
- {
- length = flask_security_disable(arg, op->size);
- }
- break;
+ rv = flask_disable();
+ break;
case FLASK_GETAVC_THRESHOLD:
- {
- length = snprintf(arg, op->size, "%d", avc_cache_threshold);
- }
- break;
+ rv = avc_cache_threshold;
+ break;
case FLASK_SETAVC_THRESHOLD:
- {
- length = flask_security_setavc_threshold(arg, op->size);
- }
- break;
+ rv = flask_security_setavc_threshold(&op.u.setavc_threshold);
+ break;
case FLASK_AVC_HASHSTATS:
- {
- length = avc_get_hash_stats(arg, op->size);
- }
- break;
+ rv = avc_get_hash_stats(&op.u.hash_stats);
+ break;
-#ifdef FLASK_AVC_STATS
+#ifdef FLASK_AVC_STATS
case FLASK_AVC_CACHESTATS:
- {
- length = flask_security_avc_cachestats(arg, op->size);
- }
- break;
+ rv = flask_security_avc_cachestats(&op.u.cache_stats);
+ break;
#endif
case FLASK_MEMBER:
- {
- length = flask_security_member(arg, op->size);
- }
- break;
+ rv = flask_security_member(&op.u.transition);
+ break;
case FLASK_ADD_OCONTEXT:
- {
- length = flask_ocontext_add(arg, op->size);
+ rv = flask_ocontext_add(&op.u.ocontext);
break;
- }
case FLASK_DEL_OCONTEXT:
- {
- length = flask_ocontext_del(arg, op->size);
+ rv = flask_ocontext_del(&op.u.ocontext);
break;
- }
-
- case FLASK_GETBOOL_NAMED:
- {
- length = flask_security_get_bool_name(arg, op->size);
- }
- break;
-
- case FLASK_GETBOOL2:
- {
- length = flask_security_get_bool(arg, op->size, 1);
- }
- break;
-
- case FLASK_SETBOOL_NAMED:
- {
- length = flask_security_set_bool_name(arg, op->size);
- }
- break;
default:
- length = -ENOSYS;
- break;
-
+ rv = -ENOSYS;
}
- if ( length < 0 )
- {
- rc = length;
+ if ( rv < 0 )
goto out;
- }
-
- if ( (FLASK_COPY_OUT&(1UL<<op->cmd)) && op->buf != NULL &&
- copy_to_guest(guest_handle_from_ptr(op->buf, char), arg, op->size) )
+
+ if ( (FLASK_COPY_OUT&(1UL<<op.cmd)) )
{
- rc = -EFAULT;
- goto out;
+ if ( copy_to_guest(u_flask_op, &op, 1) )
+ rv = -EFAULT;
}
- op->size = length;
- if ( copy_to_guest(u_flask_op, op, 1) )
- rc = -EFAULT;
-
out:
- xfree(arg);
- return rc;
+ return rv;
}
diff --git a/xen/xsm/flask/include/avc.h b/xen/xsm/flask/include/avc.h
index 8fffbb6..0f62891 100644
--- a/xen/xsm/flask/include/avc.h
+++ b/xen/xsm/flask/include/avc.h
@@ -104,7 +104,8 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid,
u32 tsid,
u32 ssid, u32 tsid, u16 tclass, u32 perms);
/* Exported to selinuxfs */
-int avc_get_hash_stats(char *buf, uint32_t size);
+struct xen_flask_hash_stats;
+int avc_get_hash_stats(struct xen_flask_hash_stats *arg);
extern unsigned int avc_cache_threshold;
#ifdef FLASK_AVC_STATS
diff --git a/xen/xsm/flask/include/security.h b/xen/xsm/flask/include/security.h
index 67ca6d0..348f018 100644
--- a/xen/xsm/flask/include/security.h
+++ b/xen/xsm/flask/include/security.h
@@ -90,8 +90,8 @@ int security_iterate_iomem_sids(unsigned long start, unsigned
long end,
int security_iterate_ioport_sids(u32 start, u32 end,
security_iterate_fn fn, void *data);
-int security_ocontext_add(char *ocontext, unsigned long low,
+int security_ocontext_add(u32 ocontext, unsigned long low,
unsigned long high, u32 sid);
-int security_ocontext_del(char *ocontext, unsigned int low, unsigned int high);
+int security_ocontext_del(u32 ocontext, unsigned int low, unsigned int high);
#endif /* _FLASK_SECURITY_H_ */
diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c
index 0189baf..363f586 100644
--- a/xen/xsm/flask/ss/services.c
+++ b/xen/xsm/flask/ss/services.c
@@ -2097,17 +2097,14 @@ int determine_ocontext( char *ocontext )
return -1;
}
-int security_ocontext_add( char *ocontext, unsigned long low, unsigned long
high
+int security_ocontext_add( u32 ocon, unsigned long low, unsigned long high
,u32 sid )
{
int ret = 0;
- int ocon = 0;
struct ocontext *c;
struct ocontext *prev;
struct ocontext *add;
- if ( (ocon = determine_ocontext(ocontext)) < 0 )
- return -EINVAL;
if ( (add = xmalloc(struct ocontext)) == NULL )
return -ENOMEM;
memset(add, 0, sizeof(struct ocontext));
@@ -2254,15 +2251,11 @@ int security_ocontext_add( char *ocontext, unsigned
long low, unsigned long high
return ret;
}
-int security_ocontext_del( char *ocontext, unsigned int low, unsigned int high
)
+int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high )
{
int ret = 0;
- int ocon = 0;
struct ocontext *c, *before_c;
- if ( (ocon = determine_ocontext(ocontext)) < 0 )
- return -EINVAL;
-
POLICY_WRLOCK;
switch( ocon )
{
--
1.7.7.6
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |