diff options
Diffstat (limited to 'xen/include/acm/acm_hooks.h')
-rw-r--r-- | xen/include/acm/acm_hooks.h | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h new file mode 100644 index 0000000000..534d919ff4 --- /dev/null +++ b/xen/include/acm/acm_hooks.h @@ -0,0 +1,337 @@ +/**************************************************************** + * acm_hooks.h + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer <sailer@watson.ibm.com> + * + * 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. + * + * acm header file implementing the global (policy-independent) + * sHype hooks that are called throughout Xen. + * + */ +#ifndef _ACM_HOOKS_H +#define _ACM_HOOKS_H + +#include <xen/config.h> +#include <xen/errno.h> +#include <xen/types.h> +#include <xen/lib.h> +#include <xen/delay.h> +#include <xen/sched.h> +#include <public/acm.h> +#include <acm/acm_core.h> +#include <public/dom0_ops.h> +#include <public/event_channel.h> +#include <asm/current.h> + +/* if ACM_TRACE_MODE defined, all hooks should + * print a short trace message */ +/* #define ACM_TRACE_MODE */ + +#ifdef ACM_TRACE_MODE +# define traceprintk(fmt, args...) printk(fmt,## args) +#else +# define traceprintk(fmt, args...) +#endif + +/* global variables */ +extern struct acm_operations *acm_primary_ops; +extern struct acm_operations *acm_secondary_ops; + +/********************************************************************************************** + * HOOK structure and meaning (justifies a few words about our model): + * + * General idea: every policy-controlled system operation is reflected in a + * transaction in the system's security state + * + * Keeping the security state consistent requires "atomic" transactions. + * The name of the hooks to place around policy-controlled transactions + * reflects this. If authorizations do not involve security state changes, + * then and only then POST and FAIL hooks remain empty since we don't care + * about the eventual outcome of the operation from a security viewpoint. + * + * PURPOSE of hook types: + * ====================== + * PRE-Hooks + * a) general authorization to guard a controlled system operation + * b) prepare security state change (means: fail hook must be able to "undo" this) + * + * POST-Hooks + * a) commit prepared state change + * + * FAIL-Hooks + * a) roll-back prepared security state change from PRE-Hook + * + * + * PLACEMENT of hook types: + * ======================== + * PRE-Hooks must be called: + * a) before a guarded/controlled system operation is started + * (return is ACM_ACCESS_PERMITTED or ACM_ACCESS_DENIED or error) + * --> operation must be aborted if return is != ACM_ACCESS_PERMITTED + * + * POST-Hooks must be called: + * a) after successful transaction (no return value; commit shall never fail) + * + * FAIL-Hooks must be called: + * a) if system transaction (operation) fails somewhen after calling the PRE-hook + * (obviously the POST-Hook is not called in this case) + * b) if another (secondary) policy denies access in its PRE-Hook + * (policy layering is useful but requires additional handling) + * + * + * + * Hook model from a security transaction viewpoint: + * + * start-sys-ops--> prepare ----succeed-----> commit --> sys-ops success + * (pre-hook) \ (post-hook) + * \ + * fail + * \ + * \ + * roll-back + * (fail-hook) + * \ + * sys-ops error + * + *************************************************************************************************/ + +struct acm_operations { + /* policy management functions (must always be defined!) */ + int (*init_domain_ssid) (void **ssid, ssidref_t ssidref); + void (*free_domain_ssid) (void *ssid); + int (*dump_binary_policy) (u8 *buffer, u16 buf_size); + int (*set_binary_policy) (u8 *buffer, u16 buf_size); + int (*dump_statistics) (u8 *buffer, u16 buf_size); + /* domain management control hooks (can be NULL) */ + int (*pre_domain_create) (void *subject_ssid, ssidref_t ssidref); + void (*post_domain_create) (domid_t domid, ssidref_t ssidref); + void (*fail_domain_create) (void *subject_ssid, ssidref_t ssidref); + void (*post_domain_destroy) (void *object_ssid, domid_t id); + /* event channel control hooks (can be NULL) */ + int (*pre_eventchannel_unbound) (domid_t id); + void (*fail_eventchannel_unbound) (domid_t id); + int (*pre_eventchannel_interdomain) (domid_t id1, domid_t id2); + int (*fail_eventchannel_interdomain) (domid_t id1, domid_t id2); + /* grant table control hooks (can be NULL) */ + int (*pre_grant_map_ref) (domid_t id); + void (*fail_grant_map_ref) (domid_t id); + int (*pre_grant_setup) (domid_t id); + void (*fail_grant_setup) (domid_t id); +}; + +static inline int acm_pre_domain_create (void *subject_ssid, ssidref_t 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 inline void acm_post_domain_create (domid_t domid, ssidref_t ssidref) +{ + if (acm_primary_ops->post_domain_create != NULL) + acm_primary_ops->post_domain_create (domid, ssidref); + if (acm_secondary_ops->post_domain_create != NULL) + acm_secondary_ops->post_domain_create (domid, ssidref); +} + +static inline void acm_fail_domain_create (void *subject_ssid, ssidref_t ssidref) +{ + if (acm_primary_ops->fail_domain_create != NULL) + acm_primary_ops->fail_domain_create (subject_ssid, ssidref); + if (acm_secondary_ops->fail_domain_create != NULL) + acm_secondary_ops->fail_domain_create (subject_ssid, ssidref); +} + +static inline void acm_post_domain_destroy (void *object_ssid, domid_t id) +{ + if (acm_primary_ops->post_domain_destroy != NULL) + acm_primary_ops->post_domain_destroy (object_ssid, id); + if (acm_secondary_ops->post_domain_destroy != NULL) + acm_secondary_ops->post_domain_destroy (object_ssid, id); + return; +} + +/* event channel ops */ + +static inline int acm_pre_eventchannel_unbound (domid_t id) +{ + if ((acm_primary_ops->pre_eventchannel_unbound != NULL) && + acm_primary_ops->pre_eventchannel_unbound (id)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) && + acm_secondary_ops->pre_eventchannel_unbound (id)) { + /* roll-back primary */ + if (acm_primary_ops->fail_eventchannel_unbound != NULL) + acm_primary_ops->fail_eventchannel_unbound (id); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} + +static inline int acm_pre_eventchannel_interdomain (domid_t id1, domid_t id2) +{ + if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) && + acm_primary_ops->pre_eventchannel_interdomain (id1, id2)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) && + acm_secondary_ops->pre_eventchannel_interdomain (id1, id2)) { + /* roll-back primary */ + if (acm_primary_ops->fail_eventchannel_interdomain != NULL) + acm_primary_ops->fail_eventchannel_interdomain (id1, id2); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} + +/************ Xen inline hooks ***************/ + +/* small macro to make the hooks more readable + * (eliminates hooks if NULL policy is active) + */ +#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) +static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid) +{ return 0; } +#else +static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid) +{ + int ret = -EACCES; + struct domain *d; + + switch(op->cmd) { + case DOM0_CREATEDOMAIN: + ret = acm_pre_domain_create(current->domain->ssid, op->u.createdomain.ssidref); + break; + case DOM0_DESTROYDOMAIN: + d = find_domain_by_id(op->u.destroydomain.domain); + if (d != NULL) { + *ssid = d->ssid; /* save for post destroy when d is gone */ + /* no policy-specific hook */ + put_domain(d); + ret = 0; + } + break; + default: + ret = 0; /* ok */ + } + return ret; +} +#endif + + +#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) +static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) +{ return; } +#else +static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid) +{ + switch(op->cmd) { + case DOM0_CREATEDOMAIN: + /* initialialize shared sHype security labels for new domain */ + acm_init_domain_ssid(op->u.createdomain.domain, op->u.createdomain.ssidref); + acm_post_domain_create(op->u.createdomain.domain, op->u.createdomain.ssidref); + break; + case DOM0_DESTROYDOMAIN: + acm_post_domain_destroy(ssid, op->u.destroydomain.domain); + /* free security ssid for the destroyed domain (also if running null policy */ + acm_free_domain_ssid((struct acm_ssid_domain *)ssid); + break; + } +} +#endif + + +#if (ACM_USE_SECURITY_POLICy == ACM_NULL_POLICY) +static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid) +{ return; } +#else +static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid) +{ + switch(op->cmd) { + case DOM0_CREATEDOMAIN: + acm_fail_domain_create(current->domain->ssid, op->u.createdomain.ssidref); + break; + } +} +#endif + + +#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) +static inline int acm_pre_event_channel(evtchn_op_t *op) +{ return 0; } +#else +static inline int acm_pre_event_channel(evtchn_op_t *op) +{ + int ret = -EACCES; + + switch(op->cmd) { + case EVTCHNOP_alloc_unbound: + ret = acm_pre_eventchannel_unbound(op->u.alloc_unbound.dom); + break; + case EVTCHNOP_bind_interdomain: + ret = acm_pre_eventchannel_interdomain(op->u.bind_interdomain.dom1, op->u.bind_interdomain.dom2); + break; + default: + ret = 0; /* ok */ + } + return ret; +} +#endif + +#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) +static inline int acm_pre_grant_map_ref(domid_t id) +{ return 0; } +#else +static inline int acm_pre_grant_map_ref (domid_t 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; +} +#endif + + +#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) +static inline int acm_pre_grant_setup(domid_t id) +{ return 0; } +#else +static inline int acm_pre_grant_setup (domid_t id) +{ + if ((acm_primary_ops->pre_grant_setup != NULL) && + acm_primary_ops->pre_grant_setup (id)) + return ACM_ACCESS_DENIED; + else if ((acm_secondary_ops->pre_grant_setup != NULL) && + acm_secondary_ops->pre_grant_setup (id)) { + /* roll-back primary */ + if (acm_primary_ops->fail_grant_setup != NULL) + acm_primary_ops->fail_grant_setup (id); + return ACM_ACCESS_DENIED; + } else + return ACM_ACCESS_PERMITTED; +} +#endif + + +#endif |