[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 |