diff -r f77a9736d9f4 -r 2f5b1793c585 Config.mk --- a/Config.mk Tue Mar 13 13:50:04 2007 -0400 +++ b/Config.mk Tue Mar 13 13:57:21 2007 -0400 @@ -58,9 +58,9 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES) #Enable XSM security module. Enabling XSM requires selection of an #XSM security module. -XSM_ENABLE ?= y +XSM_ENABLE ?= n ifeq ($(XSM_ENABLE),y) -FLASK_ENABLE ?= y +FLASK_ENABLE ?= n ifeq ($(FLASK_ENABLE),y) FLASK_DEVELOP ?= y FLASK_BOOTPARAM ?= y diff -r f77a9736d9f4 -r 2f5b1793c585 xen/Makefile --- a/xen/Makefile Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/Makefile Tue Mar 13 13:57:21 2007 -0400 @@ -55,7 +55,6 @@ _clean: delete-unfresh-files $(MAKE) -f $(BASEDIR)/Rules.mk -C include clean $(MAKE) -f $(BASEDIR)/Rules.mk -C common clean $(MAKE) -f $(BASEDIR)/Rules.mk -C drivers clean - $(MAKE) -f $(BASEDIR)/Rules.mk -C acm clean $(MAKE) -f $(BASEDIR)/Rules.mk -C xsm clean $(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) clean rm -f include/asm *.o $(TARGET)* *~ core @@ -139,7 +138,7 @@ build-headers: build-headers: $(MAKE) -C include/public/foreign -SUBDIRS = xsm acm arch/$(TARGET_ARCH) common drivers +SUBDIRS = xsm arch/$(TARGET_ARCH) common drivers define all_sources ( find include/asm-$(TARGET_ARCH) -name '*.h' -print; \ find include -name 'asm-*' -prune -o -name '*.h' -print; \ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/Rules.mk --- a/xen/Rules.mk Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/Rules.mk Tue Mar 13 13:57:21 2007 -0400 @@ -48,7 +48,6 @@ ALL_OBJS-y += $(BASEDIR)/c ALL_OBJS-y += $(BASEDIR)/common/built_in.o ALL_OBJS-y += $(BASEDIR)/drivers/built_in.o ALL_OBJS-y += $(BASEDIR)/xsm/built_in.o -ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/acm/built_in.o ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o CFLAGS-y += -g -D__XEN__ @@ -57,7 +56,7 @@ CFLAGS-$(FLASK_DEVELOP) += -DFLASK_DEV CFLAGS-$(FLASK_DEVELOP) += -DFLASK_DEVELOP CFLAGS-$(FLASK_BOOTPARAM) += -DFLASK_BOOTPARAM CFLAGS-$(FLASK_AVC_STATS) += -DFLASK_AVC_STATS -CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY +CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY -DXSM_MAGIC=0x0100bcde CFLAGS-$(verbose) += -DVERBOSE CFLAGS-$(crash_debug) += -DCRASH_DEBUG CFLAGS-$(perfc) += -DPERF_COUNTERS diff -r f77a9736d9f4 -r 2f5b1793c585 xen/arch/ia64/linux-xen/entry.S --- a/xen/arch/ia64/linux-xen/entry.S Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/arch/ia64/linux-xen/entry.S Tue Mar 13 13:57:21 2007 -0400 @@ -1512,7 +1512,7 @@ ia64_hypercall_table: data8 do_ni_hypercall /* do_vcpu_op */ data8 do_ni_hypercall /* (x86_64 only) */ /* 25 */ data8 do_ni_hypercall /* do_mmuext_op */ - data8 do_ni_hypercall /* do_acm_op */ + data8 do_ni_hypercall /* do_xsm_op */ data8 do_ni_hypercall /* do_nmi_op */ data8 do_sched_op data8 do_callback_op /* */ /* 30 */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/arch/x86/setup.c Tue Mar 13 13:57:21 2007 -0400 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -210,44 +209,6 @@ static void __init percpu_free_unused_ar #endif } -/* Fetch acm policy module from multiboot modules. */ -static void extract_acm_policy( - multiboot_info_t *mbi, - unsigned int *initrdidx, - char **_policy_start, - unsigned long *_policy_len) -{ - int i; - module_t *mod = (module_t *)__va(mbi->mods_addr); - unsigned long start, policy_len; - char *policy_start; - - /* - * Try all modules and see whichever could be the binary policy. - * Adjust the initrdidx if module[1] is the binary policy. - */ - for ( i = mbi->mods_count-1; i >= 1; i-- ) - { - start = initial_images_start + (mod[i].mod_start-mod[0].mod_start); -#if defined(__i386__) - policy_start = (char *)start; -#elif defined(__x86_64__) - policy_start = __va(start); -#endif - policy_len = mod[i].mod_end - mod[i].mod_start; - if ( acm_is_policy(policy_start, policy_len) ) - { - printk("Policy len 0x%lx, start at %p - module %d.\n", - policy_len, policy_start, i); - *_policy_start = policy_start; - *_policy_len = policy_len; - if ( i == 1 ) - *initrdidx = (mbi->mods_count > 2) ? 2 : 0; - break; - } - } -} - static void __init init_idle_domain(void) { struct domain *idle_domain; @@ -298,8 +259,6 @@ void __init __start_xen(multiboot_info_t char __cmdline[] = "", *cmdline = __cmdline; unsigned long _initrd_start = 0, _initrd_len = 0; unsigned int initrdidx = 1; - char *_policy_start = NULL; - unsigned long _policy_len = 0; module_t *mod = (module_t *)__va(mbi->mods_addr); unsigned long nr_pages, modules_length; paddr_t s, e; @@ -723,21 +682,12 @@ void __init __start_xen(multiboot_info_t if ( opt_watchdog ) watchdog_enable(); - /* Extract policy from multiboot. */ - extract_acm_policy(mbi, &initrdidx, &_policy_start, &_policy_len); - - /* initialize access control security module */ - acm_init(_policy_start, _policy_len); - /* Create initial domain 0. */ dom0 = domain_create(0, 0); if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) ) panic("Error creating domain 0\n"); dom0->is_privileged = 1; - - /* Post-create hook sets security label. */ - acm_post_domain0_create(dom0->domain_id); xsm_complete_init(dom0); diff -r f77a9736d9f4 -r 2f5b1793c585 xen/arch/x86/x86_32/entry.S --- a/xen/arch/x86/x86_32/entry.S Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/arch/x86/x86_32/entry.S Tue Mar 13 13:57:21 2007 -0400 @@ -660,7 +660,7 @@ ENTRY(hypercall_table) .long do_vcpu_op .long do_ni_hypercall /* 25 */ .long do_mmuext_op - .long do_acm_op + .long do_xsm_op .long do_nmi_op .long do_sched_op .long do_callback_op /* 30 */ @@ -671,7 +671,6 @@ ENTRY(hypercall_table) .long do_sysctl /* 35 */ .long do_domctl .long do_kexec_op - .long do_xsm_op .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -704,7 +703,7 @@ ENTRY(hypercall_args_table) .byte 3 /* do_vcpu_op */ .byte 0 /* do_ni_hypercall */ /* 25 */ .byte 4 /* do_mmuext_op */ - .byte 1 /* do_acm_op */ + .byte 1 /* do_xsm_op */ .byte 2 /* do_nmi_op */ .byte 2 /* do_sched_op */ .byte 2 /* do_callback_op */ /* 30 */ @@ -715,7 +714,6 @@ ENTRY(hypercall_args_table) .byte 1 /* do_sysctl */ /* 35 */ .byte 1 /* do_domctl */ .byte 2 /* do_kexec_op */ - .byte 1 /* do_xsm_op */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/Makefile --- a/xen/common/Makefile Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/common/Makefile Tue Mar 13 13:57:21 2007 -0400 @@ -1,4 +1,3 @@ obj-y += acm_ops.o -obj-y += acm_ops.o obj-y += bitmap.o obj-y += domctl.o obj-y += domain.o @@ -43,7 +42,6 @@ version.o: $(BASEDIR)/include/xen/compil ifeq ($(CONFIG_COMPAT),y) # extra dependencies -acm_ops.o: compat/acm_ops.c grant_table.o: compat/grant_table.c kexec.o: compat/kexec.c schedule.o: compat/schedule.c diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/domctl.c --- a/xen/common/domctl.c Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/common/domctl.c Tue Mar 13 13:57:21 2007 -0400 @@ -23,7 +23,6 @@ #include #include #include -#include #include extern long arch_do_domctl( @@ -123,11 +122,6 @@ void getdomaininfo(struct domain *d, str if ( is_hvm_domain(d) ) info->flags |= XEN_DOMINF_hvm_guest; - if ( d->ssid != NULL ) - info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref; - else - info->ssidref = ACM_DEFAULT_SSID; - xsm_security_domaininfo(d, info); info->tot_pages = d->tot_pages; @@ -179,7 +173,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc { long ret = 0; struct xen_domctl curop, *op = &curop; - void *ssid = NULL; /* save security ptr between pre and post/fail hooks */ static DEFINE_SPINLOCK(domctl_lock); if ( !IS_PRIV(current->domain) ) @@ -190,9 +183,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION ) return -EACCES; - - if ( acm_pre_domctl(op, &ssid) ) - return -EPERM; spin_lock(&domctl_lock); @@ -828,11 +818,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc spin_unlock(&domctl_lock); - if ( ret == 0 ) - acm_post_domctl(op, &ssid); - else - acm_fail_domctl(op, &ssid); - return ret; } diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/event_channel.c --- a/xen/common/event_channel.c Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/common/event_channel.c Tue Mar 13 13:57:21 2007 -0400 @@ -29,7 +29,6 @@ #include #include -#include #include #define bucket_from_port(d,p) \ @@ -112,9 +111,6 @@ static long evtchn_alloc_unbound(evtchn_ domid_t dom = alloc->dom; long rc; - if ( (rc = acm_pre_eventchannel_unbound(dom, alloc->remote_dom)) != 0 ) - return rc; - if ( dom == DOMID_SELF ) dom = current->domain->domain_id; else if ( !IS_PRIV(current->domain) ) @@ -155,9 +151,6 @@ static long evtchn_bind_interdomain(evtc int lport, rport = bind->remote_port; domid_t rdom = bind->remote_dom; long rc; - - if ( (rc = acm_pre_eventchannel_interdomain(rdom)) != 0 ) - return rc; if ( rdom == DOMID_SELF ) rdom = current->domain->domain_id; diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/grant_table.c --- a/xen/common/grant_table.c Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/common/grant_table.c Tue Mar 13 13:57:21 2007 -0400 @@ -33,7 +33,6 @@ #include #include #include -#include #include #ifndef max_nr_grant_frames @@ -200,12 +199,6 @@ __gnttab_map_grant_ref( { gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags); op->status = GNTST_bad_gntref; - return; - } - - if ( acm_pre_grant_map_ref(op->dom) ) - { - op->status = GNTST_permission_denied; return; } diff -r f77a9736d9f4 -r 2f5b1793c585 xen/include/acm/acm_hooks.h --- a/xen/include/acm/acm_hooks.h Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/include/acm/acm_hooks.h Tue Mar 13 13:57:21 2007 -0400 @@ -370,8 +370,6 @@ static inline int acm_sharing(ssidref_t } -extern int acm_init(char *policy_start, unsigned long policy_len); - /* Return true iff buffer has an acm policy magic number. */ extern int acm_is_policy(char *buf, unsigned long len); diff -r f77a9736d9f4 -r 2f5b1793c585 xen/include/public/xen.h --- a/xen/include/public/xen.h Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/include/public/xen.h Tue Mar 13 13:57:21 2007 -0400 @@ -69,7 +69,7 @@ #define __HYPERVISOR_vcpu_op 24 #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ #define __HYPERVISOR_mmuext_op 26 -#define __HYPERVISOR_acm_op 27 +#define __HYPERVISOR_xsm_op 27 #define __HYPERVISOR_nmi_op 28 #define __HYPERVISOR_sched_op 29 #define __HYPERVISOR_callback_op 30 @@ -80,7 +80,6 @@ #define __HYPERVISOR_sysctl 35 #define __HYPERVISOR_domctl 36 #define __HYPERVISOR_kexec_op 37 -#define __HYPERVISOR_xsm_op 38 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff -r f77a9736d9f4 -r 2f5b1793c585 xen/include/xen/hypercall.h --- a/xen/include/xen/hypercall.h Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/include/xen/hypercall.h Tue Mar 13 13:57:21 2007 -0400 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -98,8 +97,9 @@ do_vcpu_op( XEN_GUEST_HANDLE(void) arg); extern long -do_acm_op( - int cmd, XEN_GUEST_HANDLE(void) arg); +do_xsm_op( + int cmd, + XEN_GUEST_HANDLE(xsm_op_t) u_xsm_op); extern long do_nmi_op( @@ -126,9 +126,4 @@ compat_memory_op( #endif -extern long -do_xsm_op( - int cmd, - XEN_GUEST_HANDLE(xsm_op_t) u_xsm_op); - #endif /* __XEN_HYPERCALL_H__ */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/Makefile --- a/xen/xsm/Makefile Tue Mar 13 13:50:04 2007 -0400 +++ b/xen/xsm/Makefile Tue Mar 13 13:57:21 2007 -0400 @@ -5,3 +5,4 @@ endif endif subdir-$(FLASK_ENABLE) += flask +subdir-$(ACM_SECURITY) += acm diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/Makefile --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/Makefile Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,14 @@ +obj-y += acm_core.o +obj-y += acm_policy.o +obj-y += acm_simple_type_enforcement_hooks.o +obj-y += acm_chinesewall_hooks.o +obj-y += acm_null_hooks.o +obj-y += acm_xsm_hooks.o +obj-y += acm_ops.o + +subdir-$(CONFIG_COMPAT) += compat + +ifeq ($(CONFIG_COMPAT),y) +# extra dependencies +acm_ops.o: compat/acm_ops.c +endif diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_chinesewall_hooks.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_chinesewall_hooks.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,634 @@ +/**************************************************************** + * acm_chinesewall_hooks.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributions: + * Stefan Berger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * sHype Chinese Wall Policy for Xen + * This code implements the hooks that are called + * throughout Xen operations and decides authorization + * based on domain types and Chinese Wall conflict type + * sets. The CHWALL policy decides if a new domain can be started + * based on the types of running domains and the type of the + * new domain to be started. If the new domain's type is in + * conflict with types of running domains, then this new domain + * is not allowed to be created. A domain can have multiple types, + * in which case all types of a new domain must be conflict-free + * with all types of already running domains. + * + * indent -i4 -kr -nut + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* local cache structures for chinese wall policy */ +struct chwall_binary_policy chwall_bin_pol; + +/* + * Initializing chinese wall policy (will be filled by policy partition + * using setpolicy command) + */ +int acm_init_chwall_policy(void) +{ + /* minimal startup policy; policy write-locked already */ + chwall_bin_pol.max_types = 1; + chwall_bin_pol.max_ssidrefs = 2; + chwall_bin_pol.max_conflictsets = 1; + chwall_bin_pol.ssidrefs = + (domaintype_t *) xmalloc_array(domaintype_t, + chwall_bin_pol.max_ssidrefs * + chwall_bin_pol.max_types); + chwall_bin_pol.conflict_sets = + (domaintype_t *) xmalloc_array(domaintype_t, + chwall_bin_pol.max_conflictsets * + chwall_bin_pol.max_types); + chwall_bin_pol.running_types = + (domaintype_t *) xmalloc_array(domaintype_t, + chwall_bin_pol.max_types); + chwall_bin_pol.conflict_aggregate_set = + (domaintype_t *) xmalloc_array(domaintype_t, + chwall_bin_pol.max_types); + + if ((chwall_bin_pol.conflict_sets == NULL) + || (chwall_bin_pol.running_types == NULL) + || (chwall_bin_pol.ssidrefs == NULL) + || (chwall_bin_pol.conflict_aggregate_set == NULL)) + return ACM_INIT_SSID_ERROR; + + /* initialize state */ + memset((void *) chwall_bin_pol.ssidrefs, 0, + chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types * + sizeof(domaintype_t)); + memset((void *) chwall_bin_pol.conflict_sets, 0, + chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types * + sizeof(domaintype_t)); + memset((void *) chwall_bin_pol.running_types, 0, + chwall_bin_pol.max_types * sizeof(domaintype_t)); + memset((void *) chwall_bin_pol.conflict_aggregate_set, 0, + chwall_bin_pol.max_types * sizeof(domaintype_t)); + return ACM_OK; +} + +static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref) +{ + struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid); + traceprintk("%s.\n", __func__); + if (chwall_ssidp == NULL) + return ACM_INIT_SSID_ERROR; + + chwall_ssidp->chwall_ssidref = + GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); + + if ((chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) + || (chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)) + { + printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n", + __func__, chwall_ssidp->chwall_ssidref); + xfree(chwall_ssidp); + return ACM_INIT_SSID_ERROR; + } + (*chwall_ssid) = chwall_ssidp; + printkd("%s: determined chwall_ssidref to %x.\n", + __func__, chwall_ssidp->chwall_ssidref); + return ACM_OK; +} + +static void chwall_free_domain_ssid(void *chwall_ssid) +{ + traceprintk("%s.\n", __func__); + xfree(chwall_ssid); + return; +} + + +/* dump chinese wall cache; policy read-locked already */ +static int chwall_dump_policy(u8 * buf, u32 buf_size) +{ + struct acm_chwall_policy_buffer *chwall_buf = + (struct acm_chwall_policy_buffer *) buf; + int ret = 0; + + if (buf_size < sizeof(struct acm_chwall_policy_buffer)) + return -EINVAL; + + chwall_buf->chwall_max_types = cpu_to_be32(chwall_bin_pol.max_types); + chwall_buf->chwall_max_ssidrefs = cpu_to_be32(chwall_bin_pol.max_ssidrefs); + chwall_buf->policy_code = cpu_to_be32(ACM_CHINESE_WALL_POLICY); + chwall_buf->chwall_ssid_offset = + cpu_to_be32(sizeof(struct acm_chwall_policy_buffer)); + chwall_buf->chwall_max_conflictsets = + cpu_to_be32(chwall_bin_pol.max_conflictsets); + chwall_buf->chwall_conflict_sets_offset = + cpu_to_be32(be32_to_cpu(chwall_buf->chwall_ssid_offset) + + sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs * + chwall_bin_pol.max_types); + chwall_buf->chwall_running_types_offset = + cpu_to_be32(be32_to_cpu(chwall_buf->chwall_conflict_sets_offset) + + sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets * + chwall_bin_pol.max_types); + chwall_buf->chwall_conflict_aggregate_offset = + cpu_to_be32(be32_to_cpu(chwall_buf->chwall_running_types_offset) + + sizeof(domaintype_t) * chwall_bin_pol.max_types); + + ret = be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset) + + sizeof(domaintype_t) * chwall_bin_pol.max_types; + + ret = (ret + 7) & ~7; + + if (buf_size < ret) + return -EINVAL; + + /* now copy buffers over */ + arrcpy16((u16 *) (buf + be32_to_cpu(chwall_buf->chwall_ssid_offset)), + chwall_bin_pol.ssidrefs, + chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types); + + arrcpy16((u16 *) (buf + + be32_to_cpu(chwall_buf->chwall_conflict_sets_offset)), + chwall_bin_pol.conflict_sets, + chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types); + + arrcpy16((u16 *) (buf + + be32_to_cpu(chwall_buf->chwall_running_types_offset)), + chwall_bin_pol.running_types, chwall_bin_pol.max_types); + + arrcpy16((u16 *) (buf + + be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset)), + chwall_bin_pol.conflict_aggregate_set, + chwall_bin_pol.max_types); + return ret; +} + +/* adapt security state (running_types and conflict_aggregate_set) to all running + * domains; chwall_init_state is called when a policy is changed to bring the security + * information into a consistent state and to detect violations (return != 0). + * from a security point of view, we simulate that all running domains are re-started + */ +static int +chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, + domaintype_t * ssidrefs, domaintype_t * conflict_sets, + domaintype_t * running_types, + domaintype_t * conflict_aggregate_set) +{ + int violation = 0, i, j; + struct chwall_ssid *chwall_ssid; + ssidref_t chwall_ssidref; + struct domain *d; + + spin_lock(&domlist_update_lock); + /* go through all domains and adjust policy as if this domain was started now */ + for_each_domain ( d ) + { + chwall_ssid = + GET_SSIDP(ACM_CHINESE_WALL_POLICY, + (struct acm_ssid_domain *)d->ssid); + chwall_ssidref = chwall_ssid->chwall_ssidref; + traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n", + __func__, d->domain_id, chwall_ssidref); + /* a) adjust types ref-count for running domains */ + for (i = 0; i < chwall_buf->chwall_max_types; i++) + running_types[i] += + ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i]; + + /* b) check for conflict */ + for (i = 0; i < chwall_buf->chwall_max_types; i++) + if (conflict_aggregate_set[i] && + ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i]) + { + printk("%s: CHINESE WALL CONFLICT in type %02x.\n", + __func__, i); + violation = 1; + goto out; + } + /* set violation and break out of the loop */ + /* c) adapt conflict aggregate set for this domain (notice conflicts) */ + for (i = 0; i < chwall_buf->chwall_max_conflictsets; i++) + { + int common = 0; + /* check if conflict_set_i and ssidref have common types */ + for (j = 0; j < chwall_buf->chwall_max_types; j++) + if (conflict_sets[i * chwall_buf->chwall_max_types + j] && + ssidrefs[chwall_ssidref * + chwall_buf->chwall_max_types + j]) + { + common = 1; + break; + } + if (common == 0) + continue; /* try next conflict set */ + /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ + for (j = 0; j < chwall_buf->chwall_max_types; j++) + if (conflict_sets[i * chwall_buf->chwall_max_types + j] && + !ssidrefs[chwall_ssidref * + chwall_buf->chwall_max_types + j]) + conflict_aggregate_set[j]++; + } + } + out: + spin_unlock(&domlist_update_lock); + return violation; + /* returning "violation != 0" means that the currently running set of domains would + * not be possible if the new policy had been enforced before starting them; for chinese + * wall, this means that the new policy includes at least one conflict set of which + * more than one type is currently running */ +} + +static int chwall_set_policy(u8 * buf, u32 buf_size) +{ + /* policy write-locked already */ + struct acm_chwall_policy_buffer *chwall_buf = + (struct acm_chwall_policy_buffer *) buf; + void *ssids = NULL, *conflict_sets = NULL, *running_types = + NULL, *conflict_aggregate_set = NULL; + + if (buf_size < sizeof(struct acm_chwall_policy_buffer)) + return -EINVAL; + + /* rewrite the policy due to endianess */ + chwall_buf->policy_code = be32_to_cpu(chwall_buf->policy_code); + chwall_buf->policy_version = be32_to_cpu(chwall_buf->policy_version); + chwall_buf->chwall_max_types = be32_to_cpu(chwall_buf->chwall_max_types); + chwall_buf->chwall_max_ssidrefs = + be32_to_cpu(chwall_buf->chwall_max_ssidrefs); + chwall_buf->chwall_max_conflictsets = + be32_to_cpu(chwall_buf->chwall_max_conflictsets); + chwall_buf->chwall_ssid_offset = be32_to_cpu(chwall_buf->chwall_ssid_offset); + chwall_buf->chwall_conflict_sets_offset = + be32_to_cpu(chwall_buf->chwall_conflict_sets_offset); + chwall_buf->chwall_running_types_offset = + be32_to_cpu(chwall_buf->chwall_running_types_offset); + chwall_buf->chwall_conflict_aggregate_offset = + be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset); + + /* policy type and version checks */ + if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) || + (chwall_buf->policy_version != ACM_CHWALL_VERSION)) + return -EINVAL; + + /* 1. allocate new buffers */ + ssids = + xmalloc_array(domaintype_t, + chwall_buf->chwall_max_types * + chwall_buf->chwall_max_ssidrefs); + conflict_sets = + xmalloc_array(domaintype_t, + chwall_buf->chwall_max_conflictsets * + chwall_buf->chwall_max_types); + running_types = + xmalloc_array(domaintype_t, chwall_buf->chwall_max_types); + conflict_aggregate_set = + xmalloc_array(domaintype_t, chwall_buf->chwall_max_types); + + if ((ssids == NULL) || (conflict_sets == NULL) + || (running_types == NULL) || (conflict_aggregate_set == NULL)) + goto error_free; + + /* 2. set new policy */ + if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) * + chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > + buf_size) + goto error_free; + + arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset, + sizeof(domaintype_t), + chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs); + + if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) * + chwall_buf->chwall_max_types * + chwall_buf->chwall_max_conflictsets > buf_size) + goto error_free; + + arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset, + sizeof(domaintype_t), + chwall_buf->chwall_max_types * + chwall_buf->chwall_max_conflictsets); + + /* we also use new state buffers since max_types can change */ + memset(running_types, 0, + sizeof(domaintype_t) * chwall_buf->chwall_max_types); + memset(conflict_aggregate_set, 0, + sizeof(domaintype_t) * chwall_buf->chwall_max_types); + + /* 3. now re-calculate the state for the new policy based on running domains; + * this can fail if new policy is conflicting with running domains */ + if (chwall_init_state(chwall_buf, ssids, + conflict_sets, running_types, + conflict_aggregate_set)) + { + printk("%s: New policy conflicts with running domains. Policy load aborted.\n", + __func__); + goto error_free; /* new policy conflicts with running domains */ + } + /* 4. free old policy buffers, replace with new ones */ + chwall_bin_pol.max_types = chwall_buf->chwall_max_types; + chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs; + chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets; + xfree(chwall_bin_pol.ssidrefs); + xfree(chwall_bin_pol.conflict_aggregate_set); + xfree(chwall_bin_pol.running_types); + xfree(chwall_bin_pol.conflict_sets); + chwall_bin_pol.ssidrefs = ssids; + chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set; + chwall_bin_pol.running_types = running_types; + chwall_bin_pol.conflict_sets = conflict_sets; + return ACM_OK; + + error_free: + printk("%s: ERROR setting policy.\n", __func__); + xfree(ssids); + xfree(conflict_sets); + xfree(running_types); + xfree(conflict_aggregate_set); + return -EFAULT; +} + +static int chwall_dump_stats(u8 * buf, u16 len) +{ + /* no stats for Chinese Wall Policy */ + return 0; +} + +static int chwall_dump_ssid_types(ssidref_t ssidref, u8 * buf, u16 len) +{ + int i; + + /* fill in buffer */ + if (chwall_bin_pol.max_types > len) + return -EFAULT; + + if (ssidref >= chwall_bin_pol.max_ssidrefs) + return -EFAULT; + + /* read types for chwall ssidref */ + for (i = 0; i < chwall_bin_pol.max_types; i++) + { + if (chwall_bin_pol. + ssidrefs[ssidref * chwall_bin_pol.max_types + i]) + buf[i] = 1; + else + buf[i] = 0; + } + return chwall_bin_pol.max_types; +} + +/*************************** + * Authorization functions + ***************************/ + +/* -------- DOMAIN OPERATION HOOKS -----------*/ + +static int chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref) +{ + ssidref_t chwall_ssidref; + int i, j; + traceprintk("%s.\n", __func__); + + read_lock(&acm_bin_pol_rwlock); + chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); + if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) + { + printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", + __func__); + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_DENIED; /* catching and indicating config error */ + } + if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) + { + printk("%s: ERROR chwall_ssidref > max(%x).\n", + __func__, chwall_bin_pol.max_ssidrefs - 1); + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_DENIED; + } + /* A: chinese wall check for conflicts */ + for (i = 0; i < chwall_bin_pol.max_types; i++) + if (chwall_bin_pol.conflict_aggregate_set[i] && + chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + i]) + { + printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i); + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_DENIED; + } + + /* B: chinese wall conflict set adjustment (so that other + * other domains simultaneously created are evaluated against this new set)*/ + for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) + { + int common = 0; + /* check if conflict_set_i and ssidref have common types */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + { + common = 1; + break; + } + if (common == 0) + continue; /* try next conflict set */ + /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && !chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + chwall_bin_pol.conflict_aggregate_set[j]++; + } + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_PERMITTED; +} + +static void chwall_post_domain_create(domid_t domid, ssidref_t ssidref) +{ + int i, j; + ssidref_t chwall_ssidref; + traceprintk("%s.\n", __func__); + + read_lock(&acm_bin_pol_rwlock); + chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); + /* adjust types ref-count for running domains */ + for (i = 0; i < chwall_bin_pol.max_types; i++) + chwall_bin_pol.running_types[i] += + chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + i]; + if (domid) + { + read_unlock(&acm_bin_pol_rwlock); + return; + } + /* Xen does not call pre-create hook for DOM0; + * to consider type conflicts of any domain with DOM0, we need + * to adjust the conflict_aggregate for DOM0 here the same way it + * is done for non-DOM0 domains in the pre-hook */ + printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n", + __func__, ssidref, chwall_ssidref); + + /* chinese wall conflict set adjustment (so that other + * other domains simultaneously created are evaluated against this new set)*/ + for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) + { + int common = 0; + /* check if conflict_set_i and ssidref have common types */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + { + common = 1; + break; + } + if (common == 0) + continue; /* try next conflict set */ + /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && !chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + chwall_bin_pol.conflict_aggregate_set[j]++; + } + read_unlock(&acm_bin_pol_rwlock); + return; +} + +static void +chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref) +{ + int i, j; + ssidref_t chwall_ssidref; + traceprintk("%s.\n", __func__); + + read_lock(&acm_bin_pol_rwlock); + chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); + /* roll-back: re-adjust conflicting types aggregate */ + for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) + { + int common = 0; + /* check if conflict_set_i and ssidref have common types */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + { + common = 1; + break; + } + if (common == 0) + continue; /* try next conflict set, this one does not include any type of chwall_ssidref */ + /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && !chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + chwall_bin_pol.conflict_aggregate_set[j]--; + } + read_unlock(&acm_bin_pol_rwlock); +} + + +static void chwall_post_domain_destroy(void *object_ssid, domid_t id) +{ + int i, j; + struct chwall_ssid *chwall_ssidp = GET_SSIDP(ACM_CHINESE_WALL_POLICY, + (struct acm_ssid_domain *) + object_ssid); + ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref; + + traceprintk("%s.\n", __func__); + + read_lock(&acm_bin_pol_rwlock); + /* adjust running types set */ + for (i = 0; i < chwall_bin_pol.max_types; i++) + chwall_bin_pol.running_types[i] -= + chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + i]; + + /* roll-back: re-adjust conflicting types aggregate */ + for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) + { + int common = 0; + /* check if conflict_set_i and ssidref have common types */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + { + common = 1; + break; + } + if (common == 0) + continue; /* try next conflict set, this one does not include any type of chwall_ssidref */ + /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ + for (j = 0; j < chwall_bin_pol.max_types; j++) + if (chwall_bin_pol. + conflict_sets[i * chwall_bin_pol.max_types + j] + && !chwall_bin_pol.ssidrefs[chwall_ssidref * + chwall_bin_pol.max_types + j]) + chwall_bin_pol.conflict_aggregate_set[j]--; + } + read_unlock(&acm_bin_pol_rwlock); + return; +} + +struct acm_operations acm_chinesewall_ops = { + /* policy management services */ + .init_domain_ssid = chwall_init_domain_ssid, + .free_domain_ssid = chwall_free_domain_ssid, + .dump_binary_policy = chwall_dump_policy, + .set_binary_policy = chwall_set_policy, + .dump_statistics = chwall_dump_stats, + .dump_ssid_types = chwall_dump_ssid_types, + /* domain management control hooks */ + .pre_domain_create = chwall_pre_domain_create, + .post_domain_create = chwall_post_domain_create, + .fail_domain_create = chwall_fail_domain_create, + .post_domain_destroy = chwall_post_domain_destroy, + /* event channel control hooks */ + .pre_eventchannel_unbound = NULL, + .fail_eventchannel_unbound = NULL, + .pre_eventchannel_interdomain = NULL, + .fail_eventchannel_interdomain = NULL, + /* grant table control hooks */ + .pre_grant_map_ref = NULL, + .fail_grant_map_ref = NULL, + .pre_grant_setup = NULL, + .fail_grant_setup = NULL, + /* generic domain-requested decision hooks */ + .sharing = NULL, +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_core.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_core.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,318 @@ +/**************************************************************** + * acm_core.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributors: + * Stefan Berger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * sHype access control module (ACM) + * This file handles initialization of the ACM + * as well as initializing/freeing security + * identifiers for domains (it calls on active + * policy hook functions). + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debug: + * include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE; + * define/undefine this constant to receive / suppress any + * security hook debug output of sHype + * + * include/public/acm.h defines a constant ACM_DEBUG + * define/undefine this constant to receive non-hook-related + * debug output. + */ + +/* function prototypes */ +void acm_init_chwall_policy(void); +void acm_init_ste_policy(void); + +extern struct acm_operations acm_chinesewall_ops, + acm_simple_type_enforcement_ops, acm_null_ops; + +extern struct xsm_operations acm_xsm_ops; + +/* global ACM policy (now dynamically determined at boot time) */ +u16 acm_active_security_policy = ACM_POLICY_UNDEFINED; + +/* global ops structs called by the hooks */ +struct acm_operations *acm_primary_ops = NULL; +/* called in hook if-and-only-if primary succeeds */ +struct acm_operations *acm_secondary_ops = NULL; + +/* acm global binary policy (points to 'local' primary and secondary policies */ +struct acm_binary_policy acm_bin_pol; +/* acm binary policy lock */ +DEFINE_RWLOCK(acm_bin_pol_rwlock); + +int +acm_set_policy_reference(u8 *buf, u32 buf_size) +{ + struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf; + acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len)); + + if (!acm_bin_pol.policy_reference_name) + return -ENOMEM; + + strlcpy(acm_bin_pol.policy_reference_name, + (char *)(buf + sizeof(struct acm_policy_reference_buffer)), + be32_to_cpu(pr->len)); + printk("%s: Activating policy %s\n", __func__, + acm_bin_pol.policy_reference_name); + return 0; +} + +int +acm_dump_policy_reference(u8 *buf, u32 buf_size) +{ + struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf; + int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1; + + ret = (ret + 7) & ~7; + if (buf_size < ret) + return -EINVAL; + + memset(buf, 0, ret); + pr_buf->len = cpu_to_be32(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */ + strlcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)), + acm_bin_pol.policy_reference_name, + be32_to_cpu(pr_buf->len)); + return ret; +} + +int +acm_init_binary_policy(u32 policy_code) +{ + int ret = ACM_OK; + + acm_bin_pol.primary_policy_code = (policy_code & 0x0f); + acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f; + + write_lock(&acm_bin_pol_rwlock); + + /* set primary policy component */ + switch ((policy_code) & 0x0f) + { + + case ACM_CHINESE_WALL_POLICY: + acm_init_chwall_policy(); + acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY; + acm_primary_ops = &acm_chinesewall_ops; + break; + + case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: + acm_init_ste_policy(); + acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY; + acm_primary_ops = &acm_simple_type_enforcement_ops; + break; + + case ACM_NULL_POLICY: + acm_bin_pol.primary_policy_code = ACM_NULL_POLICY; + acm_primary_ops = &acm_null_ops; + break; + + default: + /* Unknown policy not allowed primary */ + ret = -EINVAL; + goto out; + } + + /* secondary policy component part */ + switch ((policy_code) >> 4) + { + + case ACM_NULL_POLICY: + acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY; + acm_secondary_ops = &acm_null_ops; + break; + + case ACM_CHINESE_WALL_POLICY: + if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY) + { /* not a valid combination */ + ret = -EINVAL; + goto out; + } + acm_init_chwall_policy(); + acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY; + acm_secondary_ops = &acm_chinesewall_ops; + break; + + case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: + if (acm_bin_pol.primary_policy_code == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) + { /* not a valid combination */ + ret = -EINVAL; + goto out; + } + acm_init_ste_policy(); + acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY; + acm_secondary_ops = &acm_simple_type_enforcement_ops; + break; + + default: + ret = -EINVAL; + goto out; + } + + out: + write_unlock(&acm_bin_pol_rwlock); + return ret; +} + +int +acm_is_policy(char *buf, unsigned long len) +{ + struct acm_policy_buffer *pol; + + if (buf == NULL || len < sizeof(struct acm_policy_buffer)) + return 0; + + pol = (struct acm_policy_buffer *)buf; + return be32_to_cpu(pol->magic) == ACM_MAGIC; +} + +static __init int acm_init(void) +{ + int ret = ACM_OK; + + printk("ACM-XSM: Initializing.\n"); + + if (acm_active_security_policy != ACM_POLICY_UNDEFINED) + { + printk("%s: Enforcing %s boot policy.\n", __func__, + ACM_POLICY_NAME(acm_active_security_policy)); + goto out; + } + /* else continue with the minimal hardcoded default startup policy */ + printk("%s: Loading default policy (%s).\n", + __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY)); + + if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) { + ret = -EINVAL; + goto out; + } + acm_active_security_policy = ACM_DEFAULT_SECURITY_POLICY; + if (acm_active_security_policy != ACM_NULL_POLICY) + acm_bin_pol.policy_reference_name = "DEFAULT"; + else + acm_bin_pol.policy_reference_name = "NULL"; + + out: + if (ret != ACM_OK) + { + printk("%s: Error initializing policies.\n", __func__); + /* here one could imagine a clean panic */ + return -EINVAL; + } + + if (register_xsm(&acm_xsm_ops)) + panic("ACM-XSM: Unable to register with XSM.\n"); + + return ret; +} + +xsm_initcall(acm_init); + +int +acm_init_domain_ssid(domid_t id, ssidref_t ssidref) +{ + struct acm_ssid_domain *ssid; + struct domain *subj = rcu_lock_domain_by_id(id); + int ret1, ret2; + + if (subj == NULL) + { + printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id); + return ACM_NULL_POINTER_ERROR; + } + if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL) + { + rcu_unlock_domain(subj); + return ACM_INIT_SSID_ERROR; + } + + ssid->datatype = ACM_DATATYPE_domain; + ssid->subject = subj; + ssid->domainid = subj->domain_id; + ssid->primary_ssid = NULL; + ssid->secondary_ssid = NULL; + + if (acm_active_security_policy != ACM_NULL_POLICY) + ssid->ssidref = ssidref; + else + ssid->ssidref = ACM_DEFAULT_SSID; + + subj->ssid = ssid; + /* now fill in primary and secondary parts; we only get here through hooks */ + if (acm_primary_ops->init_domain_ssid != NULL) + ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref); + else + ret1 = ACM_OK; + + if (acm_secondary_ops->init_domain_ssid != NULL) + ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref); + else + ret2 = ACM_OK; + + if ((ret1 != ACM_OK) || (ret2 != ACM_OK)) + { + printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n", + __func__, subj->domain_id); + acm_free_domain_ssid(ssid); + rcu_unlock_domain(subj); + return ACM_INIT_SSID_ERROR; + } + printkd("%s: assigned domain %x the ssidref=%x.\n", + __func__, id, ssid->ssidref); + rcu_unlock_domain(subj); + return ACM_OK; +} + + +void +acm_free_domain_ssid(struct acm_ssid_domain *ssid) +{ + /* domain is already gone, just ssid is left */ + if (ssid == NULL) + return; + + ssid->subject = NULL; + if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */ + acm_primary_ops->free_domain_ssid(ssid->primary_ssid); + ssid->primary_ssid = NULL; + if (acm_secondary_ops->free_domain_ssid != NULL) + acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid); + ssid->secondary_ssid = NULL; + xfree(ssid); + printkd("%s: Freed individual domain ssid (domain=%02x).\n", + __func__, id); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_null_hooks.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_null_hooks.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,89 @@ +/**************************************************************** + * acm_null_hooks.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#include + +static int +null_init_domain_ssid(void **ssid, ssidref_t ssidref) +{ + return ACM_OK; +} + +static void +null_free_domain_ssid(void *ssid) +{ + return; +} + +static int +null_dump_binary_policy(u8 *buf, u32 buf_size) +{ + return 0; +} + +static int +null_set_binary_policy(u8 *buf, u32 buf_size) +{ + return ACM_OK; +} + +static int +null_dump_stats(u8 *buf, u16 buf_size) +{ + /* no stats for NULL policy */ + return 0; +} + +static int +null_dump_ssid_types(ssidref_t ssidref, u8 *buffer, u16 buf_size) +{ + /* no types */ + return 0; +} + + +/* now define the hook structure similarly to LSM */ +struct acm_operations acm_null_ops = { + .init_domain_ssid = null_init_domain_ssid, + .free_domain_ssid = null_free_domain_ssid, + .dump_binary_policy = null_dump_binary_policy, + .set_binary_policy = null_set_binary_policy, + .dump_statistics = null_dump_stats, + .dump_ssid_types = null_dump_ssid_types, + /* domain management control hooks */ + .pre_domain_create = NULL, + .post_domain_create = NULL, + .fail_domain_create = NULL, + .post_domain_destroy = NULL, + /* event channel control hooks */ + .pre_eventchannel_unbound = NULL, + .fail_eventchannel_unbound = NULL, + .pre_eventchannel_interdomain = NULL, + .fail_eventchannel_interdomain = NULL, + /* grant table control hooks */ + .pre_grant_map_ref = NULL, + .fail_grant_map_ref = NULL, + .pre_grant_setup = NULL, + .fail_grant_setup = NULL +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_ops.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_ops.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,241 @@ +/****************************************************************************** + * acm_ops.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * Process acm command requests from guest OS. + * + */ + +#ifndef COMPAT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef long ret_t; + +#endif /* !COMPAT */ + +#ifndef ACM_SECURITY + + +long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) +{ + return -ENOSYS; +} + + +#else + + +#ifndef COMPAT +int acm_authorize_acm_ops(struct domain *d) +{ + /* currently, policy management functions are restricted to privileged domains */ + if (!IS_PRIV(d)) + return -EPERM; + return 0; +} +#endif + + +ret_t do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) +{ + ret_t rc = -EFAULT; + + if (acm_authorize_acm_ops(current->domain)) + return -EPERM; + + switch ( cmd ) + { + + case ACMOP_setpolicy: { + struct acm_setpolicy setpolicy; + if (copy_from_guest(&setpolicy, arg, 1) != 0) + return -EFAULT; + if (setpolicy.interface_version != ACM_INTERFACE_VERSION) + return -EACCES; + + rc = acm_set_policy(setpolicy.pushcache, + setpolicy.pushcache_size); + break; + } + + case ACMOP_getpolicy: { + struct acm_getpolicy getpolicy; + if (copy_from_guest(&getpolicy, arg, 1) != 0) + return -EFAULT; + if (getpolicy.interface_version != ACM_INTERFACE_VERSION) + return -EACCES; + + rc = acm_get_policy(getpolicy.pullcache, + getpolicy.pullcache_size); + break; + } + + case ACMOP_dumpstats: { + struct acm_dumpstats dumpstats; + if (copy_from_guest(&dumpstats, arg, 1) != 0) + return -EFAULT; + if (dumpstats.interface_version != ACM_INTERFACE_VERSION) + return -EACCES; + + rc = acm_dump_statistics(dumpstats.pullcache, + dumpstats.pullcache_size); + break; + } + + case ACMOP_getssid: { + struct acm_getssid getssid; + ssidref_t ssidref; + + if (copy_from_guest(&getssid, arg, 1) != 0) + return -EFAULT; + if (getssid.interface_version != ACM_INTERFACE_VERSION) + return -EACCES; + + if (getssid.get_ssid_by == ACM_GETBY_ssidref) + ssidref = getssid.id.ssidref; + else if (getssid.get_ssid_by == ACM_GETBY_domainid) + { + struct domain *subj = rcu_lock_domain_by_id(getssid.id.domainid); + if (!subj) + { + rc = -ESRCH; /* domain not found */ + break; + } + if (subj->ssid == NULL) + { + rcu_unlock_domain(subj); + rc = -ESRCH; + break; + } + ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; + rcu_unlock_domain(subj); + } + else + { + rc = -ESRCH; + break; + } + rc = acm_get_ssid(ssidref, getssid.ssidbuf, getssid.ssidbuf_size); + break; + } + + case ACMOP_getdecision: { + struct acm_getdecision getdecision; + ssidref_t ssidref1, ssidref2; + + if (copy_from_guest(&getdecision, arg, 1) != 0) + return -EFAULT; + if (getdecision.interface_version != ACM_INTERFACE_VERSION) + return -EACCES; + + if (getdecision.get_decision_by1 == ACM_GETBY_ssidref) + ssidref1 = getdecision.id1.ssidref; + else if (getdecision.get_decision_by1 == ACM_GETBY_domainid) + { + struct domain *subj = rcu_lock_domain_by_id(getdecision.id1.domainid); + if (!subj) + { + rc = -ESRCH; /* domain not found */ + break; + } + if (subj->ssid == NULL) + { + rcu_unlock_domain(subj); + rc = -ESRCH; + break; + } + ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; + rcu_unlock_domain(subj); + } + else + { + rc = -ESRCH; + break; + } + if (getdecision.get_decision_by2 == ACM_GETBY_ssidref) + ssidref2 = getdecision.id2.ssidref; + else if (getdecision.get_decision_by2 == ACM_GETBY_domainid) + { + struct domain *subj = rcu_lock_domain_by_id(getdecision.id2.domainid); + if (!subj) + { + rc = -ESRCH; /* domain not found */ + break;; + } + if (subj->ssid == NULL) + { + rcu_unlock_domain(subj); + rc = -ESRCH; + break; + } + ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; + rcu_unlock_domain(subj); + } + else + { + rc = -ESRCH; + break; + } + rc = acm_get_decision(ssidref1, ssidref2, getdecision.hook); + + if (rc == ACM_ACCESS_PERMITTED) + { + getdecision.acm_decision = ACM_ACCESS_PERMITTED; + rc = 0; + } + else if (rc == ACM_ACCESS_DENIED) + { + getdecision.acm_decision = ACM_ACCESS_DENIED; + rc = 0; + } + else + rc = -ESRCH; + + if ( (rc == 0) && (copy_to_guest(arg, &getdecision, 1) != 0) ) + rc = -EFAULT; + break; + } + + default: + rc = -ENOSYS; + break; + } + + return rc; +} + +#endif + +#if defined(CONFIG_COMPAT) && !defined(COMPAT) +#include "compat/acm_ops.c" +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_policy.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_policy.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,325 @@ +/**************************************************************** + * acm_policy.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributors: + * Stefan Berger + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * sHype access control policy management for Xen. + * This interface allows policy tools in authorized + * domains to interact with the Xen access control module + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) +{ + u8 *policy_buffer = NULL; + int ret = -EFAULT; + + if (buf_size < sizeof(struct acm_policy_buffer)) + return -EFAULT; + + /* copy buffer from guest domain */ + if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL) + return -ENOMEM; + + if (copy_from_guest(policy_buffer, buf, buf_size)) + { + printk("%s: Error copying!\n",__func__); + goto error_free; + } + ret = do_acm_set_policy(policy_buffer, buf_size); + + error_free: + xfree(policy_buffer); + return ret; +} + + +int +do_acm_set_policy(void *buf, u32 buf_size) +{ + struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf; + /* some sanity checking */ + if ((be32_to_cpu(pol->magic) != ACM_MAGIC) || + (buf_size != be32_to_cpu(pol->len)) || + (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION)) + { + printk("%s: ERROR in Magic, Version, or buf size.\n", __func__); + goto error_free; + } + + if (acm_active_security_policy == ACM_POLICY_UNDEFINED) { + /* setup the policy with the boot policy */ + if (acm_init_binary_policy((be32_to_cpu(pol->secondary_policy_code) << 4) | + be32_to_cpu(pol->primary_policy_code))) { + goto error_free; + } + acm_active_security_policy = + (acm_bin_pol.secondary_policy_code << 4) | acm_bin_pol.primary_policy_code; + } + + /* once acm_active_security_policy is set, it cannot be changed */ + if ((be32_to_cpu(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) || + (be32_to_cpu(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code)) + { + printkd("%s: Wrong policy type in boot policy!\n", __func__); + goto error_free; + } + + /* get bin_policy lock and rewrite policy (release old one) */ + write_lock(&acm_bin_pol_rwlock); + + /* set label reference name */ + if (acm_set_policy_reference(buf + be32_to_cpu(pol->policy_reference_offset), + be32_to_cpu(pol->primary_buffer_offset) - + be32_to_cpu(pol->policy_reference_offset))) + goto error_lock_free; + + /* set primary policy data */ + if (acm_primary_ops->set_binary_policy(buf + be32_to_cpu(pol->primary_buffer_offset), + be32_to_cpu(pol->secondary_buffer_offset) - + be32_to_cpu(pol->primary_buffer_offset))) + goto error_lock_free; + + /* set secondary policy data */ + if (acm_secondary_ops->set_binary_policy(buf + be32_to_cpu(pol->secondary_buffer_offset), + be32_to_cpu(pol->len) - + be32_to_cpu(pol->secondary_buffer_offset))) + goto error_lock_free; + + write_unlock(&acm_bin_pol_rwlock); + return ACM_OK; + + error_lock_free: + write_unlock(&acm_bin_pol_rwlock); + error_free: + printk("%s: Error setting policy.\n", __func__); + return -EFAULT; +} + +int +acm_get_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) +{ + u8 *policy_buffer; + int ret; + struct acm_policy_buffer *bin_pol; + + if (buf_size < sizeof(struct acm_policy_buffer)) + return -EFAULT; + + if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL) + return -ENOMEM; + + read_lock(&acm_bin_pol_rwlock); + + bin_pol = (struct acm_policy_buffer *)policy_buffer; + bin_pol->magic = cpu_to_be32(ACM_MAGIC); + bin_pol->primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); + bin_pol->secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); + + bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer)); + bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); + bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); + bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); + + ret = acm_dump_policy_reference(policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset), + buf_size - be32_to_cpu(bin_pol->policy_reference_offset)); + if (ret < 0) + goto error_free_unlock; + + bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); + bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); + + ret = acm_primary_ops->dump_binary_policy (policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset), + buf_size - be32_to_cpu(bin_pol->primary_buffer_offset)); + if (ret < 0) + goto error_free_unlock; + + bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); + bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); + + ret = acm_secondary_ops->dump_binary_policy(policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset), + buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset)); + if (ret < 0) + goto error_free_unlock; + + bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); + if (copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len))) + goto error_free_unlock; + + read_unlock(&acm_bin_pol_rwlock); + xfree(policy_buffer); + return ACM_OK; + + error_free_unlock: + read_unlock(&acm_bin_pol_rwlock); + printk("%s: Error getting policy.\n", __func__); + xfree(policy_buffer); + return -EFAULT; +} + +int +acm_dump_statistics(XEN_GUEST_HANDLE(void) buf, u16 buf_size) +{ + /* send stats to user space */ + u8 *stats_buffer; + int len1, len2; + struct acm_stats_buffer acm_stats; + + if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL) + return -ENOMEM; + + read_lock(&acm_bin_pol_rwlock); + + len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer), + buf_size - sizeof(struct acm_stats_buffer)); + if (len1 < 0) + goto error_lock_free; + + len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1, + buf_size - sizeof(struct acm_stats_buffer) - len1); + if (len2 < 0) + goto error_lock_free; + + acm_stats.magic = cpu_to_be32(ACM_MAGIC); + acm_stats.primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); + acm_stats.secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); + acm_stats.primary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer)); + acm_stats.secondary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1); + acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2); + + memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer)); + + if (copy_to_guest(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2)) + goto error_lock_free; + + read_unlock(&acm_bin_pol_rwlock); + xfree(stats_buffer); + return ACM_OK; + + error_lock_free: + read_unlock(&acm_bin_pol_rwlock); + xfree(stats_buffer); + return -EFAULT; +} + + +int +acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE(void) buf, u16 buf_size) +{ + /* send stats to user space */ + u8 *ssid_buffer; + int ret; + struct acm_ssid_buffer *acm_ssid; + if (buf_size < sizeof(struct acm_ssid_buffer)) + return -EFAULT; + + if ((ssid_buffer = xmalloc_array(u8, buf_size)) == NULL) + return -ENOMEM; + + read_lock(&acm_bin_pol_rwlock); + + acm_ssid = (struct acm_ssid_buffer *)ssid_buffer; + acm_ssid->len = sizeof(struct acm_ssid_buffer); + acm_ssid->ssidref = ssidref; + acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code; + acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code; + + acm_ssid->policy_reference_offset = acm_ssid->len; + ret = acm_dump_policy_reference(ssid_buffer + acm_ssid->policy_reference_offset, + buf_size - acm_ssid->policy_reference_offset); + if (ret < 0) + goto error_free_unlock; + + acm_ssid->len += ret; + acm_ssid->primary_types_offset = acm_ssid->len; + + /* ret >= 0 --> ret == max_types */ + ret = acm_primary_ops->dump_ssid_types(ACM_PRIMARY(ssidref), + ssid_buffer + acm_ssid->primary_types_offset, + buf_size - acm_ssid->primary_types_offset); + if (ret < 0) + goto error_free_unlock; + + acm_ssid->len += ret; + acm_ssid->primary_max_types = ret; + acm_ssid->secondary_types_offset = acm_ssid->len; + + ret = acm_secondary_ops->dump_ssid_types(ACM_SECONDARY(ssidref), + ssid_buffer + acm_ssid->secondary_types_offset, + buf_size - acm_ssid->secondary_types_offset); + if (ret < 0) + goto error_free_unlock; + + acm_ssid->len += ret; + acm_ssid->secondary_max_types = ret; + + if (copy_to_guest(buf, ssid_buffer, acm_ssid->len)) + goto error_free_unlock; + + read_unlock(&acm_bin_pol_rwlock); + xfree(ssid_buffer); + return ACM_OK; + + error_free_unlock: + read_unlock(&acm_bin_pol_rwlock); + printk("%s: Error getting ssid.\n", __func__); + xfree(ssid_buffer); + return -ENOMEM; +} + +int +acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook) +{ + int ret = ACM_ACCESS_DENIED; + switch (hook) { + + case ACMHOOK_sharing: + /* Sharing hook restricts access in STE policy only */ + ret = acm_sharing(ssidref1, ssidref2); + break; + + default: + /* deny */ + break; + } + + printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n", + __func__, ssidref1, ssidref2, + (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED"); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_simple_type_enforcement_hooks.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_simple_type_enforcement_hooks.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,701 @@ +/**************************************************************** + * acm_simple_type_enforcement_hooks.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributors: + * Stefan Berger + * support for network order binary policies + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * sHype Simple Type Enforcement for Xen + * STE allows to control which domains can setup sharing + * (eventchannels right now) with which other domains. Hooks + * are defined and called throughout Xen when domains bind to + * shared resources (setup eventchannels) and a domain is allowed + * to setup sharing with another domain if and only if both domains + * share at least on common type. + * + */ + +#include +#include +#include +#include +#include +#include + +/* local cache structures for STE policy */ +struct ste_binary_policy ste_bin_pol; + +static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) { + int i; + for(i=0; i< ste_bin_pol.max_types; i++) + if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] && + ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) { + printkd("%s: common type #%02x.\n", __func__, i); + return 1; + } + return 0; +} + +/* Helper function: return = (subj and obj share a common type) */ +static int share_common_type(struct domain *subj, struct domain *obj) +{ + ssidref_t ref_s, ref_o; + int ret; + + if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL)) + return 0; + read_lock(&acm_bin_pol_rwlock); + /* lookup the policy-local ssids */ + ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref; + ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref; + /* check whether subj and obj share a common ste type */ + ret = have_common_type(ref_s, ref_o); + read_unlock(&acm_bin_pol_rwlock); + return ret; +} + +/* + * Initializing STE policy (will be filled by policy partition + * using setpolicy command) + */ +int acm_init_ste_policy(void) +{ + /* minimal startup policy; policy write-locked already */ + ste_bin_pol.max_types = 1; + ste_bin_pol.max_ssidrefs = 2; + ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2); + memset(ste_bin_pol.ssidrefs, 0, 2); + + if (ste_bin_pol.ssidrefs == NULL) + return ACM_INIT_SSID_ERROR; + + /* initialize state so that dom0 can start up and communicate with itself */ + ste_bin_pol.ssidrefs[1] = 1; + + /* init stats */ + atomic_set(&(ste_bin_pol.ec_eval_count), 0); + atomic_set(&(ste_bin_pol.ec_denied_count), 0); + atomic_set(&(ste_bin_pol.ec_cachehit_count), 0); + atomic_set(&(ste_bin_pol.gt_eval_count), 0); + atomic_set(&(ste_bin_pol.gt_denied_count), 0); + atomic_set(&(ste_bin_pol.gt_cachehit_count), 0); + return ACM_OK; +} + + +/* ste initialization function hooks */ +static int +ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref) +{ + int i; + struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid); + traceprintk("%s.\n", __func__); + + if (ste_ssidp == NULL) + return ACM_INIT_SSID_ERROR; + + /* get policy-local ssid reference */ + ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref); + if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) || + (ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) { + printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n", + __func__, ste_ssidp->ste_ssidref); + xfree(ste_ssidp); + return ACM_INIT_SSID_ERROR; + } + /* clean ste cache */ + for (i=0; iste_cache[i].valid = ACM_STE_free; + + (*ste_ssid) = ste_ssidp; + printkd("%s: determined ste_ssidref to %x.\n", + __func__, ste_ssidp->ste_ssidref); + return ACM_OK; +} + + +static void +ste_free_domain_ssid(void *ste_ssid) +{ + traceprintk("%s.\n", __func__); + xfree(ste_ssid); + return; +} + +/* dump type enforcement cache; policy read-locked already */ +static int +ste_dump_policy(u8 *buf, u32 buf_size) { + struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf; + int ret = 0; + + if (buf_size < sizeof(struct acm_ste_policy_buffer)) + return -EINVAL; + + ste_buf->ste_max_types = cpu_to_be32(ste_bin_pol.max_types); + ste_buf->ste_max_ssidrefs = cpu_to_be32(ste_bin_pol.max_ssidrefs); + ste_buf->policy_code = cpu_to_be32(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); + ste_buf->ste_ssid_offset = cpu_to_be32(sizeof(struct acm_ste_policy_buffer)); + ret = be32_to_cpu(ste_buf->ste_ssid_offset) + + sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types; + + ret = (ret + 7) & ~7; + + if (buf_size < ret) + return -EINVAL; + + /* now copy buffer over */ + arrcpy(buf + be32_to_cpu(ste_buf->ste_ssid_offset), + ste_bin_pol.ssidrefs, + sizeof(domaintype_t), + ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types); + + return ret; +} + +/* ste_init_state is called when a policy is changed to detect violations (return != 0). + * from a security point of view, we simulate that all running domains are re-started and + * all sharing decisions are replayed to detect violations or current sharing behavior + * (right now: event_channels, future: also grant_tables) + */ +static int +ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs) +{ + int violation = 1; + struct ste_ssid *ste_ssid, *ste_rssid; + ssidref_t ste_ssidref, ste_rssidref; + struct domain *d, *rdom; + domid_t rdomid; + struct active_grant_entry *act; + int port, i; + + rcu_read_lock(&domlist_read_lock); + /* go by domain? or directly by global? event/grant list */ + /* go through all domains and adjust policy as if this domain was started now */ + for_each_domain ( d ) + { + struct evtchn *ports; + unsigned int bucket; + ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)d->ssid); + ste_ssidref = ste_ssid->ste_ssidref; + traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n", + __func__, d->domain_id, ste_ssidref); + /* a) check for event channel conflicts */ + for (bucket = 0; bucket < NR_EVTCHN_BUCKETS; bucket++) { + spin_lock(&d->evtchn_lock); + ports = d->evtchn[bucket]; + if (ports == NULL) { + spin_unlock(&d->evtchn_lock); + break; + } + + for (port=0; port < EVTCHNS_PER_BUCKET; port++) { + if (ports[port].state == ECS_INTERDOMAIN) { + rdom = ports[port].u.interdomain.remote_dom; + rdomid = rdom->domain_id; + } else { + continue; /* port unused */ + } + + /* rdom now has remote domain */ + ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)(rdom->ssid)); + ste_rssidref = ste_rssid->ste_ssidref; + traceprintk("%s: eventch: domain %x (ssidref %x) --> " + "domain %x (rssidref %x) used (port %x).\n", + __func__, d->domain_id, ste_ssidref, + rdom->domain_id, ste_rssidref, port); + /* check whether on subj->ssid, obj->ssid share a common type*/ + if (!have_common_type(ste_ssidref, ste_rssidref)) { + printkd("%s: Policy violation in event channel domain " + "%x -> domain %x.\n", + __func__, d->domain_id, rdomid); + spin_unlock(&d->evtchn_lock); + goto out; + } + } + spin_unlock(&d->evtchn_lock); + } + + /* b) check for grant table conflicts on shared pages */ + spin_lock(&d->grant_table->lock); + for ( i = 0; i < nr_active_grant_frames(d->grant_table); i++ ) { +#define APP (PAGE_SIZE / sizeof(struct active_grant_entry)) + act = &d->grant_table->active[i/APP][i%APP]; + if ( act->pin != 0 ) { + printkd("%s: grant dom (%hu) SHARED (%d) pin (%d) " + "dom:(%hu) frame:(%lx)\n", + __func__, d->domain_id, i, act->pin, + act->domid, (unsigned long)act->frame); + rdomid = act->domid; + if ((rdom = rcu_lock_domain_by_id(rdomid)) == NULL) { + spin_unlock(&d->grant_table->lock); + printkd("%s: domain not found ERROR!\n", __func__); + goto out; + } + /* rdom now has remote domain */ + ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)(rdom->ssid)); + ste_rssidref = ste_rssid->ste_ssidref; + rcu_unlock_domain(rdom); + if (!have_common_type(ste_ssidref, ste_rssidref)) { + spin_unlock(&d->grant_table->lock); + printkd("%s: Policy violation in grant table " + "sharing domain %x -> domain %x.\n", + __func__, d->domain_id, rdomid); + goto out; + } + } + } + spin_unlock(&d->grant_table->lock); + } + violation = 0; + out: + rcu_read_unlock(&domlist_read_lock); + return violation; + /* returning "violation != 0" means that existing sharing between domains would not + * have been allowed if the new policy had been enforced before the sharing; for ste, + * this means that there are at least 2 domains that have established sharing through + * event-channels or grant-tables but these two domains don't have no longer a common + * type in their typesets referenced by their ssidrefs */ +} + +/* set new policy; policy write-locked already */ +static int +ste_set_policy(u8 *buf, u32 buf_size) +{ + struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf; + void *ssidrefsbuf; + struct ste_ssid *ste_ssid; + struct domain *d; + int i; + + if (buf_size < sizeof(struct acm_ste_policy_buffer)) + return -EINVAL; + + /* Convert endianess of policy */ + ste_buf->policy_code = be32_to_cpu(ste_buf->policy_code); + ste_buf->policy_version = be32_to_cpu(ste_buf->policy_version); + ste_buf->ste_max_types = be32_to_cpu(ste_buf->ste_max_types); + ste_buf->ste_max_ssidrefs = be32_to_cpu(ste_buf->ste_max_ssidrefs); + ste_buf->ste_ssid_offset = be32_to_cpu(ste_buf->ste_ssid_offset); + + /* policy type and version checks */ + if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) || + (ste_buf->policy_version != ACM_STE_VERSION)) + return -EINVAL; + + /* 1. create and copy-in new ssidrefs buffer */ + ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs); + if (ssidrefsbuf == NULL) { + return -ENOMEM; + } + if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size) + goto error_free; + + arrcpy(ssidrefsbuf, + buf + ste_buf->ste_ssid_offset, + sizeof(domaintype_t), + ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types); + + /* 2. now re-calculate sharing decisions based on running domains; + * this can fail if new policy is conflicting with sharing of running domains + * now: reject violating new policy; future: adjust sharing through revoking sharing */ + if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) { + printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__); + goto error_free; /* new policy conflicts with sharing of running domains */ + } + /* 3. replace old policy (activate new policy) */ + ste_bin_pol.max_types = ste_buf->ste_max_types; + ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs; + xfree(ste_bin_pol.ssidrefs); + ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf; + + /* clear all ste caches */ + rcu_read_lock(&domlist_read_lock); + for_each_domain ( d ) { + ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)(d)->ssid); + for (i=0; iste_cache[i].valid = ACM_STE_free; + } + rcu_read_unlock(&domlist_read_lock); + return ACM_OK; + + error_free: + printk("%s: ERROR setting policy.\n", __func__); + xfree(ssidrefsbuf); + return -EFAULT; +} + +static int +ste_dump_stats(u8 *buf, u16 buf_len) +{ + struct acm_ste_stats_buffer stats; + + /* now send the hook counts to user space */ + stats.ec_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_eval_count)); + stats.gt_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_eval_count)); + stats.ec_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_denied_count)); + stats.gt_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_denied_count)); + stats.ec_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_cachehit_count)); + stats.gt_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_cachehit_count)); + + if (buf_len < sizeof(struct acm_ste_stats_buffer)) + return -ENOMEM; + + memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer)); + return sizeof(struct acm_ste_stats_buffer); +} + +static int +ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len) +{ + int i; + + /* fill in buffer */ + if (ste_bin_pol.max_types > len) + return -EFAULT; + + if (ssidref >= ste_bin_pol.max_ssidrefs) + return -EFAULT; + + /* read types for chwall ssidref */ + for(i=0; i< ste_bin_pol.max_types; i++) { + if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i]) + buf[i] = 1; + else + buf[i] = 0; + } + return ste_bin_pol.max_types; +} + +/* we need to go through this before calling the hooks, + * returns 1 == cache hit */ +static int inline +check_cache(struct domain *dom, domid_t rdom) { + struct ste_ssid *ste_ssid; + int i; + + printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom); + + if (dom->ssid == NULL) + return 0; + ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)(dom->ssid)); + + for(i=0; i< ACM_TE_CACHE_SIZE; i++) { + if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) && + (ste_ssid->ste_cache[i].id == rdom)) { + printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id); + return 1; + } + } + return 0; +} + + +/* we only get here if there is NO entry yet; no duplication check! */ +static void inline +cache_result(struct domain *subj, struct domain *obj) { + struct ste_ssid *ste_ssid; + int i; + printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id); + if (subj->ssid == NULL) + return; + ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, + (struct acm_ssid_domain *)(subj)->ssid); + for(i=0; i< ACM_TE_CACHE_SIZE; i++) + if (ste_ssid->ste_cache[i].valid == ACM_STE_free) + break; + if (i< ACM_TE_CACHE_SIZE) { + ste_ssid->ste_cache[i].valid = ACM_STE_valid; + ste_ssid->ste_cache[i].id = obj->domain_id; + } else + printk ("Cache of dom %x is full!\n", subj->domain_id); +} + +/* deletes entries for domain 'id' from all caches (re-use) */ +static void inline +clean_id_from_cache(domid_t id) +{ + struct ste_ssid *ste_ssid; + int i; + struct domain *d; + struct acm_ssid_domain *ssid; + + printkd("deleting cache for dom %x.\n", id); + rcu_read_lock(&domlist_read_lock); + /* look through caches of all domains */ + for_each_domain ( d ) { + ssid = (struct acm_ssid_domain *)(d->ssid); + + if (ssid == NULL) + continue; /* hanging domain structure, no ssid any more ... */ + ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid); + if (!ste_ssid) { + printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n", + __func__); + goto out; + } + for (i=0; iste_cache[i].valid == ACM_STE_valid) && + (ste_ssid->ste_cache[i].id == id)) + ste_ssid->ste_cache[i].valid = ACM_STE_free; + } + out: + rcu_read_unlock(&domlist_read_lock); +} + +/*************************** + * Authorization functions + **************************/ +static int +ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref) +{ + /* check for ssidref in range for policy */ + ssidref_t ste_ssidref; + traceprintk("%s.\n", __func__); + + read_lock(&acm_bin_pol_rwlock); + ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref); + if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) { + printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__); + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_DENIED; /* catching and indicating config error */ + } + if (ste_ssidref >= ste_bin_pol.max_ssidrefs) { + printk("%s: ERROR ste_ssidref > max(%x).\n", + __func__, ste_bin_pol.max_ssidrefs-1); + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_DENIED; + } + read_unlock(&acm_bin_pol_rwlock); + return ACM_ACCESS_PERMITTED; +} + +static void +ste_post_domain_destroy(void *subject_ssid, domid_t id) +{ + /* clean all cache entries for destroyed domain (might be re-used) */ + clean_id_from_cache(id); +} + +/* -------- EVENTCHANNEL OPERATIONS -----------*/ +static int +ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) { + struct domain *subj, *obj; + int ret; + traceprintk("%s: dom%x-->dom%x.\n", __func__, + (id1 == DOMID_SELF) ? current->domain->domain_id : id1, + (id2 == DOMID_SELF) ? current->domain->domain_id : id2); + + if (id1 == DOMID_SELF) id1 = current->domain->domain_id; + if (id2 == DOMID_SELF) id2 = current->domain->domain_id; + + subj = rcu_lock_domain_by_id(id1); + obj = rcu_lock_domain_by_id(id2); + if ((subj == NULL) || (obj == NULL)) { + ret = ACM_ACCESS_DENIED; + goto out; + } + /* cache check late */ + if (check_cache(subj, obj->domain_id)) { + atomic_inc(&ste_bin_pol.ec_cachehit_count); + ret = ACM_ACCESS_PERMITTED; + goto out; + } + atomic_inc(&ste_bin_pol.ec_eval_count); + + if (share_common_type(subj, obj)) { + cache_result(subj, obj); + ret = ACM_ACCESS_PERMITTED; + } else { + atomic_inc(&ste_bin_pol.ec_denied_count); + ret = ACM_ACCESS_DENIED; + } + out: + if (obj != NULL) + rcu_unlock_domain(obj); + if (subj != NULL) + rcu_unlock_domain(subj); + return ret; +} + +static int +ste_pre_eventchannel_interdomain(domid_t id) +{ + struct domain *subj=NULL, *obj=NULL; + int ret; + + traceprintk("%s: dom%x-->dom%x.\n", __func__, + current->domain->domain_id, + (id == DOMID_SELF) ? current->domain->domain_id : id); + + /* following is a bit longer but ensures that we + * "put" only domains that we where "find"-ing + */ + if (id == DOMID_SELF) id = current->domain->domain_id; + + subj = current->domain; + obj = rcu_lock_domain_by_id(id); + if (obj == NULL) { + ret = ACM_ACCESS_DENIED; + goto out; + } + + /* cache check late, but evtchn is not on performance critical path */ + if (check_cache(subj, obj->domain_id)) { + atomic_inc(&ste_bin_pol.ec_cachehit_count); + ret = ACM_ACCESS_PERMITTED; + goto out; + } + + atomic_inc(&ste_bin_pol.ec_eval_count); + + if (share_common_type(subj, obj)) { + cache_result(subj, obj); + ret = ACM_ACCESS_PERMITTED; + } else { + atomic_inc(&ste_bin_pol.ec_denied_count); + ret = ACM_ACCESS_DENIED; + } + out: + if (obj != NULL) + rcu_unlock_domain(obj); + return ret; +} + +/* -------- SHARED MEMORY OPERATIONS -----------*/ + +static int +ste_pre_grant_map_ref (domid_t id) { + struct domain *obj, *subj; + int ret; + traceprintk("%s: dom%x-->dom%x.\n", __func__, + current->domain->domain_id, id); + + if (check_cache(current->domain, id)) { + atomic_inc(&ste_bin_pol.gt_cachehit_count); + return ACM_ACCESS_PERMITTED; + } + atomic_inc(&ste_bin_pol.gt_eval_count); + subj = current->domain; + obj = rcu_lock_domain_by_id(id); + + if (share_common_type(subj, obj)) { + cache_result(subj, obj); + ret = ACM_ACCESS_PERMITTED; + } else { + atomic_inc(&ste_bin_pol.gt_denied_count); + printkd("%s: ACCESS DENIED!\n", __func__); + ret = ACM_ACCESS_DENIED; + } + if (obj != NULL) + rcu_unlock_domain(obj); + return ret; +} + + +/* since setting up grant tables involves some implicit information + flow from the creating domain to the domain that is setup, we + check types in addition to the general authorization */ +static int +ste_pre_grant_setup (domid_t id) { + struct domain *obj, *subj; + int ret; + traceprintk("%s: dom%x-->dom%x.\n", __func__, + current->domain->domain_id, id); + + if (check_cache(current->domain, id)) { + atomic_inc(&ste_bin_pol.gt_cachehit_count); + return ACM_ACCESS_PERMITTED; + } + atomic_inc(&ste_bin_pol.gt_eval_count); + /* a) check authorization (eventually use specific capabilities) */ + if (!IS_PRIV(current->domain)) { + printk("%s: Grant table management authorization denied ERROR!\n", __func__); + return ACM_ACCESS_DENIED; + } + /* b) check types */ + subj = current->domain; + obj = rcu_lock_domain_by_id(id); + + if (share_common_type(subj, obj)) { + cache_result(subj, obj); + ret = ACM_ACCESS_PERMITTED; + } else { + atomic_inc(&ste_bin_pol.gt_denied_count); + ret = ACM_ACCESS_DENIED; + } + if (obj != NULL) + rcu_unlock_domain(obj); + return ret; +} + +/* -------- DOMAIN-Requested Decision hooks -----------*/ + +static int +ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) { + if (have_common_type ( + GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1), + GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2) + )) + return ACM_ACCESS_PERMITTED; + else + return ACM_ACCESS_DENIED; +} + + +/* now define the hook structure similarly to LSM */ +struct acm_operations acm_simple_type_enforcement_ops = { + + /* policy management services */ + .init_domain_ssid = ste_init_domain_ssid, + .free_domain_ssid = ste_free_domain_ssid, + .dump_binary_policy = ste_dump_policy, + .set_binary_policy = ste_set_policy, + .dump_statistics = ste_dump_stats, + .dump_ssid_types = ste_dump_ssid_types, + + /* domain management control hooks */ + .pre_domain_create = ste_pre_domain_create, + .post_domain_create = NULL, + .fail_domain_create = NULL, + .post_domain_destroy = ste_post_domain_destroy, + + /* event channel control hooks */ + .pre_eventchannel_unbound = ste_pre_eventchannel_unbound, + .fail_eventchannel_unbound = NULL, + .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain, + .fail_eventchannel_interdomain = NULL, + + /* grant table control hooks */ + .pre_grant_map_ref = ste_pre_grant_map_ref, + .fail_grant_map_ref = NULL, + .pre_grant_setup = ste_pre_grant_setup, + .fail_grant_setup = NULL, + .sharing = ste_sharing, +}; + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/acm_xsm_hooks.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/acm_xsm_hooks.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,195 @@ +/**************************************************************** + * acm_xsm_hooks.c + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributors: + * Michael LeMay, + * George Coker, + * + * sHype hooks for XSM based on the original ACM hooks. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ + +#include +#include +#include + +static int acm_createdomain (struct xen_domctl *op) +{ + void *subject_ssid = current->domain->ssid; + ssidref_t ssidref = op->u.createdomain.ssidref; + + if ((acm_primary_ops->pre_domain_create != NULL) && + acm_primary_ops->pre_domain_create(subject_ssid, ssidref)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_domain_create != NULL) && + acm_secondary_ops->pre_domain_create(subject_ssid, ssidref)) { + /* roll-back primary */ + if (acm_primary_ops->fail_domain_create != NULL) + acm_primary_ops->fail_domain_create(subject_ssid, ssidref); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} + +static void acm_createdomain_post (struct domain *d, struct xen_domctl *op) +{ + ssidref_t ssidref = op->u.createdomain.ssidref; + + /* initialialize shared sHype security labels for new domain */ + acm_init_domain_ssid(d->domain_id, ssidref); + + if (acm_primary_ops->post_domain_create != NULL) + acm_primary_ops->post_domain_create(d->domain_id, ssidref); + if (acm_secondary_ops->post_domain_create != NULL) + acm_secondary_ops->post_domain_create(d->domain_id, ssidref); +} + +static int acm_destroydomain (struct domain *d) +{ + int ret = -EACCES; + void *ssid = NULL; + + if (d != NULL) { + ssid = d->ssid; + + if (ssid == NULL) { + printk("%s: Warning. Destroying domain without ssid pointer.\n", __func__); + return -EACCES; + } + + ret = 0; + } + + return ret; +} + +static void acm_destroydomain_post (struct domain *d) +{ + domid_t id = d->domain_id; + + if (acm_primary_ops->post_domain_destroy != NULL) + acm_primary_ops->post_domain_destroy(d->ssid, id); + if (acm_secondary_ops->post_domain_destroy != NULL) + acm_secondary_ops->post_domain_destroy(d->ssid, id); + + /* free security ssid for the destroyed domain (also if null policy */ + acm_free_domain_ssid((struct acm_ssid_domain *)(d->ssid)); + d->ssid = NULL; +} + +static void acm_createdomain_fail (struct xen_domctl *op) +{ + acm_fail_domain_create( + current->domain->ssid, op->u.createdomain.ssidref); +} + +static int acm_grant_mapref (struct domain *ld, struct domain *rd, + uint32_t flags) +{ + domid_t id = rd->domain_id; + + if ( (acm_primary_ops->pre_grant_map_ref != NULL) && + acm_primary_ops->pre_grant_map_ref(id) ) + { + return ACM_ACCESS_DENIED; + } + else if ( (acm_secondary_ops->pre_grant_map_ref != NULL) && + acm_secondary_ops->pre_grant_map_ref(id) ) + { + /* roll-back primary */ + if ( acm_primary_ops->fail_grant_map_ref != NULL ) + acm_primary_ops->fail_grant_map_ref(id); + return ACM_ACCESS_DENIED; + } + else + { + return ACM_ACCESS_PERMITTED; + } +} + +static int acm_evtchn_unbound (struct domain *d1, struct evtchn *chn1, domid_t id2) +{ + domid_t id1 = d1->domain_id; + + if ((acm_primary_ops->pre_eventchannel_unbound != NULL) && + acm_primary_ops->pre_eventchannel_unbound(id1, id2)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) && + acm_secondary_ops->pre_eventchannel_unbound(id1, id2)) { + /* roll-back primary */ + if (acm_primary_ops->fail_eventchannel_unbound != NULL) + acm_primary_ops->fail_eventchannel_unbound(id1, id2); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} + +static int acm_evtchn_interdomain (struct domain *d1, struct evtchn *chn1, + struct domain *d2, struct evtchn *chn2) +{ + domid_t id2 = d2->domain_id; + + if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) && + acm_primary_ops->pre_eventchannel_interdomain(id2)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) && + acm_secondary_ops->pre_eventchannel_interdomain(id2)) { + /* roll-back primary */ + if (acm_primary_ops->fail_eventchannel_interdomain != NULL) + acm_primary_ops->fail_eventchannel_interdomain(id2); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} + +static void acm_complete_init (struct domain *dom0) +{ + domid_t domid = dom0->domain_id; + + acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF); + + if (acm_primary_ops->post_domain_create != NULL) + acm_primary_ops->post_domain_create(domid, ACM_DOM0_SSIDREF); + if (acm_secondary_ops->post_domain_create != NULL) + acm_secondary_ops->post_domain_create(domid, ACM_DOM0_SSIDREF); + +} + +static void acm_security_domaininfo (struct domain *d, + struct xen_domctl_getdomaininfo *info) +{ + if (d->ssid != NULL) + info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref; + else + info->ssidref = ACM_DEFAULT_SSID; +} + +extern long do_acm_op(int cmd, XEN_GUEST_HANDLE(xsm_op_t) arg); + +struct xsm_operations acm_xsm_ops = { + .createdomain = acm_createdomain, + .createdomain_post = acm_createdomain_post, + .createdomain_fail = acm_createdomain_fail, + .destroydomain = acm_destroydomain, + .free_security_domain = acm_destroydomain_post, + + .grant_mapref = acm_grant_mapref, + + .evtchn_unbound = acm_evtchn_unbound, + .evtchn_interdomain = acm_evtchn_interdomain, + .complete_init = acm_complete_init, + + .security_domaininfo = acm_security_domaininfo, + + .__do_xsm_op = do_acm_op, +}; diff -r f77a9736d9f4 -r 2f5b1793c585 xen/xsm/acm/compat/acm_ops.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/xsm/acm/compat/acm_ops.c Tue Mar 13 13:57:21 2007 -0400 @@ -0,0 +1,47 @@ +/****************************************************************************** + * compat/acm_ops.c + */ + +#include +#include + +#define COMPAT +#define ret_t int + +#define do_acm_op compat_acm_op + +static inline XEN_GUEST_HANDLE(void) acm_xlat_handle(COMPAT_HANDLE(void) cmp) +{ + XEN_GUEST_HANDLE(void) nat; + + guest_from_compat_handle(nat, cmp); + return nat; +} + +#define acm_setpolicy compat_acm_setpolicy +#define acm_set_policy(h, sz) acm_set_policy(acm_xlat_handle(h), sz) + +#define acm_getpolicy compat_acm_getpolicy +#define acm_get_policy(h, sz) acm_get_policy(acm_xlat_handle(h), sz) + +#define acm_dumpstats compat_acm_dumpstats +#define acm_dump_statistics(h, sz) acm_dump_statistics(acm_xlat_handle(h), sz) + +#define acm_getssid compat_acm_getssid +#define acm_get_ssid(r, h, sz) acm_get_ssid(r, acm_xlat_handle(h), sz) + +#define xen_acm_getdecision acm_getdecision +CHECK_acm_getdecision; +#undef xen_acm_getdecision + +#include "../acm_ops.c" + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/Makefile --- a/xen/acm/Makefile Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -obj-y += acm_core.o -obj-y += acm_policy.o -obj-y += acm_simple_type_enforcement_hooks.o -obj-y += acm_chinesewall_hooks.o -obj-y += acm_null_hooks.o diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/acm_chinesewall_hooks.c --- a/xen/acm/acm_chinesewall_hooks.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,634 +0,0 @@ -/**************************************************************** - * acm_chinesewall_hooks.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * Contributions: - * Stefan Berger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * sHype Chinese Wall Policy for Xen - * This code implements the hooks that are called - * throughout Xen operations and decides authorization - * based on domain types and Chinese Wall conflict type - * sets. The CHWALL policy decides if a new domain can be started - * based on the types of running domains and the type of the - * new domain to be started. If the new domain's type is in - * conflict with types of running domains, then this new domain - * is not allowed to be created. A domain can have multiple types, - * in which case all types of a new domain must be conflict-free - * with all types of already running domains. - * - * indent -i4 -kr -nut - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* local cache structures for chinese wall policy */ -struct chwall_binary_policy chwall_bin_pol; - -/* - * Initializing chinese wall policy (will be filled by policy partition - * using setpolicy command) - */ -int acm_init_chwall_policy(void) -{ - /* minimal startup policy; policy write-locked already */ - chwall_bin_pol.max_types = 1; - chwall_bin_pol.max_ssidrefs = 2; - chwall_bin_pol.max_conflictsets = 1; - chwall_bin_pol.ssidrefs = - (domaintype_t *) xmalloc_array(domaintype_t, - chwall_bin_pol.max_ssidrefs * - chwall_bin_pol.max_types); - chwall_bin_pol.conflict_sets = - (domaintype_t *) xmalloc_array(domaintype_t, - chwall_bin_pol.max_conflictsets * - chwall_bin_pol.max_types); - chwall_bin_pol.running_types = - (domaintype_t *) xmalloc_array(domaintype_t, - chwall_bin_pol.max_types); - chwall_bin_pol.conflict_aggregate_set = - (domaintype_t *) xmalloc_array(domaintype_t, - chwall_bin_pol.max_types); - - if ((chwall_bin_pol.conflict_sets == NULL) - || (chwall_bin_pol.running_types == NULL) - || (chwall_bin_pol.ssidrefs == NULL) - || (chwall_bin_pol.conflict_aggregate_set == NULL)) - return ACM_INIT_SSID_ERROR; - - /* initialize state */ - memset((void *) chwall_bin_pol.ssidrefs, 0, - chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types * - sizeof(domaintype_t)); - memset((void *) chwall_bin_pol.conflict_sets, 0, - chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types * - sizeof(domaintype_t)); - memset((void *) chwall_bin_pol.running_types, 0, - chwall_bin_pol.max_types * sizeof(domaintype_t)); - memset((void *) chwall_bin_pol.conflict_aggregate_set, 0, - chwall_bin_pol.max_types * sizeof(domaintype_t)); - return ACM_OK; -} - -static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref) -{ - struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid); - traceprintk("%s.\n", __func__); - if (chwall_ssidp == NULL) - return ACM_INIT_SSID_ERROR; - - chwall_ssidp->chwall_ssidref = - GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); - - if ((chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) - || (chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)) - { - printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n", - __func__, chwall_ssidp->chwall_ssidref); - xfree(chwall_ssidp); - return ACM_INIT_SSID_ERROR; - } - (*chwall_ssid) = chwall_ssidp; - printkd("%s: determined chwall_ssidref to %x.\n", - __func__, chwall_ssidp->chwall_ssidref); - return ACM_OK; -} - -static void chwall_free_domain_ssid(void *chwall_ssid) -{ - traceprintk("%s.\n", __func__); - xfree(chwall_ssid); - return; -} - - -/* dump chinese wall cache; policy read-locked already */ -static int chwall_dump_policy(u8 * buf, u32 buf_size) -{ - struct acm_chwall_policy_buffer *chwall_buf = - (struct acm_chwall_policy_buffer *) buf; - int ret = 0; - - if (buf_size < sizeof(struct acm_chwall_policy_buffer)) - return -EINVAL; - - chwall_buf->chwall_max_types = cpu_to_be32(chwall_bin_pol.max_types); - chwall_buf->chwall_max_ssidrefs = cpu_to_be32(chwall_bin_pol.max_ssidrefs); - chwall_buf->policy_code = cpu_to_be32(ACM_CHINESE_WALL_POLICY); - chwall_buf->chwall_ssid_offset = - cpu_to_be32(sizeof(struct acm_chwall_policy_buffer)); - chwall_buf->chwall_max_conflictsets = - cpu_to_be32(chwall_bin_pol.max_conflictsets); - chwall_buf->chwall_conflict_sets_offset = - cpu_to_be32(be32_to_cpu(chwall_buf->chwall_ssid_offset) + - sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs * - chwall_bin_pol.max_types); - chwall_buf->chwall_running_types_offset = - cpu_to_be32(be32_to_cpu(chwall_buf->chwall_conflict_sets_offset) + - sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets * - chwall_bin_pol.max_types); - chwall_buf->chwall_conflict_aggregate_offset = - cpu_to_be32(be32_to_cpu(chwall_buf->chwall_running_types_offset) + - sizeof(domaintype_t) * chwall_bin_pol.max_types); - - ret = be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset) + - sizeof(domaintype_t) * chwall_bin_pol.max_types; - - ret = (ret + 7) & ~7; - - if (buf_size < ret) - return -EINVAL; - - /* now copy buffers over */ - arrcpy16((u16 *) (buf + be32_to_cpu(chwall_buf->chwall_ssid_offset)), - chwall_bin_pol.ssidrefs, - chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types); - - arrcpy16((u16 *) (buf + - be32_to_cpu(chwall_buf->chwall_conflict_sets_offset)), - chwall_bin_pol.conflict_sets, - chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types); - - arrcpy16((u16 *) (buf + - be32_to_cpu(chwall_buf->chwall_running_types_offset)), - chwall_bin_pol.running_types, chwall_bin_pol.max_types); - - arrcpy16((u16 *) (buf + - be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset)), - chwall_bin_pol.conflict_aggregate_set, - chwall_bin_pol.max_types); - return ret; -} - -/* adapt security state (running_types and conflict_aggregate_set) to all running - * domains; chwall_init_state is called when a policy is changed to bring the security - * information into a consistent state and to detect violations (return != 0). - * from a security point of view, we simulate that all running domains are re-started - */ -static int -chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, - domaintype_t * ssidrefs, domaintype_t * conflict_sets, - domaintype_t * running_types, - domaintype_t * conflict_aggregate_set) -{ - int violation = 0, i, j; - struct chwall_ssid *chwall_ssid; - ssidref_t chwall_ssidref; - struct domain *d; - - spin_lock(&domlist_update_lock); - /* go through all domains and adjust policy as if this domain was started now */ - for_each_domain ( d ) - { - chwall_ssid = - GET_SSIDP(ACM_CHINESE_WALL_POLICY, - (struct acm_ssid_domain *)d->ssid); - chwall_ssidref = chwall_ssid->chwall_ssidref; - traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n", - __func__, d->domain_id, chwall_ssidref); - /* a) adjust types ref-count for running domains */ - for (i = 0; i < chwall_buf->chwall_max_types; i++) - running_types[i] += - ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i]; - - /* b) check for conflict */ - for (i = 0; i < chwall_buf->chwall_max_types; i++) - if (conflict_aggregate_set[i] && - ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i]) - { - printk("%s: CHINESE WALL CONFLICT in type %02x.\n", - __func__, i); - violation = 1; - goto out; - } - /* set violation and break out of the loop */ - /* c) adapt conflict aggregate set for this domain (notice conflicts) */ - for (i = 0; i < chwall_buf->chwall_max_conflictsets; i++) - { - int common = 0; - /* check if conflict_set_i and ssidref have common types */ - for (j = 0; j < chwall_buf->chwall_max_types; j++) - if (conflict_sets[i * chwall_buf->chwall_max_types + j] && - ssidrefs[chwall_ssidref * - chwall_buf->chwall_max_types + j]) - { - common = 1; - break; - } - if (common == 0) - continue; /* try next conflict set */ - /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ - for (j = 0; j < chwall_buf->chwall_max_types; j++) - if (conflict_sets[i * chwall_buf->chwall_max_types + j] && - !ssidrefs[chwall_ssidref * - chwall_buf->chwall_max_types + j]) - conflict_aggregate_set[j]++; - } - } - out: - spin_unlock(&domlist_update_lock); - return violation; - /* returning "violation != 0" means that the currently running set of domains would - * not be possible if the new policy had been enforced before starting them; for chinese - * wall, this means that the new policy includes at least one conflict set of which - * more than one type is currently running */ -} - -static int chwall_set_policy(u8 * buf, u32 buf_size) -{ - /* policy write-locked already */ - struct acm_chwall_policy_buffer *chwall_buf = - (struct acm_chwall_policy_buffer *) buf; - void *ssids = NULL, *conflict_sets = NULL, *running_types = - NULL, *conflict_aggregate_set = NULL; - - if (buf_size < sizeof(struct acm_chwall_policy_buffer)) - return -EINVAL; - - /* rewrite the policy due to endianess */ - chwall_buf->policy_code = be32_to_cpu(chwall_buf->policy_code); - chwall_buf->policy_version = be32_to_cpu(chwall_buf->policy_version); - chwall_buf->chwall_max_types = be32_to_cpu(chwall_buf->chwall_max_types); - chwall_buf->chwall_max_ssidrefs = - be32_to_cpu(chwall_buf->chwall_max_ssidrefs); - chwall_buf->chwall_max_conflictsets = - be32_to_cpu(chwall_buf->chwall_max_conflictsets); - chwall_buf->chwall_ssid_offset = be32_to_cpu(chwall_buf->chwall_ssid_offset); - chwall_buf->chwall_conflict_sets_offset = - be32_to_cpu(chwall_buf->chwall_conflict_sets_offset); - chwall_buf->chwall_running_types_offset = - be32_to_cpu(chwall_buf->chwall_running_types_offset); - chwall_buf->chwall_conflict_aggregate_offset = - be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset); - - /* policy type and version checks */ - if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) || - (chwall_buf->policy_version != ACM_CHWALL_VERSION)) - return -EINVAL; - - /* 1. allocate new buffers */ - ssids = - xmalloc_array(domaintype_t, - chwall_buf->chwall_max_types * - chwall_buf->chwall_max_ssidrefs); - conflict_sets = - xmalloc_array(domaintype_t, - chwall_buf->chwall_max_conflictsets * - chwall_buf->chwall_max_types); - running_types = - xmalloc_array(domaintype_t, chwall_buf->chwall_max_types); - conflict_aggregate_set = - xmalloc_array(domaintype_t, chwall_buf->chwall_max_types); - - if ((ssids == NULL) || (conflict_sets == NULL) - || (running_types == NULL) || (conflict_aggregate_set == NULL)) - goto error_free; - - /* 2. set new policy */ - if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) * - chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > - buf_size) - goto error_free; - - arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset, - sizeof(domaintype_t), - chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs); - - if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) * - chwall_buf->chwall_max_types * - chwall_buf->chwall_max_conflictsets > buf_size) - goto error_free; - - arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset, - sizeof(domaintype_t), - chwall_buf->chwall_max_types * - chwall_buf->chwall_max_conflictsets); - - /* we also use new state buffers since max_types can change */ - memset(running_types, 0, - sizeof(domaintype_t) * chwall_buf->chwall_max_types); - memset(conflict_aggregate_set, 0, - sizeof(domaintype_t) * chwall_buf->chwall_max_types); - - /* 3. now re-calculate the state for the new policy based on running domains; - * this can fail if new policy is conflicting with running domains */ - if (chwall_init_state(chwall_buf, ssids, - conflict_sets, running_types, - conflict_aggregate_set)) - { - printk("%s: New policy conflicts with running domains. Policy load aborted.\n", - __func__); - goto error_free; /* new policy conflicts with running domains */ - } - /* 4. free old policy buffers, replace with new ones */ - chwall_bin_pol.max_types = chwall_buf->chwall_max_types; - chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs; - chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets; - xfree(chwall_bin_pol.ssidrefs); - xfree(chwall_bin_pol.conflict_aggregate_set); - xfree(chwall_bin_pol.running_types); - xfree(chwall_bin_pol.conflict_sets); - chwall_bin_pol.ssidrefs = ssids; - chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set; - chwall_bin_pol.running_types = running_types; - chwall_bin_pol.conflict_sets = conflict_sets; - return ACM_OK; - - error_free: - printk("%s: ERROR setting policy.\n", __func__); - xfree(ssids); - xfree(conflict_sets); - xfree(running_types); - xfree(conflict_aggregate_set); - return -EFAULT; -} - -static int chwall_dump_stats(u8 * buf, u16 len) -{ - /* no stats for Chinese Wall Policy */ - return 0; -} - -static int chwall_dump_ssid_types(ssidref_t ssidref, u8 * buf, u16 len) -{ - int i; - - /* fill in buffer */ - if (chwall_bin_pol.max_types > len) - return -EFAULT; - - if (ssidref >= chwall_bin_pol.max_ssidrefs) - return -EFAULT; - - /* read types for chwall ssidref */ - for (i = 0; i < chwall_bin_pol.max_types; i++) - { - if (chwall_bin_pol. - ssidrefs[ssidref * chwall_bin_pol.max_types + i]) - buf[i] = 1; - else - buf[i] = 0; - } - return chwall_bin_pol.max_types; -} - -/*************************** - * Authorization functions - ***************************/ - -/* -------- DOMAIN OPERATION HOOKS -----------*/ - -static int chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref) -{ - ssidref_t chwall_ssidref; - int i, j; - traceprintk("%s.\n", __func__); - - read_lock(&acm_bin_pol_rwlock); - chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); - if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) - { - printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", - __func__); - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_DENIED; /* catching and indicating config error */ - } - if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) - { - printk("%s: ERROR chwall_ssidref > max(%x).\n", - __func__, chwall_bin_pol.max_ssidrefs - 1); - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_DENIED; - } - /* A: chinese wall check for conflicts */ - for (i = 0; i < chwall_bin_pol.max_types; i++) - if (chwall_bin_pol.conflict_aggregate_set[i] && - chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + i]) - { - printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i); - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_DENIED; - } - - /* B: chinese wall conflict set adjustment (so that other - * other domains simultaneously created are evaluated against this new set)*/ - for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) - { - int common = 0; - /* check if conflict_set_i and ssidref have common types */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - { - common = 1; - break; - } - if (common == 0) - continue; /* try next conflict set */ - /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && !chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - chwall_bin_pol.conflict_aggregate_set[j]++; - } - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_PERMITTED; -} - -static void chwall_post_domain_create(domid_t domid, ssidref_t ssidref) -{ - int i, j; - ssidref_t chwall_ssidref; - traceprintk("%s.\n", __func__); - - read_lock(&acm_bin_pol_rwlock); - chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); - /* adjust types ref-count for running domains */ - for (i = 0; i < chwall_bin_pol.max_types; i++) - chwall_bin_pol.running_types[i] += - chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + i]; - if (domid) - { - read_unlock(&acm_bin_pol_rwlock); - return; - } - /* Xen does not call pre-create hook for DOM0; - * to consider type conflicts of any domain with DOM0, we need - * to adjust the conflict_aggregate for DOM0 here the same way it - * is done for non-DOM0 domains in the pre-hook */ - printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n", - __func__, ssidref, chwall_ssidref); - - /* chinese wall conflict set adjustment (so that other - * other domains simultaneously created are evaluated against this new set)*/ - for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) - { - int common = 0; - /* check if conflict_set_i and ssidref have common types */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - { - common = 1; - break; - } - if (common == 0) - continue; /* try next conflict set */ - /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && !chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - chwall_bin_pol.conflict_aggregate_set[j]++; - } - read_unlock(&acm_bin_pol_rwlock); - return; -} - -static void -chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref) -{ - int i, j; - ssidref_t chwall_ssidref; - traceprintk("%s.\n", __func__); - - read_lock(&acm_bin_pol_rwlock); - chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref); - /* roll-back: re-adjust conflicting types aggregate */ - for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) - { - int common = 0; - /* check if conflict_set_i and ssidref have common types */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - { - common = 1; - break; - } - if (common == 0) - continue; /* try next conflict set, this one does not include any type of chwall_ssidref */ - /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && !chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - chwall_bin_pol.conflict_aggregate_set[j]--; - } - read_unlock(&acm_bin_pol_rwlock); -} - - -static void chwall_post_domain_destroy(void *object_ssid, domid_t id) -{ - int i, j; - struct chwall_ssid *chwall_ssidp = GET_SSIDP(ACM_CHINESE_WALL_POLICY, - (struct acm_ssid_domain *) - object_ssid); - ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref; - - traceprintk("%s.\n", __func__); - - read_lock(&acm_bin_pol_rwlock); - /* adjust running types set */ - for (i = 0; i < chwall_bin_pol.max_types; i++) - chwall_bin_pol.running_types[i] -= - chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + i]; - - /* roll-back: re-adjust conflicting types aggregate */ - for (i = 0; i < chwall_bin_pol.max_conflictsets; i++) - { - int common = 0; - /* check if conflict_set_i and ssidref have common types */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - { - common = 1; - break; - } - if (common == 0) - continue; /* try next conflict set, this one does not include any type of chwall_ssidref */ - /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */ - for (j = 0; j < chwall_bin_pol.max_types; j++) - if (chwall_bin_pol. - conflict_sets[i * chwall_bin_pol.max_types + j] - && !chwall_bin_pol.ssidrefs[chwall_ssidref * - chwall_bin_pol.max_types + j]) - chwall_bin_pol.conflict_aggregate_set[j]--; - } - read_unlock(&acm_bin_pol_rwlock); - return; -} - -struct acm_operations acm_chinesewall_ops = { - /* policy management services */ - .init_domain_ssid = chwall_init_domain_ssid, - .free_domain_ssid = chwall_free_domain_ssid, - .dump_binary_policy = chwall_dump_policy, - .set_binary_policy = chwall_set_policy, - .dump_statistics = chwall_dump_stats, - .dump_ssid_types = chwall_dump_ssid_types, - /* domain management control hooks */ - .pre_domain_create = chwall_pre_domain_create, - .post_domain_create = chwall_post_domain_create, - .fail_domain_create = chwall_fail_domain_create, - .post_domain_destroy = chwall_post_domain_destroy, - /* event channel control hooks */ - .pre_eventchannel_unbound = NULL, - .fail_eventchannel_unbound = NULL, - .pre_eventchannel_interdomain = NULL, - .fail_eventchannel_interdomain = NULL, - /* grant table control hooks */ - .pre_grant_map_ref = NULL, - .fail_grant_map_ref = NULL, - .pre_grant_setup = NULL, - .fail_grant_setup = NULL, - /* generic domain-requested decision hooks */ - .sharing = NULL, -}; - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/acm_core.c --- a/xen/acm/acm_core.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -/**************************************************************** - * acm_core.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * Contributors: - * Stefan Berger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * sHype access control module (ACM) - * This file handles initialization of the ACM - * as well as initializing/freeing security - * identifiers for domains (it calls on active - * policy hook functions). - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* debug: - * include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE; - * define/undefine this constant to receive / suppress any - * security hook debug output of sHype - * - * include/public/acm.h defines a constant ACM_DEBUG - * define/undefine this constant to receive non-hook-related - * debug output. - */ - -/* function prototypes */ -void acm_init_chwall_policy(void); -void acm_init_ste_policy(void); - -extern struct acm_operations acm_chinesewall_ops, - acm_simple_type_enforcement_ops, acm_null_ops; - -/* global ACM policy (now dynamically determined at boot time) */ -u16 acm_active_security_policy = ACM_POLICY_UNDEFINED; - -/* global ops structs called by the hooks */ -struct acm_operations *acm_primary_ops = NULL; -/* called in hook if-and-only-if primary succeeds */ -struct acm_operations *acm_secondary_ops = NULL; - -/* acm global binary policy (points to 'local' primary and secondary policies */ -struct acm_binary_policy acm_bin_pol; -/* acm binary policy lock */ -DEFINE_RWLOCK(acm_bin_pol_rwlock); - -int -acm_set_policy_reference(u8 *buf, u32 buf_size) -{ - struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf; - acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len)); - - if (!acm_bin_pol.policy_reference_name) - return -ENOMEM; - - strlcpy(acm_bin_pol.policy_reference_name, - (char *)(buf + sizeof(struct acm_policy_reference_buffer)), - be32_to_cpu(pr->len)); - printk("%s: Activating policy %s\n", __func__, - acm_bin_pol.policy_reference_name); - return 0; -} - -int -acm_dump_policy_reference(u8 *buf, u32 buf_size) -{ - struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf; - int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1; - - ret = (ret + 7) & ~7; - if (buf_size < ret) - return -EINVAL; - - memset(buf, 0, ret); - pr_buf->len = cpu_to_be32(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */ - strlcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)), - acm_bin_pol.policy_reference_name, - be32_to_cpu(pr_buf->len)); - return ret; -} - -int -acm_init_binary_policy(u32 policy_code) -{ - int ret = ACM_OK; - - acm_bin_pol.primary_policy_code = (policy_code & 0x0f); - acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f; - - write_lock(&acm_bin_pol_rwlock); - - /* set primary policy component */ - switch ((policy_code) & 0x0f) - { - - case ACM_CHINESE_WALL_POLICY: - acm_init_chwall_policy(); - acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY; - acm_primary_ops = &acm_chinesewall_ops; - break; - - case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: - acm_init_ste_policy(); - acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY; - acm_primary_ops = &acm_simple_type_enforcement_ops; - break; - - case ACM_NULL_POLICY: - acm_bin_pol.primary_policy_code = ACM_NULL_POLICY; - acm_primary_ops = &acm_null_ops; - break; - - default: - /* Unknown policy not allowed primary */ - ret = -EINVAL; - goto out; - } - - /* secondary policy component part */ - switch ((policy_code) >> 4) - { - - case ACM_NULL_POLICY: - acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY; - acm_secondary_ops = &acm_null_ops; - break; - - case ACM_CHINESE_WALL_POLICY: - if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY) - { /* not a valid combination */ - ret = -EINVAL; - goto out; - } - acm_init_chwall_policy(); - acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY; - acm_secondary_ops = &acm_chinesewall_ops; - break; - - case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY: - if (acm_bin_pol.primary_policy_code == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) - { /* not a valid combination */ - ret = -EINVAL; - goto out; - } - acm_init_ste_policy(); - acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY; - acm_secondary_ops = &acm_simple_type_enforcement_ops; - break; - - default: - ret = -EINVAL; - goto out; - } - - out: - write_unlock(&acm_bin_pol_rwlock); - return ret; -} - -int -acm_is_policy(char *buf, unsigned long len) -{ - struct acm_policy_buffer *pol; - - if (buf == NULL || len < sizeof(struct acm_policy_buffer)) - return 0; - - pol = (struct acm_policy_buffer *)buf; - return be32_to_cpu(pol->magic) == ACM_MAGIC; -} - - -static int -acm_setup(char *policy_start, - unsigned long policy_len) -{ - int rc = ACM_OK; - struct acm_policy_buffer *pol; - - if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer)) - return rc; - - pol = (struct acm_policy_buffer *)policy_start; - if (be32_to_cpu(pol->magic) != ACM_MAGIC) - return rc; - - rc = do_acm_set_policy((void *)policy_start, (u32)policy_len); - if (rc == ACM_OK) - { - printkd("Policy len 0x%lx, start at %p.\n",policy_len,policy_start); - } - else - { - printk("Invalid policy.\n"); - /* load default policy later */ - acm_active_security_policy = ACM_POLICY_UNDEFINED; - } - return rc; -} - - -int -acm_init(char *policy_start, - unsigned long policy_len) -{ - int ret = ACM_OK; - - /* first try to load the boot policy (uses its own locks) */ - acm_setup(policy_start, policy_len); - - if (acm_active_security_policy != ACM_POLICY_UNDEFINED) - { - printk("%s: Enforcing %s boot policy.\n", __func__, - ACM_POLICY_NAME(acm_active_security_policy)); - goto out; - } - /* else continue with the minimal hardcoded default startup policy */ - printk("%s: Loading default policy (%s).\n", - __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY)); - - if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) { - ret = -EINVAL; - goto out; - } - acm_active_security_policy = ACM_DEFAULT_SECURITY_POLICY; - if (acm_active_security_policy != ACM_NULL_POLICY) - acm_bin_pol.policy_reference_name = "DEFAULT"; - else - acm_bin_pol.policy_reference_name = "NULL"; - - out: - if (ret != ACM_OK) - { - printk("%s: Error initializing policies.\n", __func__); - /* here one could imagine a clean panic */ - return -EINVAL; - } - return ret; -} - -int -acm_init_domain_ssid(domid_t id, ssidref_t ssidref) -{ - struct acm_ssid_domain *ssid; - struct domain *subj = rcu_lock_domain_by_id(id); - int ret1, ret2; - - if (subj == NULL) - { - printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id); - return ACM_NULL_POINTER_ERROR; - } - if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL) - { - rcu_unlock_domain(subj); - return ACM_INIT_SSID_ERROR; - } - - ssid->datatype = ACM_DATATYPE_domain; - ssid->subject = subj; - ssid->domainid = subj->domain_id; - ssid->primary_ssid = NULL; - ssid->secondary_ssid = NULL; - - if (acm_active_security_policy != ACM_NULL_POLICY) - ssid->ssidref = ssidref; - else - ssid->ssidref = ACM_DEFAULT_SSID; - - subj->ssid = ssid; - /* now fill in primary and secondary parts; we only get here through hooks */ - if (acm_primary_ops->init_domain_ssid != NULL) - ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref); - else - ret1 = ACM_OK; - - if (acm_secondary_ops->init_domain_ssid != NULL) - ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref); - else - ret2 = ACM_OK; - - if ((ret1 != ACM_OK) || (ret2 != ACM_OK)) - { - printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n", - __func__, subj->domain_id); - acm_free_domain_ssid(ssid); - rcu_unlock_domain(subj); - return ACM_INIT_SSID_ERROR; - } - printkd("%s: assigned domain %x the ssidref=%x.\n", - __func__, id, ssid->ssidref); - rcu_unlock_domain(subj); - return ACM_OK; -} - - -void -acm_free_domain_ssid(struct acm_ssid_domain *ssid) -{ - /* domain is already gone, just ssid is left */ - if (ssid == NULL) - return; - - ssid->subject = NULL; - if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */ - acm_primary_ops->free_domain_ssid(ssid->primary_ssid); - ssid->primary_ssid = NULL; - if (acm_secondary_ops->free_domain_ssid != NULL) - acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid); - ssid->secondary_ssid = NULL; - xfree(ssid); - printkd("%s: Freed individual domain ssid (domain=%02x).\n", - __func__, id); -} - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/acm_null_hooks.c --- a/xen/acm/acm_null_hooks.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/**************************************************************** - * acm_null_hooks.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - */ - -#include - -static int -null_init_domain_ssid(void **ssid, ssidref_t ssidref) -{ - return ACM_OK; -} - -static void -null_free_domain_ssid(void *ssid) -{ - return; -} - -static int -null_dump_binary_policy(u8 *buf, u32 buf_size) -{ - return 0; -} - -static int -null_set_binary_policy(u8 *buf, u32 buf_size) -{ - return ACM_OK; -} - -static int -null_dump_stats(u8 *buf, u16 buf_size) -{ - /* no stats for NULL policy */ - return 0; -} - -static int -null_dump_ssid_types(ssidref_t ssidref, u8 *buffer, u16 buf_size) -{ - /* no types */ - return 0; -} - - -/* now define the hook structure similarly to LSM */ -struct acm_operations acm_null_ops = { - .init_domain_ssid = null_init_domain_ssid, - .free_domain_ssid = null_free_domain_ssid, - .dump_binary_policy = null_dump_binary_policy, - .set_binary_policy = null_set_binary_policy, - .dump_statistics = null_dump_stats, - .dump_ssid_types = null_dump_ssid_types, - /* domain management control hooks */ - .pre_domain_create = NULL, - .post_domain_create = NULL, - .fail_domain_create = NULL, - .post_domain_destroy = NULL, - /* event channel control hooks */ - .pre_eventchannel_unbound = NULL, - .fail_eventchannel_unbound = NULL, - .pre_eventchannel_interdomain = NULL, - .fail_eventchannel_interdomain = NULL, - /* grant table control hooks */ - .pre_grant_map_ref = NULL, - .fail_grant_map_ref = NULL, - .pre_grant_setup = NULL, - .fail_grant_setup = NULL -}; - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/acm_policy.c --- a/xen/acm/acm_policy.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,325 +0,0 @@ -/**************************************************************** - * acm_policy.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * Contributors: - * Stefan Berger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * sHype access control policy management for Xen. - * This interface allows policy tools in authorized - * domains to interact with the Xen access control module - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int -acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) -{ - u8 *policy_buffer = NULL; - int ret = -EFAULT; - - if (buf_size < sizeof(struct acm_policy_buffer)) - return -EFAULT; - - /* copy buffer from guest domain */ - if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL) - return -ENOMEM; - - if (copy_from_guest(policy_buffer, buf, buf_size)) - { - printk("%s: Error copying!\n",__func__); - goto error_free; - } - ret = do_acm_set_policy(policy_buffer, buf_size); - - error_free: - xfree(policy_buffer); - return ret; -} - - -int -do_acm_set_policy(void *buf, u32 buf_size) -{ - struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf; - /* some sanity checking */ - if ((be32_to_cpu(pol->magic) != ACM_MAGIC) || - (buf_size != be32_to_cpu(pol->len)) || - (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION)) - { - printk("%s: ERROR in Magic, Version, or buf size.\n", __func__); - goto error_free; - } - - if (acm_active_security_policy == ACM_POLICY_UNDEFINED) { - /* setup the policy with the boot policy */ - if (acm_init_binary_policy((be32_to_cpu(pol->secondary_policy_code) << 4) | - be32_to_cpu(pol->primary_policy_code))) { - goto error_free; - } - acm_active_security_policy = - (acm_bin_pol.secondary_policy_code << 4) | acm_bin_pol.primary_policy_code; - } - - /* once acm_active_security_policy is set, it cannot be changed */ - if ((be32_to_cpu(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) || - (be32_to_cpu(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code)) - { - printkd("%s: Wrong policy type in boot policy!\n", __func__); - goto error_free; - } - - /* get bin_policy lock and rewrite policy (release old one) */ - write_lock(&acm_bin_pol_rwlock); - - /* set label reference name */ - if (acm_set_policy_reference(buf + be32_to_cpu(pol->policy_reference_offset), - be32_to_cpu(pol->primary_buffer_offset) - - be32_to_cpu(pol->policy_reference_offset))) - goto error_lock_free; - - /* set primary policy data */ - if (acm_primary_ops->set_binary_policy(buf + be32_to_cpu(pol->primary_buffer_offset), - be32_to_cpu(pol->secondary_buffer_offset) - - be32_to_cpu(pol->primary_buffer_offset))) - goto error_lock_free; - - /* set secondary policy data */ - if (acm_secondary_ops->set_binary_policy(buf + be32_to_cpu(pol->secondary_buffer_offset), - be32_to_cpu(pol->len) - - be32_to_cpu(pol->secondary_buffer_offset))) - goto error_lock_free; - - write_unlock(&acm_bin_pol_rwlock); - return ACM_OK; - - error_lock_free: - write_unlock(&acm_bin_pol_rwlock); - error_free: - printk("%s: Error setting policy.\n", __func__); - return -EFAULT; -} - -int -acm_get_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size) -{ - u8 *policy_buffer; - int ret; - struct acm_policy_buffer *bin_pol; - - if (buf_size < sizeof(struct acm_policy_buffer)) - return -EFAULT; - - if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL) - return -ENOMEM; - - read_lock(&acm_bin_pol_rwlock); - - bin_pol = (struct acm_policy_buffer *)policy_buffer; - bin_pol->magic = cpu_to_be32(ACM_MAGIC); - bin_pol->primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); - bin_pol->secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); - - bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer)); - bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); - bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); - bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); - - ret = acm_dump_policy_reference(policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset), - buf_size - be32_to_cpu(bin_pol->policy_reference_offset)); - if (ret < 0) - goto error_free_unlock; - - bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); - bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); - - ret = acm_primary_ops->dump_binary_policy (policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset), - buf_size - be32_to_cpu(bin_pol->primary_buffer_offset)); - if (ret < 0) - goto error_free_unlock; - - bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); - bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len)); - - ret = acm_secondary_ops->dump_binary_policy(policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset), - buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset)); - if (ret < 0) - goto error_free_unlock; - - bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret); - if (copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len))) - goto error_free_unlock; - - read_unlock(&acm_bin_pol_rwlock); - xfree(policy_buffer); - return ACM_OK; - - error_free_unlock: - read_unlock(&acm_bin_pol_rwlock); - printk("%s: Error getting policy.\n", __func__); - xfree(policy_buffer); - return -EFAULT; -} - -int -acm_dump_statistics(XEN_GUEST_HANDLE(void) buf, u16 buf_size) -{ - /* send stats to user space */ - u8 *stats_buffer; - int len1, len2; - struct acm_stats_buffer acm_stats; - - if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL) - return -ENOMEM; - - read_lock(&acm_bin_pol_rwlock); - - len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer), - buf_size - sizeof(struct acm_stats_buffer)); - if (len1 < 0) - goto error_lock_free; - - len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1, - buf_size - sizeof(struct acm_stats_buffer) - len1); - if (len2 < 0) - goto error_lock_free; - - acm_stats.magic = cpu_to_be32(ACM_MAGIC); - acm_stats.primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code); - acm_stats.secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code); - acm_stats.primary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer)); - acm_stats.secondary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1); - acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2); - - memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer)); - - if (copy_to_guest(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2)) - goto error_lock_free; - - read_unlock(&acm_bin_pol_rwlock); - xfree(stats_buffer); - return ACM_OK; - - error_lock_free: - read_unlock(&acm_bin_pol_rwlock); - xfree(stats_buffer); - return -EFAULT; -} - - -int -acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE(void) buf, u16 buf_size) -{ - /* send stats to user space */ - u8 *ssid_buffer; - int ret; - struct acm_ssid_buffer *acm_ssid; - if (buf_size < sizeof(struct acm_ssid_buffer)) - return -EFAULT; - - if ((ssid_buffer = xmalloc_array(u8, buf_size)) == NULL) - return -ENOMEM; - - read_lock(&acm_bin_pol_rwlock); - - acm_ssid = (struct acm_ssid_buffer *)ssid_buffer; - acm_ssid->len = sizeof(struct acm_ssid_buffer); - acm_ssid->ssidref = ssidref; - acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code; - acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code; - - acm_ssid->policy_reference_offset = acm_ssid->len; - ret = acm_dump_policy_reference(ssid_buffer + acm_ssid->policy_reference_offset, - buf_size - acm_ssid->policy_reference_offset); - if (ret < 0) - goto error_free_unlock; - - acm_ssid->len += ret; - acm_ssid->primary_types_offset = acm_ssid->len; - - /* ret >= 0 --> ret == max_types */ - ret = acm_primary_ops->dump_ssid_types(ACM_PRIMARY(ssidref), - ssid_buffer + acm_ssid->primary_types_offset, - buf_size - acm_ssid->primary_types_offset); - if (ret < 0) - goto error_free_unlock; - - acm_ssid->len += ret; - acm_ssid->primary_max_types = ret; - acm_ssid->secondary_types_offset = acm_ssid->len; - - ret = acm_secondary_ops->dump_ssid_types(ACM_SECONDARY(ssidref), - ssid_buffer + acm_ssid->secondary_types_offset, - buf_size - acm_ssid->secondary_types_offset); - if (ret < 0) - goto error_free_unlock; - - acm_ssid->len += ret; - acm_ssid->secondary_max_types = ret; - - if (copy_to_guest(buf, ssid_buffer, acm_ssid->len)) - goto error_free_unlock; - - read_unlock(&acm_bin_pol_rwlock); - xfree(ssid_buffer); - return ACM_OK; - - error_free_unlock: - read_unlock(&acm_bin_pol_rwlock); - printk("%s: Error getting ssid.\n", __func__); - xfree(ssid_buffer); - return -ENOMEM; -} - -int -acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook) -{ - int ret = ACM_ACCESS_DENIED; - switch (hook) { - - case ACMHOOK_sharing: - /* Sharing hook restricts access in STE policy only */ - ret = acm_sharing(ssidref1, ssidref2); - break; - - default: - /* deny */ - break; - } - - printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n", - __func__, ssidref1, ssidref2, - (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED"); - - return ret; -} - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/acm/acm_simple_type_enforcement_hooks.c --- a/xen/acm/acm_simple_type_enforcement_hooks.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,701 +0,0 @@ -/**************************************************************** - * acm_simple_type_enforcement_hooks.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * Contributors: - * Stefan Berger - * support for network order binary policies - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * sHype Simple Type Enforcement for Xen - * STE allows to control which domains can setup sharing - * (eventchannels right now) with which other domains. Hooks - * are defined and called throughout Xen when domains bind to - * shared resources (setup eventchannels) and a domain is allowed - * to setup sharing with another domain if and only if both domains - * share at least on common type. - * - */ - -#include -#include -#include -#include -#include -#include - -/* local cache structures for STE policy */ -struct ste_binary_policy ste_bin_pol; - -static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) { - int i; - for(i=0; i< ste_bin_pol.max_types; i++) - if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] && - ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) { - printkd("%s: common type #%02x.\n", __func__, i); - return 1; - } - return 0; -} - -/* Helper function: return = (subj and obj share a common type) */ -static int share_common_type(struct domain *subj, struct domain *obj) -{ - ssidref_t ref_s, ref_o; - int ret; - - if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL)) - return 0; - read_lock(&acm_bin_pol_rwlock); - /* lookup the policy-local ssids */ - ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref; - ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref; - /* check whether subj and obj share a common ste type */ - ret = have_common_type(ref_s, ref_o); - read_unlock(&acm_bin_pol_rwlock); - return ret; -} - -/* - * Initializing STE policy (will be filled by policy partition - * using setpolicy command) - */ -int acm_init_ste_policy(void) -{ - /* minimal startup policy; policy write-locked already */ - ste_bin_pol.max_types = 1; - ste_bin_pol.max_ssidrefs = 2; - ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2); - memset(ste_bin_pol.ssidrefs, 0, 2); - - if (ste_bin_pol.ssidrefs == NULL) - return ACM_INIT_SSID_ERROR; - - /* initialize state so that dom0 can start up and communicate with itself */ - ste_bin_pol.ssidrefs[1] = 1; - - /* init stats */ - atomic_set(&(ste_bin_pol.ec_eval_count), 0); - atomic_set(&(ste_bin_pol.ec_denied_count), 0); - atomic_set(&(ste_bin_pol.ec_cachehit_count), 0); - atomic_set(&(ste_bin_pol.gt_eval_count), 0); - atomic_set(&(ste_bin_pol.gt_denied_count), 0); - atomic_set(&(ste_bin_pol.gt_cachehit_count), 0); - return ACM_OK; -} - - -/* ste initialization function hooks */ -static int -ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref) -{ - int i; - struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid); - traceprintk("%s.\n", __func__); - - if (ste_ssidp == NULL) - return ACM_INIT_SSID_ERROR; - - /* get policy-local ssid reference */ - ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref); - if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) || - (ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) { - printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n", - __func__, ste_ssidp->ste_ssidref); - xfree(ste_ssidp); - return ACM_INIT_SSID_ERROR; - } - /* clean ste cache */ - for (i=0; iste_cache[i].valid = ACM_STE_free; - - (*ste_ssid) = ste_ssidp; - printkd("%s: determined ste_ssidref to %x.\n", - __func__, ste_ssidp->ste_ssidref); - return ACM_OK; -} - - -static void -ste_free_domain_ssid(void *ste_ssid) -{ - traceprintk("%s.\n", __func__); - xfree(ste_ssid); - return; -} - -/* dump type enforcement cache; policy read-locked already */ -static int -ste_dump_policy(u8 *buf, u32 buf_size) { - struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf; - int ret = 0; - - if (buf_size < sizeof(struct acm_ste_policy_buffer)) - return -EINVAL; - - ste_buf->ste_max_types = cpu_to_be32(ste_bin_pol.max_types); - ste_buf->ste_max_ssidrefs = cpu_to_be32(ste_bin_pol.max_ssidrefs); - ste_buf->policy_code = cpu_to_be32(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY); - ste_buf->ste_ssid_offset = cpu_to_be32(sizeof(struct acm_ste_policy_buffer)); - ret = be32_to_cpu(ste_buf->ste_ssid_offset) + - sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types; - - ret = (ret + 7) & ~7; - - if (buf_size < ret) - return -EINVAL; - - /* now copy buffer over */ - arrcpy(buf + be32_to_cpu(ste_buf->ste_ssid_offset), - ste_bin_pol.ssidrefs, - sizeof(domaintype_t), - ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types); - - return ret; -} - -/* ste_init_state is called when a policy is changed to detect violations (return != 0). - * from a security point of view, we simulate that all running domains are re-started and - * all sharing decisions are replayed to detect violations or current sharing behavior - * (right now: event_channels, future: also grant_tables) - */ -static int -ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs) -{ - int violation = 1; - struct ste_ssid *ste_ssid, *ste_rssid; - ssidref_t ste_ssidref, ste_rssidref; - struct domain *d, *rdom; - domid_t rdomid; - struct active_grant_entry *act; - int port, i; - - rcu_read_lock(&domlist_read_lock); - /* go by domain? or directly by global? event/grant list */ - /* go through all domains and adjust policy as if this domain was started now */ - for_each_domain ( d ) - { - struct evtchn *ports; - unsigned int bucket; - ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)d->ssid); - ste_ssidref = ste_ssid->ste_ssidref; - traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n", - __func__, d->domain_id, ste_ssidref); - /* a) check for event channel conflicts */ - for (bucket = 0; bucket < NR_EVTCHN_BUCKETS; bucket++) { - spin_lock(&d->evtchn_lock); - ports = d->evtchn[bucket]; - if (ports == NULL) { - spin_unlock(&d->evtchn_lock); - break; - } - - for (port=0; port < EVTCHNS_PER_BUCKET; port++) { - if (ports[port].state == ECS_INTERDOMAIN) { - rdom = ports[port].u.interdomain.remote_dom; - rdomid = rdom->domain_id; - } else { - continue; /* port unused */ - } - - /* rdom now has remote domain */ - ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)(rdom->ssid)); - ste_rssidref = ste_rssid->ste_ssidref; - traceprintk("%s: eventch: domain %x (ssidref %x) --> " - "domain %x (rssidref %x) used (port %x).\n", - __func__, d->domain_id, ste_ssidref, - rdom->domain_id, ste_rssidref, port); - /* check whether on subj->ssid, obj->ssid share a common type*/ - if (!have_common_type(ste_ssidref, ste_rssidref)) { - printkd("%s: Policy violation in event channel domain " - "%x -> domain %x.\n", - __func__, d->domain_id, rdomid); - spin_unlock(&d->evtchn_lock); - goto out; - } - } - spin_unlock(&d->evtchn_lock); - } - - /* b) check for grant table conflicts on shared pages */ - spin_lock(&d->grant_table->lock); - for ( i = 0; i < nr_active_grant_frames(d->grant_table); i++ ) { -#define APP (PAGE_SIZE / sizeof(struct active_grant_entry)) - act = &d->grant_table->active[i/APP][i%APP]; - if ( act->pin != 0 ) { - printkd("%s: grant dom (%hu) SHARED (%d) pin (%d) " - "dom:(%hu) frame:(%lx)\n", - __func__, d->domain_id, i, act->pin, - act->domid, (unsigned long)act->frame); - rdomid = act->domid; - if ((rdom = rcu_lock_domain_by_id(rdomid)) == NULL) { - spin_unlock(&d->grant_table->lock); - printkd("%s: domain not found ERROR!\n", __func__); - goto out; - } - /* rdom now has remote domain */ - ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)(rdom->ssid)); - ste_rssidref = ste_rssid->ste_ssidref; - rcu_unlock_domain(rdom); - if (!have_common_type(ste_ssidref, ste_rssidref)) { - spin_unlock(&d->grant_table->lock); - printkd("%s: Policy violation in grant table " - "sharing domain %x -> domain %x.\n", - __func__, d->domain_id, rdomid); - goto out; - } - } - } - spin_unlock(&d->grant_table->lock); - } - violation = 0; - out: - rcu_read_unlock(&domlist_read_lock); - return violation; - /* returning "violation != 0" means that existing sharing between domains would not - * have been allowed if the new policy had been enforced before the sharing; for ste, - * this means that there are at least 2 domains that have established sharing through - * event-channels or grant-tables but these two domains don't have no longer a common - * type in their typesets referenced by their ssidrefs */ -} - -/* set new policy; policy write-locked already */ -static int -ste_set_policy(u8 *buf, u32 buf_size) -{ - struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf; - void *ssidrefsbuf; - struct ste_ssid *ste_ssid; - struct domain *d; - int i; - - if (buf_size < sizeof(struct acm_ste_policy_buffer)) - return -EINVAL; - - /* Convert endianess of policy */ - ste_buf->policy_code = be32_to_cpu(ste_buf->policy_code); - ste_buf->policy_version = be32_to_cpu(ste_buf->policy_version); - ste_buf->ste_max_types = be32_to_cpu(ste_buf->ste_max_types); - ste_buf->ste_max_ssidrefs = be32_to_cpu(ste_buf->ste_max_ssidrefs); - ste_buf->ste_ssid_offset = be32_to_cpu(ste_buf->ste_ssid_offset); - - /* policy type and version checks */ - if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) || - (ste_buf->policy_version != ACM_STE_VERSION)) - return -EINVAL; - - /* 1. create and copy-in new ssidrefs buffer */ - ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs); - if (ssidrefsbuf == NULL) { - return -ENOMEM; - } - if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size) - goto error_free; - - arrcpy(ssidrefsbuf, - buf + ste_buf->ste_ssid_offset, - sizeof(domaintype_t), - ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types); - - /* 2. now re-calculate sharing decisions based on running domains; - * this can fail if new policy is conflicting with sharing of running domains - * now: reject violating new policy; future: adjust sharing through revoking sharing */ - if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) { - printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__); - goto error_free; /* new policy conflicts with sharing of running domains */ - } - /* 3. replace old policy (activate new policy) */ - ste_bin_pol.max_types = ste_buf->ste_max_types; - ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs; - xfree(ste_bin_pol.ssidrefs); - ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf; - - /* clear all ste caches */ - rcu_read_lock(&domlist_read_lock); - for_each_domain ( d ) { - ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)(d)->ssid); - for (i=0; iste_cache[i].valid = ACM_STE_free; - } - rcu_read_unlock(&domlist_read_lock); - return ACM_OK; - - error_free: - printk("%s: ERROR setting policy.\n", __func__); - xfree(ssidrefsbuf); - return -EFAULT; -} - -static int -ste_dump_stats(u8 *buf, u16 buf_len) -{ - struct acm_ste_stats_buffer stats; - - /* now send the hook counts to user space */ - stats.ec_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_eval_count)); - stats.gt_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_eval_count)); - stats.ec_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_denied_count)); - stats.gt_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_denied_count)); - stats.ec_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_cachehit_count)); - stats.gt_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_cachehit_count)); - - if (buf_len < sizeof(struct acm_ste_stats_buffer)) - return -ENOMEM; - - memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer)); - return sizeof(struct acm_ste_stats_buffer); -} - -static int -ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len) -{ - int i; - - /* fill in buffer */ - if (ste_bin_pol.max_types > len) - return -EFAULT; - - if (ssidref >= ste_bin_pol.max_ssidrefs) - return -EFAULT; - - /* read types for chwall ssidref */ - for(i=0; i< ste_bin_pol.max_types; i++) { - if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i]) - buf[i] = 1; - else - buf[i] = 0; - } - return ste_bin_pol.max_types; -} - -/* we need to go through this before calling the hooks, - * returns 1 == cache hit */ -static int inline -check_cache(struct domain *dom, domid_t rdom) { - struct ste_ssid *ste_ssid; - int i; - - printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom); - - if (dom->ssid == NULL) - return 0; - ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)(dom->ssid)); - - for(i=0; i< ACM_TE_CACHE_SIZE; i++) { - if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) && - (ste_ssid->ste_cache[i].id == rdom)) { - printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id); - return 1; - } - } - return 0; -} - - -/* we only get here if there is NO entry yet; no duplication check! */ -static void inline -cache_result(struct domain *subj, struct domain *obj) { - struct ste_ssid *ste_ssid; - int i; - printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id); - if (subj->ssid == NULL) - return; - ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, - (struct acm_ssid_domain *)(subj)->ssid); - for(i=0; i< ACM_TE_CACHE_SIZE; i++) - if (ste_ssid->ste_cache[i].valid == ACM_STE_free) - break; - if (i< ACM_TE_CACHE_SIZE) { - ste_ssid->ste_cache[i].valid = ACM_STE_valid; - ste_ssid->ste_cache[i].id = obj->domain_id; - } else - printk ("Cache of dom %x is full!\n", subj->domain_id); -} - -/* deletes entries for domain 'id' from all caches (re-use) */ -static void inline -clean_id_from_cache(domid_t id) -{ - struct ste_ssid *ste_ssid; - int i; - struct domain *d; - struct acm_ssid_domain *ssid; - - printkd("deleting cache for dom %x.\n", id); - rcu_read_lock(&domlist_read_lock); - /* look through caches of all domains */ - for_each_domain ( d ) { - ssid = (struct acm_ssid_domain *)(d->ssid); - - if (ssid == NULL) - continue; /* hanging domain structure, no ssid any more ... */ - ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid); - if (!ste_ssid) { - printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n", - __func__); - goto out; - } - for (i=0; iste_cache[i].valid == ACM_STE_valid) && - (ste_ssid->ste_cache[i].id == id)) - ste_ssid->ste_cache[i].valid = ACM_STE_free; - } - out: - rcu_read_unlock(&domlist_read_lock); -} - -/*************************** - * Authorization functions - **************************/ -static int -ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref) -{ - /* check for ssidref in range for policy */ - ssidref_t ste_ssidref; - traceprintk("%s.\n", __func__); - - read_lock(&acm_bin_pol_rwlock); - ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref); - if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) { - printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__); - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_DENIED; /* catching and indicating config error */ - } - if (ste_ssidref >= ste_bin_pol.max_ssidrefs) { - printk("%s: ERROR ste_ssidref > max(%x).\n", - __func__, ste_bin_pol.max_ssidrefs-1); - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_DENIED; - } - read_unlock(&acm_bin_pol_rwlock); - return ACM_ACCESS_PERMITTED; -} - -static void -ste_post_domain_destroy(void *subject_ssid, domid_t id) -{ - /* clean all cache entries for destroyed domain (might be re-used) */ - clean_id_from_cache(id); -} - -/* -------- EVENTCHANNEL OPERATIONS -----------*/ -static int -ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) { - struct domain *subj, *obj; - int ret; - traceprintk("%s: dom%x-->dom%x.\n", __func__, - (id1 == DOMID_SELF) ? current->domain->domain_id : id1, - (id2 == DOMID_SELF) ? current->domain->domain_id : id2); - - if (id1 == DOMID_SELF) id1 = current->domain->domain_id; - if (id2 == DOMID_SELF) id2 = current->domain->domain_id; - - subj = rcu_lock_domain_by_id(id1); - obj = rcu_lock_domain_by_id(id2); - if ((subj == NULL) || (obj == NULL)) { - ret = ACM_ACCESS_DENIED; - goto out; - } - /* cache check late */ - if (check_cache(subj, obj->domain_id)) { - atomic_inc(&ste_bin_pol.ec_cachehit_count); - ret = ACM_ACCESS_PERMITTED; - goto out; - } - atomic_inc(&ste_bin_pol.ec_eval_count); - - if (share_common_type(subj, obj)) { - cache_result(subj, obj); - ret = ACM_ACCESS_PERMITTED; - } else { - atomic_inc(&ste_bin_pol.ec_denied_count); - ret = ACM_ACCESS_DENIED; - } - out: - if (obj != NULL) - rcu_unlock_domain(obj); - if (subj != NULL) - rcu_unlock_domain(subj); - return ret; -} - -static int -ste_pre_eventchannel_interdomain(domid_t id) -{ - struct domain *subj=NULL, *obj=NULL; - int ret; - - traceprintk("%s: dom%x-->dom%x.\n", __func__, - current->domain->domain_id, - (id == DOMID_SELF) ? current->domain->domain_id : id); - - /* following is a bit longer but ensures that we - * "put" only domains that we where "find"-ing - */ - if (id == DOMID_SELF) id = current->domain->domain_id; - - subj = current->domain; - obj = rcu_lock_domain_by_id(id); - if (obj == NULL) { - ret = ACM_ACCESS_DENIED; - goto out; - } - - /* cache check late, but evtchn is not on performance critical path */ - if (check_cache(subj, obj->domain_id)) { - atomic_inc(&ste_bin_pol.ec_cachehit_count); - ret = ACM_ACCESS_PERMITTED; - goto out; - } - - atomic_inc(&ste_bin_pol.ec_eval_count); - - if (share_common_type(subj, obj)) { - cache_result(subj, obj); - ret = ACM_ACCESS_PERMITTED; - } else { - atomic_inc(&ste_bin_pol.ec_denied_count); - ret = ACM_ACCESS_DENIED; - } - out: - if (obj != NULL) - rcu_unlock_domain(obj); - return ret; -} - -/* -------- SHARED MEMORY OPERATIONS -----------*/ - -static int -ste_pre_grant_map_ref (domid_t id) { - struct domain *obj, *subj; - int ret; - traceprintk("%s: dom%x-->dom%x.\n", __func__, - current->domain->domain_id, id); - - if (check_cache(current->domain, id)) { - atomic_inc(&ste_bin_pol.gt_cachehit_count); - return ACM_ACCESS_PERMITTED; - } - atomic_inc(&ste_bin_pol.gt_eval_count); - subj = current->domain; - obj = rcu_lock_domain_by_id(id); - - if (share_common_type(subj, obj)) { - cache_result(subj, obj); - ret = ACM_ACCESS_PERMITTED; - } else { - atomic_inc(&ste_bin_pol.gt_denied_count); - printkd("%s: ACCESS DENIED!\n", __func__); - ret = ACM_ACCESS_DENIED; - } - if (obj != NULL) - rcu_unlock_domain(obj); - return ret; -} - - -/* since setting up grant tables involves some implicit information - flow from the creating domain to the domain that is setup, we - check types in addition to the general authorization */ -static int -ste_pre_grant_setup (domid_t id) { - struct domain *obj, *subj; - int ret; - traceprintk("%s: dom%x-->dom%x.\n", __func__, - current->domain->domain_id, id); - - if (check_cache(current->domain, id)) { - atomic_inc(&ste_bin_pol.gt_cachehit_count); - return ACM_ACCESS_PERMITTED; - } - atomic_inc(&ste_bin_pol.gt_eval_count); - /* a) check authorization (eventually use specific capabilities) */ - if (!IS_PRIV(current->domain)) { - printk("%s: Grant table management authorization denied ERROR!\n", __func__); - return ACM_ACCESS_DENIED; - } - /* b) check types */ - subj = current->domain; - obj = rcu_lock_domain_by_id(id); - - if (share_common_type(subj, obj)) { - cache_result(subj, obj); - ret = ACM_ACCESS_PERMITTED; - } else { - atomic_inc(&ste_bin_pol.gt_denied_count); - ret = ACM_ACCESS_DENIED; - } - if (obj != NULL) - rcu_unlock_domain(obj); - return ret; -} - -/* -------- DOMAIN-Requested Decision hooks -----------*/ - -static int -ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) { - if (have_common_type ( - GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1), - GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2) - )) - return ACM_ACCESS_PERMITTED; - else - return ACM_ACCESS_DENIED; -} - - -/* now define the hook structure similarly to LSM */ -struct acm_operations acm_simple_type_enforcement_ops = { - - /* policy management services */ - .init_domain_ssid = ste_init_domain_ssid, - .free_domain_ssid = ste_free_domain_ssid, - .dump_binary_policy = ste_dump_policy, - .set_binary_policy = ste_set_policy, - .dump_statistics = ste_dump_stats, - .dump_ssid_types = ste_dump_ssid_types, - - /* domain management control hooks */ - .pre_domain_create = ste_pre_domain_create, - .post_domain_create = NULL, - .fail_domain_create = NULL, - .post_domain_destroy = ste_post_domain_destroy, - - /* event channel control hooks */ - .pre_eventchannel_unbound = ste_pre_eventchannel_unbound, - .fail_eventchannel_unbound = NULL, - .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain, - .fail_eventchannel_interdomain = NULL, - - /* grant table control hooks */ - .pre_grant_map_ref = ste_pre_grant_map_ref, - .fail_grant_map_ref = NULL, - .pre_grant_setup = ste_pre_grant_setup, - .fail_grant_setup = NULL, - .sharing = ste_sharing, -}; - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/acm_ops.c --- a/xen/common/acm_ops.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -/****************************************************************************** - * acm_ops.c - * - * Copyright (C) 2005 IBM Corporation - * - * Author: - * Reiner Sailer - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * Process acm command requests from guest OS. - * - */ - -#ifndef COMPAT -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef long ret_t; - -#endif /* !COMPAT */ - -#ifndef ACM_SECURITY - - -long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) -{ - return -ENOSYS; -} - - -#else - - -#ifndef COMPAT -int acm_authorize_acm_ops(struct domain *d) -{ - /* currently, policy management functions are restricted to privileged domains */ - if (!IS_PRIV(d)) - return -EPERM; - return 0; -} -#endif - - -ret_t do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) -{ - ret_t rc = -EFAULT; - - if (acm_authorize_acm_ops(current->domain)) - return -EPERM; - - switch ( cmd ) - { - - case ACMOP_setpolicy: { - struct acm_setpolicy setpolicy; - if (copy_from_guest(&setpolicy, arg, 1) != 0) - return -EFAULT; - if (setpolicy.interface_version != ACM_INTERFACE_VERSION) - return -EACCES; - - rc = acm_set_policy(setpolicy.pushcache, - setpolicy.pushcache_size); - break; - } - - case ACMOP_getpolicy: { - struct acm_getpolicy getpolicy; - if (copy_from_guest(&getpolicy, arg, 1) != 0) - return -EFAULT; - if (getpolicy.interface_version != ACM_INTERFACE_VERSION) - return -EACCES; - - rc = acm_get_policy(getpolicy.pullcache, - getpolicy.pullcache_size); - break; - } - - case ACMOP_dumpstats: { - struct acm_dumpstats dumpstats; - if (copy_from_guest(&dumpstats, arg, 1) != 0) - return -EFAULT; - if (dumpstats.interface_version != ACM_INTERFACE_VERSION) - return -EACCES; - - rc = acm_dump_statistics(dumpstats.pullcache, - dumpstats.pullcache_size); - break; - } - - case ACMOP_getssid: { - struct acm_getssid getssid; - ssidref_t ssidref; - - if (copy_from_guest(&getssid, arg, 1) != 0) - return -EFAULT; - if (getssid.interface_version != ACM_INTERFACE_VERSION) - return -EACCES; - - if (getssid.get_ssid_by == ACM_GETBY_ssidref) - ssidref = getssid.id.ssidref; - else if (getssid.get_ssid_by == ACM_GETBY_domainid) - { - struct domain *subj = rcu_lock_domain_by_id(getssid.id.domainid); - if (!subj) - { - rc = -ESRCH; /* domain not found */ - break; - } - if (subj->ssid == NULL) - { - rcu_unlock_domain(subj); - rc = -ESRCH; - break; - } - ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; - rcu_unlock_domain(subj); - } - else - { - rc = -ESRCH; - break; - } - rc = acm_get_ssid(ssidref, getssid.ssidbuf, getssid.ssidbuf_size); - break; - } - - case ACMOP_getdecision: { - struct acm_getdecision getdecision; - ssidref_t ssidref1, ssidref2; - - if (copy_from_guest(&getdecision, arg, 1) != 0) - return -EFAULT; - if (getdecision.interface_version != ACM_INTERFACE_VERSION) - return -EACCES; - - if (getdecision.get_decision_by1 == ACM_GETBY_ssidref) - ssidref1 = getdecision.id1.ssidref; - else if (getdecision.get_decision_by1 == ACM_GETBY_domainid) - { - struct domain *subj = rcu_lock_domain_by_id(getdecision.id1.domainid); - if (!subj) - { - rc = -ESRCH; /* domain not found */ - break; - } - if (subj->ssid == NULL) - { - rcu_unlock_domain(subj); - rc = -ESRCH; - break; - } - ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; - rcu_unlock_domain(subj); - } - else - { - rc = -ESRCH; - break; - } - if (getdecision.get_decision_by2 == ACM_GETBY_ssidref) - ssidref2 = getdecision.id2.ssidref; - else if (getdecision.get_decision_by2 == ACM_GETBY_domainid) - { - struct domain *subj = rcu_lock_domain_by_id(getdecision.id2.domainid); - if (!subj) - { - rc = -ESRCH; /* domain not found */ - break;; - } - if (subj->ssid == NULL) - { - rcu_unlock_domain(subj); - rc = -ESRCH; - break; - } - ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; - rcu_unlock_domain(subj); - } - else - { - rc = -ESRCH; - break; - } - rc = acm_get_decision(ssidref1, ssidref2, getdecision.hook); - - if (rc == ACM_ACCESS_PERMITTED) - { - getdecision.acm_decision = ACM_ACCESS_PERMITTED; - rc = 0; - } - else if (rc == ACM_ACCESS_DENIED) - { - getdecision.acm_decision = ACM_ACCESS_DENIED; - rc = 0; - } - else - rc = -ESRCH; - - if ( (rc == 0) && (copy_to_guest(arg, &getdecision, 1) != 0) ) - rc = -EFAULT; - break; - } - - default: - rc = -ENOSYS; - break; - } - - return rc; -} - -#endif - -#if defined(CONFIG_COMPAT) && !defined(COMPAT) -#include "compat/acm_ops.c" -#endif - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff -r f77a9736d9f4 -r 2f5b1793c585 xen/common/compat/acm_ops.c --- a/xen/common/compat/acm_ops.c Tue Mar 13 13:50:04 2007 -0400 +++ /dev/null Thu Jan 1 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/****************************************************************************** - * compat/acm_ops.c - */ - -#include -#include - -#define COMPAT -#define ret_t int - -#define do_acm_op compat_acm_op - -static inline XEN_GUEST_HANDLE(void) acm_xlat_handle(COMPAT_HANDLE(void) cmp) -{ - XEN_GUEST_HANDLE(void) nat; - - guest_from_compat_handle(nat, cmp); - return nat; -} - -#define acm_setpolicy compat_acm_setpolicy -#define acm_set_policy(h, sz) acm_set_policy(acm_xlat_handle(h), sz) - -#define acm_getpolicy compat_acm_getpolicy -#define acm_get_policy(h, sz) acm_get_policy(acm_xlat_handle(h), sz) - -#define acm_dumpstats compat_acm_dumpstats -#define acm_dump_statistics(h, sz) acm_dump_statistics(acm_xlat_handle(h), sz) - -#define acm_getssid compat_acm_getssid -#define acm_get_ssid(r, h, sz) acm_get_ssid(r, acm_xlat_handle(h), sz) - -#define xen_acm_getdecision acm_getdecision -CHECK_acm_getdecision; -#undef xen_acm_getdecision - -#include "../acm_ops.c" - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */