From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel De Graaf Subject: [PATCH v2] xsm: add device tree labeling support Date: Thu, 12 Mar 2015 16:42:22 -0400 Message-ID: <1426192942-6029-1-git-send-email-dgdegra@tycho.nsa.gov> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YW9wS-0001oh-Go for xen-devel@lists.xenproject.org; Thu, 12 Mar 2015 20:42:52 +0000 List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xenproject.org Cc: Daniel De Graaf , julien.grall@linaro.org List-Id: xen-devel@lists.xenproject.org This adds support in the hypervisor and policy build toolchain for Xen/Flask policy version 30, which adds the ability to label ARM device tree nodes and expands the IOMEM ocontext entries to 64 bits. Signed-off-by: Daniel De Graaf --- tools/flask/policy/Makefile | 20 ++++-- xen/include/public/xsm/flask_op.h | 9 +++ xen/xsm/flask/flask_op.c | 28 ++++++++ xen/xsm/flask/include/security.h | 14 +++- xen/xsm/flask/ss/policydb.c | 133 ++++++++++++++++++++++++++++++++------ xen/xsm/flask/ss/policydb.h | 7 +- xen/xsm/flask/ss/services.c | 118 ++++++++++++++++++++++++++++++--- 7 files changed, 287 insertions(+), 42 deletions(-) diff --git a/tools/flask/policy/Makefile b/tools/flask/policy/Makefile index e564396..4be921c 100644 --- a/tools/flask/policy/Makefile +++ b/tools/flask/policy/Makefile @@ -20,21 +20,21 @@ MLS_CATS ?= 256 CHECKPOLICY ?= checkpolicy M4 ?= m4 +# Output security policy version. Leave unset to autodetect. +OUTPUT_POLICY ?= $(BEST_POLICY_VER) + ######################################## # # End of configuration options # ######################################## -# Policy version -# By default, checkpolicy creates the highest version policy it supports. Force -# the use of version 24 which is the highest that Xen supports, and the first to -# include the Xen policy type (needed for static device policy). -OUTPUT_POLICY = 24 - POLICY_FILENAME = xenpolicy-$(shell $(MAKE) -C $(XEN_ROOT)/xen xenversion --no-print-directory) POLICY_LOADPATH = /boot +# List of policy versions supported by the hypervisor +POLICY_VER_LIST_HV = 24 30 + # policy source layout POLDIR := policy MODDIR := $(POLDIR)/modules @@ -64,6 +64,14 @@ MOD_CONF := $(POLDIR)/modules.conf # checkpolicy can use the #line directives provided by -s for error reporting: M4PARAM := -D self_contained_policy -s + +# The output of checkpolicy -V is "30 (compatibility range 30-15)", and the +# first word of the output is the maximum policy version supported. +CHECKPOLICY_VER_MAX := $(firstword $(shell $(CHECKPOLICY) -V)) + +# Find the highest version supported by both the hypervisor and checkpolicy +BEST_POLICY_VER := $(shell best=24; for ver in $(POLICY_VER_LIST_HV); do if test $$ver -le $(CHECKPOLICY_VER_MAX); then best=$$ver; fi; done; echo $$best) + CHECKPOLICY_PARAM := -t Xen -c $(OUTPUT_POLICY) # enable MLS if requested. diff --git a/xen/include/public/xsm/flask_op.h b/xen/include/public/xsm/flask_op.h index f874589..c76359c 100644 --- a/xen/include/public/xsm/flask_op.h +++ b/xen/include/public/xsm/flask_op.h @@ -150,6 +150,13 @@ struct xen_flask_relabel { uint32_t sid; }; +struct xen_flask_devicetree_label { + /* IN */ + uint32_t sid; + uint32_t length; + XEN_GUEST_HANDLE(char) path; +}; + struct xen_flask_op { uint32_t cmd; #define FLASK_LOAD 1 @@ -176,6 +183,7 @@ struct xen_flask_op { #define FLASK_DEL_OCONTEXT 22 #define FLASK_GET_PEER_SID 23 #define FLASK_RELABEL_DOMAIN 24 +#define FLASK_DEVICETREE_LABEL 25 uint32_t interface_version; /* XEN_FLASK_INTERFACE_VERSION */ union { struct xen_flask_load load; @@ -195,6 +203,7 @@ struct xen_flask_op { struct xen_flask_ocontext ocontext; struct xen_flask_peersid peersid; struct xen_flask_relabel relabel; + struct xen_flask_devicetree_label devicetree_label; } u; }; typedef struct xen_flask_op xen_flask_op_t; diff --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c index 84c7fec..47aacc1 100644 --- a/xen/xsm/flask/flask_op.c +++ b/xen/xsm/flask/flask_op.c @@ -563,6 +563,27 @@ static int flask_security_load(struct xen_flask_load *load) return ret; } +static int flask_devicetree_label(struct xen_flask_devicetree_label *arg) +{ + int rv; + char *buf; + u32 sid = arg->sid; + u32 perm = sid ? SECURITY__ADD_OCONTEXT : SECURITY__DEL_OCONTEXT; + + rv = domain_has_security(current->domain, perm); + if ( rv ) + return rv; + + rv = flask_copyin_string(arg->path, &buf, arg->length, PAGE_SIZE); + if ( rv ) + return rv; + + /* buf is consumed or freed by this function */ + rv = security_devicetree_setlabel(buf, sid); + + return rv; +} + #ifndef COMPAT static int flask_ocontext_del(struct xen_flask_ocontext *arg) @@ -790,6 +811,10 @@ ret_t do_flask_op(XEN_GUEST_HANDLE_PARAM(xsm_op_t) u_flask_op) rv = flask_relabel_domain(&op.u.relabel); break; + case FLASK_DEVICETREE_LABEL: + rv = flask_devicetree_label(&op.u.devicetree_label); + break; + default: rv = -ENOSYS; } @@ -848,6 +873,9 @@ CHECK_flask_transition; #define flask_security_get_bool compat_security_get_bool #define flask_security_set_bool compat_security_set_bool +#define xen_flask_devicetree_label compat_flask_devicetree_label +#define flask_devicetree_label compat_devicetree_label + #define xen_flask_op_t compat_flask_op_t #undef ret_t #define ret_t int diff --git a/xen/xsm/flask/include/security.h b/xen/xsm/flask/include/security.h index d07bae0..34bbe62 100644 --- a/xen/xsm/flask/include/security.h +++ b/xen/xsm/flask/include/security.h @@ -30,10 +30,16 @@ #define POLICYDB_VERSION_POLCAP 22 #define POLICYDB_VERSION_PERMISSIVE 23 #define POLICYDB_VERSION_BOUNDARY 24 +#define POLICYDB_VERSION_FILENAME_TRANS 25 +#define POLICYDB_VERSION_ROLETRANS 26 +#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 +#define POLICYDB_VERSION_DEFAULT_TYPE 28 +#define POLICYDB_VERSION_CONSTRAINT_NAMES 29 +#define POLICYDB_VERSION_XEN_DEVICETREE 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XEN_DEVICETREE enum flask_bootparam_t { FLASK_BOOTPARAM_PERMISSIVE, @@ -82,6 +88,8 @@ int security_ioport_sid(u32 ioport, u32 *out_sid); int security_device_sid(u32 device, u32 *out_sid); +int security_devicetree_sid(const char *path, u32 *out_sid); + int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass); @@ -96,5 +104,7 @@ int security_iterate_ioport_sids(u32 start, u32 end, int security_ocontext_add(u32 ocontext, unsigned long low, unsigned long high, u32 sid); -int security_ocontext_del(u32 ocontext, unsigned int low, unsigned int high); +int security_ocontext_del(u32 ocontext, unsigned long low, unsigned long high); + +int security_devicetree_setlabel(char *path, u32 sid); #endif /* _FLASK_SECURITY_H_ */ diff --git a/xen/xsm/flask/ss/policydb.c b/xen/xsm/flask/ss/policydb.c index b88ea56..a1060b1 100644 --- a/xen/xsm/flask/ss/policydb.c +++ b/xen/xsm/flask/ss/policydb.c @@ -74,55 +74,55 @@ static struct policydb_compat_info policydb_compat[] = { { .version = POLICYDB_VERSION_BASE, .sym_num = SYM_NUM - 3, - .ocon_num = OCON_NUM - 1, + .ocon_num = 4, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_BOOL, .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM - 1, + .ocon_num = 4, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_IPV6, .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_NLCLASS, .sym_num = SYM_NUM - 2, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_MLS, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_AVTAB, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_RANGETRANS, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_POLCAP, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { .version = POLICYDB_VERSION_PERMISSIVE, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = 5, .target_type = TARGET_XEN_OLD, }, { @@ -134,7 +134,13 @@ static struct policydb_compat_info policydb_compat[] = { { .version = POLICYDB_VERSION_BOUNDARY, .sym_num = SYM_NUM, - .ocon_num = OCON_NUM, + .ocon_num = OCON_DEVICE + 1, + .target_type = TARGET_XEN, + }, + { + .version = POLICYDB_VERSION_XEN_DEVICETREE, + .sym_num = SYM_NUM, + .ocon_num = OCON_DTREE + 1, .target_type = TARGET_XEN, }, }; @@ -634,7 +640,7 @@ static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); context_destroy(&c->context[1]); - if ( i == OCON_ISID ) + if ( i == OCON_ISID || i == OCON_DTREE ) xfree(c->u.name); xfree(c); } @@ -1040,8 +1046,8 @@ bad: goto out; } -static int read_cons_helper(struct constraint_node **nodep, int ncons, - int allowxtarget, void *fp) +static int read_cons_helper(struct policydb *p, struct constraint_node **nodep, + int ncons, int allowxtarget, void *fp) { struct constraint_node *c, *lc; struct constraint_expr *e, *le; @@ -1115,6 +1121,23 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons, depth++; if ( ebitmap_read(&e->names, fp) ) return -EINVAL; + if ( p->policyvers >= POLICYDB_VERSION_CONSTRAINT_NAMES ) + { + struct ebitmap dummy; + ebitmap_init(&dummy); + if ( ebitmap_read(&dummy, fp) ) + return -EINVAL; + ebitmap_destroy(&dummy); + + ebitmap_init(&dummy); + if ( ebitmap_read(&dummy, fp) ) + return -EINVAL; + ebitmap_destroy(&dummy); + + rc = next_entry(buf, fp, sizeof(u32)); + if ( rc < 0 ) + return rc; + } break; default: return -EINVAL; @@ -1184,7 +1207,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) goto bad; } - rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); + rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp); if ( rc ) goto bad; @@ -1195,11 +1218,27 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) if ( rc < 0 ) goto bad; ncons = le32_to_cpu(buf[0]); - rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); + rc = read_cons_helper(p, &cladatum->validatetrans, ncons, 1, fp); if ( rc ) goto bad; } + if ( p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS ) + { + rc = next_entry(buf, fp, sizeof(u32) * 3); + if ( rc ) + goto bad; + /* these values are ignored by Xen */ + } + + if ( p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE ) + { + rc = next_entry(buf, fp, sizeof(u32) * 1); + if ( rc ) + goto bad; + /* ignored by Xen */ + } + rc = hashtab_insert(h, key, cladatum); if ( rc ) goto bad; @@ -1874,7 +1913,10 @@ int policydb_read(struct policydb *p, void *fp) ltr->next = tr; else p->role_tr = tr; - rc = next_entry(buf, fp, sizeof(u32)*3); + if ( p->policyvers >= POLICYDB_VERSION_ROLETRANS ) + rc = next_entry(buf, fp, sizeof(u32)*4); + else + rc = next_entry(buf, fp, sizeof(u32)*3); if ( rc < 0 ) goto bad; tr->role = le32_to_cpu(buf[0]); @@ -1921,6 +1963,20 @@ int policydb_read(struct policydb *p, void *fp) lra = ra; } + if ( p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS ) + { + rc = next_entry(buf, fp, sizeof(u32)); + if ( rc ) + goto bad; + nel = le32_to_cpu(buf[0]); + if ( nel ) + { + printk(KERN_ERR "Flask: unsupported genfs config data\n"); + rc = -EINVAL; + goto bad; + } + } + rc = policydb_index_classes(p); if ( rc ) goto bad; @@ -1999,11 +2055,23 @@ int policydb_read(struct policydb *p, void *fp) "Old xen policy does not support iomemcon"); goto bad; } - rc = next_entry(buf, fp, sizeof(u32) *2); - if ( rc < 0 ) - goto bad; - c->u.iomem.low_iomem = le32_to_cpu(buf[0]); - c->u.iomem.high_iomem = le32_to_cpu(buf[1]); + if ( p->policyvers >= POLICYDB_VERSION_XEN_DEVICETREE ) + { + u64 b64[2]; + rc = next_entry(b64, fp, sizeof(u64) *2); + if ( rc < 0 ) + goto bad; + c->u.iomem.low_iomem = le64_to_cpu(b64[0]); + c->u.iomem.high_iomem = le64_to_cpu(b64[1]); + } + else + { + rc = next_entry(buf, fp, sizeof(u32) *2); + if ( rc < 0 ) + goto bad; + c->u.iomem.low_iomem = le32_to_cpu(buf[0]); + c->u.iomem.high_iomem = le32_to_cpu(buf[1]); + } rc = context_read_and_validate(&c->context[0], p, fp); if ( rc ) goto bad; @@ -2023,6 +2091,29 @@ int policydb_read(struct policydb *p, void *fp) if ( rc ) goto bad; break; + case OCON_DTREE: + if ( p->target_type != TARGET_XEN ) + { + printk(KERN_ERR + "Old xen policy does not support devicetreecon"); + goto bad; + } + rc = next_entry(buf, fp, sizeof(u32)); + if ( rc < 0 ) + goto bad; + len = le32_to_cpu(buf[0]); + rc = -ENOMEM; + c->u.name = xmalloc_array(char, len + 1); + if (!c->u.name) + goto bad; + rc = next_entry(c->u.name, fp, len); + if ( rc < 0 ) + goto bad; + c->u.name[len] = 0; + rc = context_read_and_validate(&c->context[0], p, fp); + if ( rc ) + goto bad; + break; default: printk(KERN_ERR "Flask: unsupported object context config data\n"); diff --git a/xen/xsm/flask/ss/policydb.h b/xen/xsm/flask/ss/policydb.h index b176300..30be71a 100644 --- a/xen/xsm/flask/ss/policydb.h +++ b/xen/xsm/flask/ss/policydb.h @@ -154,8 +154,8 @@ struct ocontext { u32 high_ioport; } ioport; struct { - u32 low_iomem; - u32 high_iomem; + u64 low_iomem; + u64 high_iomem; } iomem; } u; struct context context[2]; /* security context(s) */ @@ -180,7 +180,8 @@ struct ocontext { #define OCON_IOPORT 2 /* io ports */ #define OCON_IOMEM 3 /* io memory */ #define OCON_DEVICE 4 /* pci devices */ -#define OCON_NUM 5 +#define OCON_DTREE 5 /* device tree nodes */ +#define OCON_NUM 6 #define OCON_NUM_OLD 7 /* The policy database */ diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c index f0e459a..f31d7d7 100644 --- a/xen/xsm/flask/ss/services.c +++ b/xen/xsm/flask/ss/services.c @@ -1831,6 +1831,41 @@ out: return rc; } +int security_devicetree_sid(const char *path, u32 *out_sid) +{ + struct ocontext *c; + int rc = 0; + + POLICY_RDLOCK; + + c = policydb.ocontexts[OCON_DTREE]; + while ( c ) + { + if ( strcmp(c->u.name, path) == 0 ) + break; + c = c->next; + } + + if ( c ) + { + if ( !c->sid[0] ) + { + rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); + if ( rc ) + goto out; + } + *out_sid = c->sid[0]; + } + else + { + *out_sid = SECINITSID_DEVICE; + } + +out: + POLICY_RDUNLOCK; + return rc; +} + int security_find_bool(const char *name) { int i, rv = -ENOENT; @@ -2131,9 +2166,8 @@ int security_ocontext_add( u32 ocon, unsigned long low, unsigned long high c->u.iomem.high_iomem == high && c->sid[0] == sid) break; - printk("%s: IO Memory overlap with entry %#x - %#x\n", - __FUNCTION__, c->u.iomem.low_iomem, - c->u.iomem.high_iomem); + printk("%s: IO Memory overlap with entry %#"PRIx64" - %#"PRIx64"\n", + __FUNCTION__, c->u.iomem.low_iomem, c->u.iomem.high_iomem); ret = -EEXIST; break; } @@ -2188,7 +2222,7 @@ int security_ocontext_add( u32 ocon, unsigned long low, unsigned long high return ret; } -int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) +int security_ocontext_del( u32 ocon, unsigned long low, unsigned long high ) { int ret = 0; struct ocontext *c, *before_c; @@ -2217,7 +2251,7 @@ int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) } } - printk("%s: ocontext not found: pirq %d\n", __FUNCTION__, low); + printk("%s: ocontext not found: pirq %ld\n", __FUNCTION__, low); ret = -ENOENT; break; @@ -2243,8 +2277,8 @@ int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) } } - printk("%s: ocontext not found: ioport %#x - %#x\n", __FUNCTION__, - low, high); + printk("%s: ocontext not found: ioport %#lx - %#lx\n", + __FUNCTION__, low, high); ret = -ENOENT; break; @@ -2270,8 +2304,8 @@ int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) } } - printk("%s: ocontext not found: iomem %#x - %#x\n", __FUNCTION__, - low, high); + printk("%s: ocontext not found: iomem %#lx - %#lx\n", + __FUNCTION__, low, high); ret = -ENOENT; break; @@ -2296,7 +2330,7 @@ int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) } } - printk("%s: ocontext not found: pcidevice %#x\n", __FUNCTION__, low); + printk("%s: ocontext not found: pcidevice %#lx\n", __FUNCTION__, low); ret = -ENOENT; break; @@ -2308,3 +2342,67 @@ int security_ocontext_del( u32 ocon, unsigned int low, unsigned int high ) POLICY_WRUNLOCK; return ret; } + +int security_devicetree_setlabel(char *path, u32 sid) +{ + int ret = 0; + struct ocontext *c; + struct ocontext **pcurr; + struct ocontext *add = NULL; + + if ( sid ) + { + add = xzalloc(struct ocontext); + if ( add == NULL ) + { + xfree(path); + return -ENOMEM; + } + add->sid[0] = sid; + add->u.name = path; + } + else + { + ret = -ENOENT; + } + + POLICY_WRLOCK; + + pcurr = &policydb.ocontexts[OCON_DTREE]; + c = *pcurr; + while ( c ) + { + if ( strcmp(c->u.name, path) == 0 ) + { + if ( sid ) + { + ret = -EEXIST; + break; + } + else + { + *pcurr = c->next; + xfree(c->u.name); + xfree(c); + ret = 0; + break; + } + } + pcurr = &c->next; + c = *pcurr; + } + + if ( add && ret == 0 ) + { + add->next = policydb.ocontexts[OCON_DTREE]; + policydb.ocontexts[OCON_DTREE] = add; + add = NULL; + path = NULL; + } + + POLICY_WRUNLOCK; + + xfree(add); + xfree(path); + return ret; +} -- 2.1.0