Changes from v2: * Added overall hooks for domctl, sysctl, and platform_hypercall so that new sub-operations are protected by IS_PRIV checks * Reorganized the IS_PRIV additions to dummy.h so they are added in the same patch that removes the IS_PRIV they are replacing * Reworked hooks in the MM hotpath to increase efficiency * Dropped some unneeded XSM hook additions due to do_domctl hook * Dropped the rcu_lock*target_domain_by_id function removal patch * Restore IS_PRIV check in PHYSDEVOP_alloc_irq_vector * Use the existing hook function structure for tmem Overall, this series should not change the behavior of Xen when XSM is not enabled; however, in some cases, the exact errors that are returned will be different because security checks have been moved below validity checks. Background: The Xen hypervisor has two basic access control function calls: IS_PRIV and the xsm_* functions. Most privileged operations currently require that both checks succeed, and many times the checks are at different locations in the code. When performing dom0 disaggregation, many of the functions normally protected with IS_PRIV are handled by domains other than dom0. This requires either making all such disaggregated domains privileged, or allowing certain operations to be performed without an IS_PRIV check. Because the privileged bit also short-circuits the IS_PRIV_FOR check, and some IS_PRIV calls do not currently have an accompanying XSM call, this series implements the second option. Once applied, most IS_PRIV checks are isolated in the newly introduced xen/include/xsm/dummy.h header. The remaining checks cover a few areas that that have some reason to remain because they involve hardware access or workarounds: 1. Overriding the IRQ and IO memory access checks (arch/x86/domctl.c). These overrides should not be needed, as dom0 should have access without needing the override. 2. Allow MAP_PIRQ_TYPE_GSI to ignore domain_pirq_to_irq negative return 3. The hack for device model framebuffers in get_page_from_l1e 4. Installing maps of non-owned pages in shadow_get_page_from_l1e 5. PCI configuration space (arch/x86/traps.c). Allowing a PV Linux domU to access the PCI configuration space is a good way to crash the system as it reconfigures PCI devices during boot, so this needs to remain to get a working system when FLASK is in permissive mode. 6. Various MSR accesses (arch/x86/traps.c) The ARM architecture is not touched at all in these patches; however, none of the changes should affect ARM. XSM hooks will need to be added for the arch-specific controls in order for FLASK to be useful on ARM, but those changes are outside the scope of this series. Miscellaneous updates to FLASK: [PATCH 01/22] xsm/flask: remove inherited class attributes [PATCH 02/22] xsm/flask: remove unneeded create_sid field [PATCH 04/22] xsm/flask: add domain relabel support [PATCH 05/22] libxl: introduce XSM relabel on build [PATCH 06/22] flask/policy: Add domain relabel example [PATCH 08/22] xsm/flask: Add checks on the domain performing the Preparatory new functions/hooks: [PATCH 03/22] xen: Add versions of rcu_lock_*_domain without IS_PRIV [PATCH 07/22] arch/x86: add distinct XSM hooks for map/unmap [PATCH 13/22] xen: lock target domain in do_domctl common code IS_PRIV Refactoring: [PATCH 09/22] xsm: Use the dummy XSM module if XSM is disabled [PATCH 10/22] xen: use XSM instead of IS_PRIV where duplicated [PATCH 11/22] xen: avoid calling rcu_lock_*target_domain when an XSM [PATCH 12/22] arch/x86: convert platform_hypercall to use XSM [PATCH 14/22] xen: convert do_domctl to use XSM [PATCH 15/22] xen: convert do_sysctl to use XSM Additional new/updated hooks: [PATCH 16/22] xsm/flask: add missing hooks [PATCH 17/22] xsm/flask: add distinct SIDs for self/target access [PATCH 18/22] arch/x86: Add missing mem_sharing XSM hooks [PATCH 19/22] arch/x86: check remote MMIO remap permissions [PATCH 20/22] arch/x86: use XSM hooks for get_pg_owner access checks [PATCH 21/22] xen: Add XSM hook for XENMEM_exchange [PATCH 22/22] tmem: add XSM hooks
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 01/22] xsm/flask: remove inherited class attributes
The ability to declare common permission blocks shared across multiple classes is not currently used in Xen. Currently, support for this feature is broken in the header generation scripts, and it is not expected that this feature will be used in the future, so remove the dead code. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/Makefile | 2 +- tools/flask/policy/policy/flask/access_vectors | 17 +---- tools/flask/policy/policy/flask/mkaccess_vector.sh | 89 ---------------------- xen/xsm/flask/avc.c | 39 ---------- xen/xsm/flask/include/av_inherit.h | 1 - xen/xsm/flask/include/avc_ss.h | 8 -- xen/xsm/flask/include/common_perm_to_string.h | 1 - xen/xsm/flask/ss/policydb.c | 46 +---------- xen/xsm/flask/ss/services.c | 54 +------------ 9 files changed, 8 insertions(+), 249 deletions(-) delete mode 100644 xen/xsm/flask/include/av_inherit.h delete mode 100644 xen/xsm/flask/include/common_perm_to_string.h diff --git a/tools/flask/policy/policy/flask/Makefile b/tools/flask/policy/policy/flask/Makefile index 970b9fe..5f57e88 100644 --- a/tools/flask/policy/policy/flask/Makefile +++ b/tools/flask/policy/policy/flask/Makefile @@ -14,7 +14,7 @@ FLASK_H_DEPEND = security_classes initial_sids AV_H_DEPEND = access_vectors FLASK_H_FILES = class_to_string.h flask.h initial_sid_to_string.h -AV_H_FILES = av_inherit.h common_perm_to_string.h av_perm_to_string.h av_permissions.h +AV_H_FILES = av_perm_to_string.h av_permissions.h ALL_H_FILES = $(FLASK_H_FILES) $(AV_H_FILES) all: $(ALL_H_FILES) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 5901911..a884312 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -1,22 +1,7 @@ # -# Define common prefixes for access vectors -# -# common common_name { permission_name ... } - -# -# Define a common prefix for file access vectors. -# - - -# # Define the access vectors. # -# class class_name [ inherits common_name ] { permission_name ... } - - -# -# Define the access vector interpretation for file-related objects. -# +# class class_name { permission_name ... } class xen { diff --git a/tools/flask/policy/policy/flask/mkaccess_vector.sh b/tools/flask/policy/policy/flask/mkaccess_vector.sh index b5da734..43a60a7 100644 --- a/tools/flask/policy/policy/flask/mkaccess_vector.sh +++ b/tools/flask/policy/policy/flask/mkaccess_vector.sh @@ -10,50 +10,21 @@ shift # output files av_permissions="av_permissions.h" -av_inherit="av_inherit.h" -common_perm_to_string="common_perm_to_string.h" av_perm_to_string="av_perm_to_string.h" cat $* | $awk " BEGIN { outfile = \"$av_permissions\" - inheritfile = \"$av_inherit\" - cpermfile = \"$common_perm_to_string\" avpermfile = \"$av_perm_to_string\" "'' nextstate = "COMMON_OR_AV"; printf("/* This file is automatically generated. Do not edit. */\n") > outfile; - printf("/* This file is automatically generated. Do not edit. */\n") > inheritfile; - printf("/* This file is automatically generated. Do not edit. */\n") > cpermfile; printf("/* This file is automatically generated. Do not edit. */\n") > avpermfile; ; } /^[ \t]*#/ { next; } -$1 == "common" { - if (nextstate != "COMMON_OR_AV") - { - printf("Parse error: Unexpected COMMON definition on line %d\n", NR); - next; - } - - if ($2 in common_defined) - { - printf("Duplicate COMMON definition for %s on line %d.\n", $2, NR); - next; - } - common_defined[$2] = 1; - - tclass = $2; - common_name = $2; - permission = 1; - - printf("TB_(common_%s_perm_to_string)\n", $2) > cpermfile; - - nextstate = "COMMON-OPENBRACKET"; - next; - } $1 == "class" { if (nextstate != "COMMON_OR_AV" && nextstate != "CLASS_OR_CLASS-OPENBRACKET") @@ -71,62 +42,11 @@ $1 == "class" { } av_defined[tclass] = 1; - inherits = ""; permission = 1; nextstate = "INHERITS_OR_CLASS-OPENBRACKET"; next; } -$1 == "inherits" { - if (nextstate != "INHERITS_OR_CLASS-OPENBRACKET") - { - printf("Parse error: Unexpected INHERITS definition on line %d\n", NR); - next; - } - - if (!($2 in common_defined)) - { - printf("COMMON %s is not defined (line %d).\n", $2, NR); - next; - } - - inherits = $2; - permission = common_base[$2]; - - for (combined in common_perms) - { - split(combined,separate, SUBSEP); - if (separate[1] == inherits) - { - inherited_perms[common_perms[combined]] = separate[2]; - } - } - - j = 1; - for (i in inherited_perms) { - ind[j] = i + 0; - j++; - } - n = asort(ind); - for (i = 1; i <= n; i++) { - perm = inherited_perms[ind[i]]; - printf("#define %s__%s", toupper(tclass), toupper(perm)) > outfile; - spaces = 40 - (length(perm) + length(tclass)); - if (spaces < 1) - spaces = 1; - for (j = 0; j < spaces; j++) - printf(" ") > outfile; - printf("0x%08xUL\n", ind[i]) > outfile; - } - printf("\n") > outfile; - for (i in ind) delete ind[i]; - for (i in inherited_perms) delete inherited_perms[i]; - - printf(" S_(SECCLASS_%s, %s, 0x%08xUL)\n", toupper(tclass), inherits, permission) > inheritfile; - - nextstate = "CLASS_OR_CLASS-OPENBRACKET"; - next; - } $1 == "{" { if (nextstate != "INHERITS_OR_CLASS-OPENBRACKET" && nextstate != "CLASS_OR_CLASS-OPENBRACKET" && @@ -177,15 +97,6 @@ $1 == "{" { av_perms[tclass,$1] = permission; - if (inherits != "") - { - if ((inherits,$1) in common_perms) - { - printf("Permission %s in %s on line %d conflicts with common permission.\n", $1, tclass, inherits, NR); - next; - } - } - printf("#define %s__%s", toupper(tclass), toupper($1)) > outfile; printf(" S_(SECCLASS_%s, %s__%s, \"%s\")\n", toupper(tclass), toupper(tclass), toupper($1), $1) > avpermfile; diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c index 44240a9..7fede00 100644 --- a/xen/xsm/flask/avc.c +++ b/xen/xsm/flask/avc.c @@ -45,28 +45,11 @@ static const char *class_to_string[] = { #undef S_ }; -#define TB_(s) static const char * s [] = { -#define TE_(s) }; -#define S_(s) s, -#include "common_perm_to_string.h" -#undef TB_ -#undef TE_ -#undef S_ - -static const struct av_inherit av_inherit[] = { -#define S_(c, i, b) { .tclass = c, .common_pts = common_##i##_perm_to_string, \ - .common_base = b }, -#include "av_inherit.h" -#undef S_ -}; - const struct selinux_class_perm selinux_class_perm = { .av_perm_to_string = av_perm_to_string, .av_pts_len = ARRAY_SIZE(av_perm_to_string), .class_to_string = class_to_string, .cts_len = ARRAY_SIZE(class_to_string), - .av_inherit = av_inherit, - .av_inherit_len = ARRAY_SIZE(av_inherit) }; #define AVC_CACHE_SLOTS 512 @@ -181,8 +164,6 @@ static void avc_printk(struct avc_dump_buf *buf, const char *fmt, ...) */ static void avc_dump_av(struct avc_dump_buf *buf, u16 tclass, u32 av) { - const char **common_pts = NULL; - u32 common_base = 0; int i, i2, perm; if ( av == 0 ) @@ -191,29 +172,9 @@ static void avc_dump_av(struct avc_dump_buf *buf, u16 tclass, u32 av) return; } - for ( i = 0; i < ARRAY_SIZE(av_inherit); i++ ) - { - if (av_inherit[i].tclass == tclass) - { - common_pts = av_inherit[i].common_pts; - common_base = av_inherit[i].common_base; - break; - } - } - avc_printk(buf, " {"); i = 0; perm = 1; - while ( perm < common_base ) - { - if (perm & av) - { - avc_printk(buf, " %s", common_pts[i]); - av &= ~perm; - } - i++; - perm <<= 1; - } while ( i < sizeof(av) * 8 ) { diff --git a/xen/xsm/flask/include/av_inherit.h b/xen/xsm/flask/include/av_inherit.h deleted file mode 100644 index 321ffe7..0000000 --- a/xen/xsm/flask/include/av_inherit.h +++ /dev/null @@ -1 +0,0 @@ -/* This file is automatically generated. Do not edit. */ diff --git a/xen/xsm/flask/include/avc_ss.h b/xen/xsm/flask/include/avc_ss.h index ea4e98c..a3d7d1e 100644 --- a/xen/xsm/flask/include/avc_ss.h +++ b/xen/xsm/flask/include/avc_ss.h @@ -16,19 +16,11 @@ struct av_perm_to_string { const char *name; }; -struct av_inherit { - const char **common_pts; - u32 common_base; - u16 tclass; -}; - struct selinux_class_perm { const struct av_perm_to_string *av_perm_to_string; u32 av_pts_len; u32 cts_len; const char **class_to_string; - const struct av_inherit *av_inherit; - u32 av_inherit_len; }; extern const struct selinux_class_perm selinux_class_perm; diff --git a/xen/xsm/flask/include/common_perm_to_string.h b/xen/xsm/flask/include/common_perm_to_string.h deleted file mode 100644 index 321ffe7..0000000 --- a/xen/xsm/flask/include/common_perm_to_string.h +++ /dev/null @@ -1 +0,0 @@ -/* This file is automatically generated. Do not edit. */ diff --git a/xen/xsm/flask/ss/policydb.c b/xen/xsm/flask/ss/policydb.c index 26097b9..fefcd59 100644 --- a/xen/xsm/flask/ss/policydb.c +++ b/xen/xsm/flask/ss/policydb.c @@ -254,14 +254,6 @@ out_free_symtab: static int common_index(void *key, void *datum, void *datap) { - struct policydb *p; - struct common_datum *comdatum; - - comdatum = datum; - p = datap; - if ( !comdatum->value || comdatum->value > p->p_commons.nprim ) - return -EINVAL; - p->p_common_val_to_name[comdatum->value - 1] = key; return 0; } @@ -382,8 +374,7 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) }; /* - * Define the common val_to_name array and the class - * val_to_name and val_to_struct arrays in a policy + * Define the class val_to_name and val_to_struct arrays in a policy * database structure. * * Caller must clean up upon failure. @@ -392,18 +383,6 @@ static int policydb_index_classes(struct policydb *p) { int rc; - p->p_common_val_to_name - xmalloc_array(char *, p->p_commons.nprim); - if ( !p->p_common_val_to_name ) - { - rc = -ENOMEM; - goto out; - } - - rc = hashtab_map(p->p_commons.table, common_index, p); - if ( rc ) - goto out; - p->class_val_to_struct xmalloc_array(struct class_datum *, p->p_classes.nprim); if ( !p->class_val_to_struct ) @@ -1200,26 +1179,9 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) if ( len2 ) { - cladatum->comkey = xmalloc_array(char, len2 + 1); - if ( !cladatum->comkey ) - { - rc = -ENOMEM; - goto bad; - } - rc = next_entry(cladatum->comkey, fp, len2); - if ( rc < 0 ) - goto bad; - cladatum->comkey[len2] = 0; - - cladatum->comdatum = hashtab_search(p->p_commons.table, - cladatum->comkey); - if ( !cladatum->comdatum ) - { - printk(KERN_ERR "Flask: unknown common %s\n", - cladatum->comkey); - rc = -EINVAL; - goto bad; - } + printk(KERN_ERR "Flask: classes with common prefixes are not supported\n"); + rc = -EINVAL; + goto bad; } for ( i = 0; i < nel; i++ ) { diff --git a/xen/xsm/flask/ss/services.c b/xen/xsm/flask/ss/services.c index 363f586..1bf3b0c 100644 --- a/xen/xsm/flask/ss/services.c +++ b/xen/xsm/flask/ss/services.c @@ -1167,10 +1167,10 @@ int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) */ static int validate_classes(struct policydb *p) { - int i, j; + int i; struct class_datum *cladatum; struct perm_datum *perdatum; - u32 nprim, tmp, common_pts_len, perm_val, pol_val; + u32 nprim, perm_val, pol_val; u16 class_val; const struct selinux_class_perm *kdefs = &selinux_class_perm; const char *def_class, *def_perm, *pol_class; @@ -1233,56 +1233,6 @@ static int validate_classes(struct policydb *p) return -EINVAL; } } - for ( i = 0; i < kdefs->av_inherit_len; i++ ) - { - class_val = kdefs->av_inherit[i].tclass; - if ( class_val > p->p_classes.nprim ) - continue; - pol_class = p->p_class_val_to_name[class_val-1]; - cladatum = hashtab_search(p->p_classes.table, pol_class); - BUG_ON( !cladatum ); - if ( !cladatum->comdatum ) - { - printk(KERN_ERR - "Flask: class %s should have an inherits clause but does not\n", - pol_class); - return -EINVAL; - } - tmp = kdefs->av_inherit[i].common_base; - common_pts_len = 0; - while ( !(tmp & 0x01) ) - { - common_pts_len++; - tmp >>= 1; - } - perms = &cladatum->comdatum->permissions; - for ( j = 0; j < common_pts_len; j++ ) - { - def_perm = kdefs->av_inherit[i].common_pts[j]; - if ( j >= perms->nprim ) - { - printk(KERN_INFO - "Flask: permission %s in class %s not defined in policy\n", - def_perm, pol_class); - return -EINVAL; - } - perdatum = hashtab_search(perms->table, def_perm); - if ( perdatum == NULL ) - { - printk(KERN_ERR - "Flask: permission %s in class %s not found in policy\n", - def_perm, pol_class); - return -EINVAL; - } - if ( perdatum->value != j + 1 ) - { - printk(KERN_ERR - "Flask: permission %s in class %s has incorrect value\n", - def_perm, pol_class); - return -EINVAL; - } - } - } return 0; } -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 02/22] xsm/flask: remove unneeded create_sid field
This field was only used to populate the ssid of dom0, which can be handled explicitly in the domain creation hook. This also removes the unnecessary permission check on the creation of dom0. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/modules/xen/xen.te | 2 -- xen/xsm/flask/hooks.c | 23 ++++++++++------------- xen/xsm/flask/include/objsec.h | 1 - 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index e175d4b..9cc5240 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -52,8 +52,6 @@ type device_t, resource_type; # Rules required to boot the hypervisor and dom0 # ################################################################################ -allow xen_t dom0_t:domain { create }; - allow dom0_t xen_t:xen { kexec readapic writeapic mtrr_read mtrr_add mtrr_del scheduler physinfo heap quirk readconsole writeconsole settime getcpuinfo microcode cpupool_op sched_op pm_op }; diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 8c853de..88fef9c 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -108,12 +108,10 @@ static int flask_domain_alloc_security(struct domain *d) memset(dsec, 0, sizeof(struct domain_security_struct)); - dsec->create_sid = SECSID_NULL; switch ( d->domain_id ) { case DOMID_IDLE: dsec->sid = SECINITSID_XEN; - dsec->create_sid = SECINITSID_DOM0; break; case DOMID_XEN: dsec->sid = SECINITSID_DOMXEN; @@ -489,25 +487,24 @@ static int flask_domain_create(struct domain *d, u32 ssidref) int rc; struct domain_security_struct *dsec1; struct domain_security_struct *dsec2; + static int dom0_created = 0; dsec1 = current->domain->ssid; + dsec2 = d->ssid; - if ( dsec1->create_sid == SECSID_NULL ) - dsec1->create_sid = ssidref; + if ( is_idle_domain(current->domain) && !dom0_created ) + { + dsec2->sid = SECINITSID_DOM0; + dom0_created = 1; + return 0; + } - rc = avc_has_perm(dsec1->sid, dsec1->create_sid, SECCLASS_DOMAIN, + rc = avc_has_perm(dsec1->sid, ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL); if ( rc ) - { - dsec1->create_sid = SECSID_NULL; return rc; - } - - dsec2 = d->ssid; - dsec2->sid = dsec1->create_sid; - dsec1->create_sid = SECSID_NULL; - dsec2->create_sid = SECSID_NULL; + dsec2->sid = ssidref; return rc; } diff --git a/xen/xsm/flask/include/objsec.h b/xen/xsm/flask/include/objsec.h index df5baee..4ff52be 100644 --- a/xen/xsm/flask/include/objsec.h +++ b/xen/xsm/flask/include/objsec.h @@ -19,7 +19,6 @@ struct domain_security_struct { u32 sid; /* current SID */ - u32 create_sid; }; struct evtchn_security_struct { -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 03/22] xen: Add versions of rcu_lock_*_domain without IS_PRIV checks
These functions will be used to avoid duplication of IS_PRIV calls that will be introduced in XSM hooks. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/common/domain.c | 21 +++++++++++++++++++++ xen/include/xen/sched.h | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index a1aa05e..52489b3 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -420,6 +420,13 @@ struct domain *rcu_lock_domain_by_id(domid_t dom) return d; } +struct domain *rcu_lock_domain_by_any_id(domid_t dom) +{ + if ( dom == DOMID_SELF ) + return rcu_lock_current_domain(); + return rcu_lock_domain_by_id(dom); +} + int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d) { if ( dom == DOMID_SELF ) @@ -454,6 +461,20 @@ int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d) return 0; } +int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d) +{ + if ( (*d = rcu_lock_domain_by_id(dom)) == NULL ) + return -ESRCH; + + if ( *d == current->domain ) + { + rcu_unlock_domain(*d); + return -EPERM; + } + + return 0; +} + int domain_kill(struct domain *d) { int rc = 0; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 53804c8..b0def4a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -447,6 +447,11 @@ struct domain *domain_create( struct domain *rcu_lock_domain_by_id(domid_t dom); /* + * As above function, but resolves DOMID_SELF to current domain + */ +struct domain *rcu_lock_domain_by_any_id(domid_t dom); + +/* * As above function, but accounts for current domain context: * - Translates target DOMID_SELF into caller''s domain id; and * - Checks that caller has permission to act on the target domain. @@ -460,6 +465,12 @@ int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d); */ int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d); +/* + * As rcu_lock_domain_by_id(), but will fail EPERM or ESRCH rather than resolve + * to local domain. + */ +int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d); + /* Finish a RCU critical region started by rcu_lock_domain_by_id(). */ static inline void rcu_unlock_domain(struct domain *d) { -- 1.7.11.4
This adds the ability to change a domain''s XSM label after creation. The new label will be used for all future access checks; however, existing event channels and memory mappings will remain valid even if their creation would be denied by the new label. With appropriate security policy and hooks in the domain builder, this can be used to create domains that the domain builder does not have access to after building. It can also be used to allow a domain to drop privileges - for example, prior to launching a user-supplied kernel loaded by a pv-grub stubdom. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/access_vectors | 7 ++++ tools/flask/policy/policy/flask/security_classes | 1 + tools/flask/policy/policy/modules/xen/xen.te | 2 +- xen/include/public/xsm/flask_op.h | 8 ++++ xen/xsm/flask/flask_op.c | 49 ++++++++++++++++++++++++ xen/xsm/flask/include/av_perm_to_string.h | 3 ++ xen/xsm/flask/include/av_permissions.h | 4 ++ xen/xsm/flask/include/class_to_string.h | 1 + xen/xsm/flask/include/flask.h | 15 ++++---- 9 files changed, 82 insertions(+), 8 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index a884312..c7e29ab 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -73,6 +73,13 @@ class domain set_virq_handler } +class domain2 +{ + relabelfrom + relabelto + relabelself +} + class hvm { sethvmc diff --git a/tools/flask/policy/policy/flask/security_classes b/tools/flask/policy/policy/flask/security_classes index 2ca35d2..ef134a7 100644 --- a/tools/flask/policy/policy/flask/security_classes +++ b/tools/flask/policy/policy/flask/security_classes @@ -9,6 +9,7 @@ class xen class domain +class domain2 class hvm class mmu class resource diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index 9cc5240..9550397 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -169,7 +169,7 @@ delegate_devices(dom0_t, domU_t) ################################################################################ # Domains must be declared using domain_type -neverallow * ~domain_type:domain create; +neverallow * ~domain_type:domain { create transition }; # Resources must be declared using resource_type neverallow * ~resource_type:resource use; diff --git a/xen/include/public/xsm/flask_op.h b/xen/include/public/xsm/flask_op.h index 1a251c9..233de81 100644 --- a/xen/include/public/xsm/flask_op.h +++ b/xen/include/public/xsm/flask_op.h @@ -142,6 +142,12 @@ struct xen_flask_peersid { uint32_t sid; }; +struct xen_flask_relabel { + /* IN */ + uint32_t domid; + uint32_t sid; +}; + struct xen_flask_op { uint32_t cmd; #define FLASK_LOAD 1 @@ -167,6 +173,7 @@ struct xen_flask_op { #define FLASK_ADD_OCONTEXT 21 #define FLASK_DEL_OCONTEXT 22 #define FLASK_GET_PEER_SID 23 +#define FLASK_RELABEL_DOMAIN 24 uint32_t interface_version; /* XEN_FLASK_INTERFACE_VERSION */ union { struct xen_flask_load load; @@ -185,6 +192,7 @@ struct xen_flask_op { /* FLASK_ADD_OCONTEXT, FLASK_DEL_OCONTEXT */ struct xen_flask_ocontext ocontext; struct xen_flask_peersid peersid; + struct xen_flask_relabel relabel; } u; }; typedef struct xen_flask_op xen_flask_op_t; diff --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c index bd4db37..9c8dfe7 100644 --- a/xen/xsm/flask/flask_op.c +++ b/xen/xsm/flask/flask_op.c @@ -573,6 +573,51 @@ static int flask_get_peer_sid(struct xen_flask_peersid *arg) return rv; } +static int flask_relabel_domain(struct xen_flask_relabel *arg) +{ + int rc; + struct domain *d; + struct domain_security_struct *csec = current->domain->ssid; + struct domain_security_struct *dsec; + struct avc_audit_data ad; + AVC_AUDIT_DATA_INIT(&ad, NONE); + + d = rcu_lock_domain_by_any_id(arg->domid); + if ( d == NULL ) + return -ESRCH; + + ad.sdom = current->domain; + ad.tdom = d; + dsec = d->ssid; + + if ( arg->domid == DOMID_SELF ) + { + rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, &ad); + if ( rc ) + goto out; + } + else + { + rc = avc_has_perm(csec->sid, dsec->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, &ad); + if ( rc ) + goto out; + + rc = avc_has_perm(csec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, &ad); + if ( rc ) + goto out; + } + + rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN, DOMAIN__TRANSITION, &ad); + if ( rc ) + goto out; + + dsec->sid = arg->sid; + + out: + rcu_unlock_domain(d); + return rc; +} + long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op) { xen_flask_op_t op; @@ -680,6 +725,10 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op) rv = flask_get_peer_sid(&op.u.peersid); break; + case FLASK_RELABEL_DOMAIN: + rv = flask_relabel_domain(&op.u.relabel); + break; + default: rv = -ENOSYS; } diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 17a1c36..e7e2058 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -61,6 +61,9 @@ S_(SECCLASS_DOMAIN, DOMAIN__SETPODTARGET, "setpodtarget") S_(SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO, "set_misc_info") S_(SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER, "set_virq_handler") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, "relabelfrom") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, "relabelto") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, "relabelself") S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc") S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc") S_(SECCLASS_HVM, HVM__SETPARAM, "setparam") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index 42eaf81..cb1c5dc 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -63,6 +63,10 @@ #define DOMAIN__SET_MISC_INFO 0x40000000UL #define DOMAIN__SET_VIRQ_HANDLER 0x80000000UL +#define DOMAIN2__RELABELFROM 0x00000001UL +#define DOMAIN2__RELABELTO 0x00000002UL +#define DOMAIN2__RELABELSELF 0x00000004UL + #define HVM__SETHVMC 0x00000001UL #define HVM__GETHVMC 0x00000002UL #define HVM__SETPARAM 0x00000004UL diff --git a/xen/xsm/flask/include/class_to_string.h b/xen/xsm/flask/include/class_to_string.h index ab55700..7716645 100644 --- a/xen/xsm/flask/include/class_to_string.h +++ b/xen/xsm/flask/include/class_to_string.h @@ -5,6 +5,7 @@ S_("null") S_("xen") S_("domain") + S_("domain2") S_("hvm") S_("mmu") S_("resource") diff --git a/xen/xsm/flask/include/flask.h b/xen/xsm/flask/include/flask.h index 6d29c5a..3bff998 100644 --- a/xen/xsm/flask/include/flask.h +++ b/xen/xsm/flask/include/flask.h @@ -7,13 +7,14 @@ */ #define SECCLASS_XEN 1 #define SECCLASS_DOMAIN 2 -#define SECCLASS_HVM 3 -#define SECCLASS_MMU 4 -#define SECCLASS_RESOURCE 5 -#define SECCLASS_SHADOW 6 -#define SECCLASS_EVENT 7 -#define SECCLASS_GRANT 8 -#define SECCLASS_SECURITY 9 +#define SECCLASS_DOMAIN2 3 +#define SECCLASS_HVM 4 +#define SECCLASS_MMU 5 +#define SECCLASS_RESOURCE 6 +#define SECCLASS_SHADOW 7 +#define SECCLASS_EVENT 8 +#define SECCLASS_GRANT 9 +#define SECCLASS_SECURITY 10 /* * Security identifier indices for initial entities -- 1.7.11.4
Allow a domain to be built under one security label and run using a different label. This can be used to prevent the domain builder or control domain from having the ability to access a guest domain''s memory via map_foreign_range except during the build process where this is required. Note: this does not provide complete protection from a malicious dom0; mappings created during the build process may persist after the relabel, and could be used to indirectly access the guest''s memory. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- tools/libxc/xc_flask.c | 10 ++++++++++ tools/libxc/xenctrl.h | 1 + tools/libxl/libxl_create.c | 4 ++++ tools/libxl/libxl_types.idl | 1 + tools/libxl/xl_cmdimpl.c | 20 +++++++++++++++++++- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tools/libxc/xc_flask.c b/tools/libxc/xc_flask.c index 80c5a2d..face1e0 100644 --- a/tools/libxc/xc_flask.c +++ b/tools/libxc/xc_flask.c @@ -422,6 +422,16 @@ int xc_flask_setavc_threshold(xc_interface *xch, int threshold) return xc_flask_op(xch, &op); } +int xc_flask_relabel_domain(xc_interface *xch, int domid, uint32_t sid) +{ + DECLARE_FLASK_OP; + op.cmd = FLASK_RELABEL_DOMAIN; + op.u.relabel.domid = domid; + op.u.relabel.sid = sid; + + return xc_flask_op(xch, &op); +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index b7741ca..0d595a0 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -2173,6 +2173,7 @@ int xc_flask_policyvers(xc_interface *xc_handle); int xc_flask_avc_hashstats(xc_interface *xc_handle, char *buf, int size); int xc_flask_getavc_threshold(xc_interface *xc_handle); int xc_flask_setavc_threshold(xc_interface *xc_handle, int threshold); +int xc_flask_relabel_domain(xc_interface *xch, int domid, uint32_t sid); struct elf_binary; void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf, diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index ef17f05..6d7bf4e 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -1126,6 +1126,10 @@ static void domcreate_complete(libxl__egc *egc, int rc) { STATE_AO_GC(dcs->ao); + libxl_domain_config *const d_config = dcs->guest_config; + + if (!rc && d_config->b_info.exec_ssidref) + rc = xc_flask_relabel_domain(CTX->xch, dcs->guest_domid, d_config->b_info.exec_ssidref); if (rc) { if (dcs->guest_domid) { diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 6d5c578..bc11591 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -262,6 +262,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("video_memkb", MemKB), ("shadow_memkb", MemKB), ("rtc_timeoffset", uint32), + ("exec_ssidref", uint32), ("localtime", libxl_defbool), ("disable_migrate", libxl_defbool), ("cpuid", libxl_cpuid_policy_list), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 2d6ab97..9b5f291 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -595,16 +595,34 @@ static void parse_config_data(const char *config_source, exit(1); } - if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) { + if (!xlu_cfg_get_string (config, "init_seclabel", &buf, 0)) { e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), &c_info->ssidref); if (e) { if (errno == ENOSYS) { + fprintf(stderr, "XSM Disabled: init_seclabel not supported\n"); + } else { + fprintf(stderr, "Invalid init_seclabel: %s\n", buf); + exit(1); + } + } + } + + if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) { + uint32_t ssidref; + e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), + &ssidref); + if (e) { + if (errno == ENOSYS) { fprintf(stderr, "XSM Disabled: seclabel not supported\n"); } else { fprintf(stderr, "Invalid seclabel: %s\n", buf); exit(1); } + } else if (c_info->ssidref) { + b_info->exec_ssidref = ssidref; + } else { + c_info->ssidref = ssidref; } } -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 06/22] flask/policy: Add domain relabel example
This adds the nomigrate_t type to the example FLASK policy which allows domains to be created that dom0 cannot access after building. Example domain configuration snippet: seclabel=''customer_1:vm_r:nomigrate_t'' init_seclabel=''customer_1:vm_r:nomigrate_t_building'' Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- docs/misc/xsm-flask.txt | 2 + tools/flask/policy/policy/modules/xen/xen.if | 56 +++++++++++++++++++++------- tools/flask/policy/policy/modules/xen/xen.te | 10 +++++ 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/docs/misc/xsm-flask.txt b/docs/misc/xsm-flask.txt index 6b0d327..0778a28 100644 --- a/docs/misc/xsm-flask.txt +++ b/docs/misc/xsm-flask.txt @@ -60,6 +60,8 @@ that can be used without dom0 disaggregation. The main types for domUs are: - domU_t is a domain that can communicate with any other domU_t - isolated_domU_t can only communicate with dom0 - prot_domU_t is a domain type whose creation can be disabled with a boolean + - nomigrate_t is a domain that must be created via the nomigrate_t_building + type, and whose memory cannot be read by dom0 once created HVM domains with stubdomain device models use two types (one per domain): - domHVM_t is an HVM domain that uses a stubdomain device model diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index 3f58909..2ad11b2 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -9,24 +9,47 @@ # Declare a type as a domain type, and allow basic domain setup define(`declare_domain'', ` type $1, domain_type`''ifelse(`$#'', `1'', `'', `,shift($@)''); + type $1_channel, event_type; + type_transition $1 domain_type:event $1_channel; allow $1 $1:grant { query setup }; allow $1 $1:mmu { adjust physmap map_read map_write stat pinpage }; allow $1 $1:hvm { getparam setparam }; '') -# create_domain(priv, target) -# Allow a domain to be created -define(`create_domain'', ` +# declare_build_label(type) +# Declare a paired _building type for the given domain type +define(`declare_build_label'', ` + type $1_building, domain_type; + type_transition $1_building domain_type:event $1_channel; + allow $1_building $1 : domain transition; +'') + +define(`create_domain_common'', ` allow $1 $2:domain { create max_vcpus setdomainmaxmem setaddrsize - getdomaininfo hypercall setvcpucontext scheduler - unpause getvcpuinfo getvcpuextstate getaddrsize - getvcpuaffinity }; + getdomaininfo hypercall setvcpucontext setextvcpucontext + scheduler getvcpuinfo getvcpuextstate getaddrsize + getvcpuaffinity setvcpuaffinity }; allow $1 $2:security check_context; allow $1 $2:shadow enable; allow $1 $2:mmu {map_read map_write adjust memorymap physmap pinpage}; allow $1 $2:grant setup; - allow $1 $2:hvm { cacheattr getparam hvmctl irqlevel pciroute setparam pcilevel trackdirtyvram }; - allow $1 $2_$1_channel:event create; + allow $1 $2:hvm { cacheattr getparam hvmctl irqlevel pciroute sethvmc setparam pcilevel trackdirtyvram }; +'') + +# create_domain(priv, target) +# Allow a domain to be created directly +define(`create_domain'', ` + create_domain_common($1, $2) + allow $1 $2_channel:event create; +'') + +# create_domain_build_label(priv, target) +# Allow a domain to be created via its domain build label +define(`create_domain_build_label'', ` + create_domain_common($1, $2_building) + allow $1 $2_channel:event create; + allow $1 $2_building:domain2 relabelfrom; + allow $1 $2:domain2 relabelto; '') # manage_domain(priv, target) @@ -37,6 +60,15 @@ define(`manage_domain'', ` setvcpuaffinity setdomainmaxmem }; '') +# migrate_domain_out(priv, target) +# Allow creation of a snapshot or migration image from a domain +# (inbound migration is the same as domain creation) +define(`migrate_domain_out'', ` + allow $1 $2:hvm { gethvmc getparam irqlevel }; + allow $1 $2:mmu { stat pageinfo map_read }; + allow $1 $2:domain { getaddrsize getvcpucontext getextvcpucontext getvcpuextstate pause destroy }; +'') + ################################################################################ # # Inter-domain communication @@ -47,8 +79,6 @@ define(`manage_domain'', ` # This allows an event channel to be created from domains with labels # <source> to <dest> and will label it <chan-label> define(`create_channel'', ` - type $3, event_type; - type_transition $1 $2:event $3; allow $1 $3:event { create send status }; allow $3 $2:event { bind }; '') @@ -56,8 +86,8 @@ define(`create_channel'', ` # domain_event_comms(dom1, dom2) # Allow two domain types to communicate using event channels define(`domain_event_comms'', ` - create_channel($1, $2, $1_$2_channel) - create_channel($2, $1, $2_$1_channel) + create_channel($1, $2, $1_channel) + create_channel($2, $1, $2_channel) '') # domain_comms(dom1, dom2) @@ -72,7 +102,7 @@ define(`domain_comms'', ` # Allow a domain types to communicate with others of its type using grants # and event channels (this includes event channels to DOMID_SELF) define(`domain_self_comms'', ` - create_channel($1, $1, $1_self_channel) + create_channel($1, $1, $1_channel) allow $1 $1:grant { map_read map_write copy unmap }; '') diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index 9550397..1162153 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -90,6 +90,7 @@ create_domain(dom0_t, isolated_domU_t) manage_domain(dom0_t, isolated_domU_t) domain_comms(dom0_t, isolated_domU_t) +# Declare a boolean that denies creation of prot_domU_t domains gen_bool(prot_doms_locked, false) declare_domain(prot_domU_t) if (!prot_doms_locked) { @@ -111,6 +112,15 @@ manage_domain(dom0_t, dm_dom_t) domain_comms(dom0_t, dm_dom_t) device_model(dm_dom_t, domHVM_t) +# nomigrate_t must be built via the nomigrate_t_building label; once built, +# dom0 cannot read its memory. +declare_domain(nomigrate_t) +declare_build_label(nomigrate_t) +create_domain_build_label(dom0_t, nomigrate_t) +manage_domain(dom0_t, nomigrate_t) +domain_comms(dom0_t, nomigrate_t) +domain_self_comms(nomigrate_t) + ############################################################################### # # Device delegation -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 07/22] arch/x86: add distinct XSM hooks for map/unmap
The xsm_iomem_permission and xsm_ioport_permission hooks are intended to be called by the domain builder, while the calls in arch/x86/domctl.c which control mapping are also performed by the device model. Because of this, they should not use the same XSM hooks. This also adds a missing XSM hook in the unbind IRQ domctl. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/arch/x86/domctl.c | 8 ++++++-- xen/arch/x86/physdev.c | 2 +- xen/include/xsm/xsm.h | 25 ++++++++++++++++++++++--- xen/xsm/dummy.c | 20 +++++++++++++++++++- xen/xsm/flask/hooks.c | 42 ++++++++++++++++++++---------------------- 5 files changed, 68 insertions(+), 29 deletions(-) diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 7a89040..9eebd3b 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -805,6 +805,10 @@ long arch_do_domctl( !irq_access_permitted(current->domain, bind->machine_irq) ) goto unbind_out; + ret = xsm_unbind_pt_irq(d, bind); + if ( ret ) + goto unbind_out; + if ( iommu_enabled ) { spin_lock(&pcidevs_lock); @@ -842,7 +846,7 @@ long arch_do_domctl( if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) break; - ret = xsm_iomem_permission(d, mfn, mfn + nr_mfns - 1, add); + ret = xsm_iomem_mapping(d, mfn, mfn + nr_mfns - 1, add); if ( ret ) { rcu_unlock_domain(d); break; @@ -904,7 +908,7 @@ long arch_do_domctl( if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) break; - ret = xsm_ioport_permission(d, fmp, fmp + np - 1, add); + ret = xsm_ioport_mapping(d, fmp, fmp + np - 1, add); if ( ret ) { rcu_unlock_domain(d); break; diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 984c813..13b85da 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -242,7 +242,7 @@ int physdev_unmap_pirq(domid_t domid, int pirq) if ( !IS_PRIV_FOR(current->domain, d) ) goto free_domain; - ret = xsm_irq_permission(d, domain_pirq_to_irq(d, pirq), 0); + ret = xsm_unmap_domain_pirq(d, domain_pirq_to_irq(d, pirq)); if ( ret ) goto free_domain; diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 593cdbd..cbbe673 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -117,8 +117,10 @@ struct xsm_operations { char *(*show_irq_sid) (int irq); int (*map_domain_pirq) (struct domain *d, int irq, void *data); + int (*unmap_domain_pirq) (struct domain *d, int irq); int (*irq_permission) (struct domain *d, int pirq, uint8_t allow); int (*iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow); + int (*iomem_mapping) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow); int (*pci_config_permission) (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access); int (*get_device_group) (uint32_t machine_bdf); @@ -176,11 +178,12 @@ struct xsm_operations { int (*add_to_physmap) (struct domain *d1, struct domain *d2); int (*sendtrigger) (struct domain *d); int (*bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); - int (*unbind_pt_irq) (struct domain *d); + int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); int (*pin_mem_cacheattr) (struct domain *d); int (*ext_vcpucontext) (struct domain *d, uint32_t cmd); int (*vcpuextstate) (struct domain *d, uint32_t cmd); int (*ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow); + int (*ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow); #endif }; @@ -495,6 +498,11 @@ static inline int xsm_map_domain_pirq (struct domain *d, int irq, void *data) return xsm_call(map_domain_pirq(d, irq, data)); } +static inline int xsm_unmap_domain_pirq (struct domain *d, int irq) +{ + return xsm_call(unmap_domain_pirq(d, irq)); +} + static inline int xsm_irq_permission (struct domain *d, int pirq, uint8_t allow) { return xsm_call(irq_permission(d, pirq, allow)); @@ -505,6 +513,11 @@ static inline int xsm_iomem_permission (struct domain *d, uint64_t s, uint64_t e return xsm_call(iomem_permission(d, s, e, allow)); } +static inline int xsm_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + return xsm_call(iomem_mapping(d, s, e, allow)); +} + static inline int xsm_pci_config_permission (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) { return xsm_call(pci_config_permission(d, machine_bdf, start, end, access)); @@ -781,9 +794,10 @@ static inline int xsm_bind_pt_irq(struct domain *d, return xsm_call(bind_pt_irq(d, bind)); } -static inline int xsm_unbind_pt_irq(struct domain *d) +static inline int xsm_unbind_pt_irq(struct domain *d, + struct xen_domctl_bind_pt_irq *bind) { - return xsm_call(unbind_pt_irq(d)); + return xsm_call(unbind_pt_irq(d, bind)); } static inline int xsm_pin_mem_cacheattr(struct domain *d) @@ -804,6 +818,11 @@ static inline int xsm_ioport_permission (struct domain *d, uint32_t s, uint32_t { return xsm_call(ioport_permission(d, s, e, allow)); } + +static inline int xsm_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + return xsm_call(ioport_mapping(d, s, e, allow)); +} #endif /* CONFIG_X86 */ extern struct xsm_operations dummy_xsm_ops; diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 4836fc0..a5dbfe7 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -395,6 +395,11 @@ static int dummy_map_domain_pirq (struct domain *d, int irq, void *data) return 0; } +static int dummy_unmap_domain_pirq (struct domain *d, int irq) +{ + return 0; +} + static int dummy_irq_permission (struct domain *d, int pirq, uint8_t allow) { return 0; @@ -405,6 +410,11 @@ static int dummy_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uin return 0; } +static int dummy_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + return 0; +} + static int dummy_pci_config_permission (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) @@ -585,7 +595,7 @@ static int dummy_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *b return 0; } -static int dummy_unbind_pt_irq (struct domain *d) +static int dummy_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) { return 0; } @@ -609,6 +619,11 @@ static int dummy_ioport_permission (struct domain *d, uint32_t s, uint32_t e, ui { return 0; } + +static int dummy_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + return 0; +} #endif struct xsm_operations dummy_xsm_ops; @@ -693,8 +708,10 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, show_irq_sid); set_to_dummy_if_null(ops, map_domain_pirq); + set_to_dummy_if_null(ops, unmap_domain_pirq); set_to_dummy_if_null(ops, irq_permission); set_to_dummy_if_null(ops, iomem_permission); + set_to_dummy_if_null(ops, iomem_mapping); set_to_dummy_if_null(ops, pci_config_permission); set_to_dummy_if_null(ops, get_device_group); @@ -757,5 +774,6 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, ext_vcpucontext); set_to_dummy_if_null(ops, vcpuextstate); set_to_dummy_if_null(ops, ioport_permission); + set_to_dummy_if_null(ops, ioport_mapping); #endif } diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 88fef9c..74c9271 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -721,43 +721,40 @@ static int flask_map_domain_pirq (struct domain *d, int irq, void *data) return rc; } -static int flask_irq_permission (struct domain *d, int irq, uint8_t access) +static int flask_unmap_domain_pirq (struct domain *d, int irq) { - u32 perm; - u32 rsid; + u32 sid; int rc = -EPERM; - struct domain_security_struct *ssec, *tsec; + struct domain_security_struct *ssec; struct avc_audit_data ad; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, - resource_to_perm(access)); - + rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__REMOVE); if ( rc ) return rc; - if ( access ) - perm = RESOURCE__ADD_IRQ; - else - perm = RESOURCE__REMOVE_IRQ; - ssec = current->domain->ssid; - tsec = d->ssid; - rc = get_irq_sid(irq, &rsid, &ad); - if ( rc ) - return rc; - - rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad); + if ( irq >= nr_irqs_gsi ) { + /* TODO support for MSI here */ + return 0; + } else { + rc = get_irq_sid(irq, &sid, &ad); + } if ( rc ) return rc; - if ( access ) - rc = avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, - RESOURCE__USE, &ad); + rc = avc_has_perm(ssec->sid, sid, SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, &ad); return rc; } +static int flask_irq_permission (struct domain *d, int pirq, uint8_t access) +{ + /* the PIRQ number is not useful; real IRQ is checked during mapping */ + return domain_has_perm(current->domain, d, SECCLASS_RESOURCE, + resource_to_perm(access)); +} + struct iomem_has_perm_data { struct domain_security_struct *ssec, *tsec; u32 perm; @@ -1413,7 +1410,7 @@ static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *b return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } -static int flask_unbind_pt_irq (struct domain *d) +static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) { return domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__REMOVE); } @@ -1533,6 +1530,7 @@ static struct xsm_operations flask_ops = { .show_irq_sid = flask_show_irq_sid, .map_domain_pirq = flask_map_domain_pirq, + .unmap_domain_pirq = flask_unmap_domain_pirq, .irq_permission = flask_irq_permission, .iomem_permission = flask_iomem_permission, .pci_config_permission = flask_pci_config_permission, -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 08/22] xsm/flask: Add checks on the domain performing the set_target operation
The existing domain__set_target check only verifies that the source and target domains can be associated. We also need to check that the privileged domain making this association is allowed to do so. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/access_vectors | 2 ++ xen/xsm/flask/hooks.c | 7 +++++++ xen/xsm/flask/include/av_perm_to_string.h | 2 ++ xen/xsm/flask/include/av_permissions.h | 2 ++ 4 files changed, 13 insertions(+) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index c7e29ab..11d02da 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -78,6 +78,8 @@ class domain2 relabelfrom relabelto relabelself + make_priv_for + set_as_target } class hvm diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 74c9271..6d4b4f0 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -577,6 +577,13 @@ static int flask_domain_settime(struct domain *d) static int flask_set_target(struct domain *d, struct domain *e) { + int rc; + rc = domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__MAKE_PRIV_FOR); + if ( rc ) + return rc; + rc = domain_has_perm(current->domain, e, SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET); + if ( rc ) + return rc; return domain_has_perm(d, e, SECCLASS_DOMAIN, DOMAIN__SET_TARGET); } diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index e7e2058..10f8e80 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -64,6 +64,8 @@ S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, "relabelfrom") S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, "relabelto") S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, "relabelself") + S_(SECCLASS_DOMAIN2, DOMAIN2__MAKE_PRIV_FOR, "make_priv_for") + S_(SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET, "set_as_target") S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc") S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc") S_(SECCLASS_HVM, HVM__SETPARAM, "setparam") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index cb1c5dc..f7cfee1 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -66,6 +66,8 @@ #define DOMAIN2__RELABELFROM 0x00000001UL #define DOMAIN2__RELABELTO 0x00000002UL #define DOMAIN2__RELABELSELF 0x00000004UL +#define DOMAIN2__MAKE_PRIV_FOR 0x00000008UL +#define DOMAIN2__SET_AS_TARGET 0x00000010UL #define HVM__SETHVMC 0x00000001UL #define HVM__GETHVMC 0x00000002UL -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 09/22] xsm: Use the dummy XSM module if XSM is disabled
This patch moves the implementation of the dummy XSM module to a header file that provides inline functions when XSM_ENABLE is not defined. This reduces duplication between the dummy module and callers when the implementation of the dummy return is not just "return 0", and also provides better compile-time checking for completeness of the XSM implementations in the dummy module. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/common/domctl.c | 2 - xen/include/xsm/dummy.h | 628 ++++++++++++++++++++++++++++++++++++++++++++++++ xen/include/xsm/xsm.h | 290 +++++++++++----------- xen/xsm/dummy.c | 617 +---------------------------------------------- xen/xsm/xsm_core.c | 2 +- 5 files changed, 772 insertions(+), 767 deletions(-) create mode 100644 xen/include/xsm/dummy.h diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 2b1f182..d99ba67 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -267,10 +267,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) return -EPERM; break; } -#ifdef XSM_ENABLE case XEN_DOMCTL_getdomaininfo: break; -#endif default: if ( !IS_PRIV(current->domain) ) return -EPERM; diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h new file mode 100644 index 0000000..61c6f13 --- /dev/null +++ b/xen/include/xsm/dummy.h @@ -0,0 +1,628 @@ +/* + * Default XSM hooks - IS_PRIV and IS_PRIV_FOR checks + * + * Author: Daniel De Graaf <dgdegra@tyhco.nsa.gov> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ + +#include <xen/sched.h> +#include <xsm/xsm.h> + +static XSM_DEFAULT(void, security_domaininfo)(struct domain *d, + struct xen_domctl_getdomaininfo *info) +{ + return; +} + +static XSM_DEFAULT(int, setvcpucontext)(struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, pausedomain) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, unpausedomain) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, resumedomain) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, domain_create)(struct domain *d, u32 ssidref) +{ + return 0; +} + +static XSM_DEFAULT(int, max_vcpus)(struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, destroydomain) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, vcpuaffinity) (int cmd, struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, scheduler) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, getdomaininfo) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getvcpucontext) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, getvcpuinfo) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, domain_settime) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, set_target) (struct domain *d, struct domain *e) +{ + return 0; +} + +static XSM_DEFAULT(int, domctl)(struct domain *d, int cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, set_virq_handler)(struct domain *d, uint32_t virq) +{ + return 0; +} + +static XSM_DEFAULT(int, tbufcontrol) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, readconsole) (uint32_t clear) +{ + return 0; +} + +static XSM_DEFAULT(int, sched_id) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, setdomainmaxmem) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, setdomainhandle) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, setdebugging) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, perfcontrol) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, debug_keys) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, getcpuinfo) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, get_pmstat) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, setpminfo) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, pm_op) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, do_mca) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, availheap) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, alloc_security_domain) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(void, free_security_domain) (struct domain *d) +{ + return; +} + +static XSM_DEFAULT(int, grant_mapref) (struct domain *d1, struct domain *d2, + uint32_t flags) +{ + return 0; +} + +static XSM_DEFAULT(int, grant_unmapref) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, grant_setup) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, grant_transfer) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, grant_copy) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, grant_query_size) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, memory_adjust_reservation) (struct domain *d1, + struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, memory_stat_reservation) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, console_io) (struct domain *d, int cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, profile) (struct domain *d, int op) +{ + return 0; +} + +static XSM_DEFAULT(int, kexec) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, schedop_shutdown) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, memory_pin_page) (struct domain *d1, struct domain *d2, + struct page_info *page) +{ + return 0; +} + +static XSM_DEFAULT(int, evtchn_unbound) (struct domain *d, struct evtchn *chn, + domid_t id2) +{ + return 0; +} + +static XSM_DEFAULT(int, evtchn_interdomain) (struct domain *d1, struct evtchn + *chan1, struct domain *d2, struct evtchn *chan2) +{ + return 0; +} + +static XSM_DEFAULT(void, evtchn_close_post) (struct evtchn *chn) +{ + return; +} + +static XSM_DEFAULT(int, evtchn_send) (struct domain *d, struct evtchn *chn) +{ + return 0; +} + +static XSM_DEFAULT(int, evtchn_status) (struct domain *d, struct evtchn *chn) +{ + return 0; +} + +static XSM_DEFAULT(int, evtchn_reset) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, alloc_security_evtchn) (struct evtchn *chn) +{ + return 0; +} + +static XSM_DEFAULT(void, free_security_evtchn) (struct evtchn *chn) +{ + return; +} + +static XSM_DEFAULT(char *, show_security_evtchn) (struct domain *d, const struct evtchn *chn) +{ + return NULL; +} + +static XSM_DEFAULT(int, get_pod_target)(struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, set_pod_target)(struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, get_device_group) (uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, test_assign_device) (uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, assign_device) (struct domain *d, uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, deassign_device) (struct domain *d, uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_plug_core) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_unplug_core) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_plug_pci) (uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_unplug_pci) (uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_setup_pci) (uint32_t machine_bdf) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_setup_gsi) (int gsi) +{ + return 0; +} + +static XSM_DEFAULT(int, resource_setup_misc) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, page_offline) (uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, lockprof) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, cpupool_op) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, sched_op) (void) +{ + return 0; +} + +static XSM_DEFAULT(long, __do_xsm_op)(XEN_GUEST_HANDLE(xsm_op_t) op) +{ + return -ENOSYS; +} + +static XSM_DEFAULT(char *, show_irq_sid) (int irq) +{ + return NULL; +} + +static XSM_DEFAULT(int, map_domain_pirq) (struct domain *d, int irq, void *data) +{ + return 0; +} + +static XSM_DEFAULT(int, unmap_domain_pirq) (struct domain *d, int irq) +{ + return 0; +} + +static XSM_DEFAULT(int, irq_permission) (struct domain *d, int pirq, uint8_t allow) +{ + return 0; +} + +static XSM_DEFAULT(int, iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + return 0; +} + +static XSM_DEFAULT(int, iomem_mapping) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + return 0; +} + +static XSM_DEFAULT(int, pci_config_permission) (struct domain *d, uint32_t machine_bdf, + uint16_t start, uint16_t end, + uint8_t access) +{ + return 0; +} + +#ifdef CONFIG_X86 +static XSM_DEFAULT(int, shadow_control) (struct domain *d, uint32_t op) +{ + return 0; +} + +static XSM_DEFAULT(int, getpageframeinfo) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, getmemlist) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, hypercall_init) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, hvmcontext) (struct domain *d, uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, address_size) (struct domain *d, uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, machine_address_size) (struct domain *d, uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, hvm_param) (struct domain *d, unsigned long op) +{ + return 0; +} + +static XSM_DEFAULT(int, hvm_set_pci_intx_level) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, hvm_set_isa_irq_level) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, hvm_set_pci_link_route) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, hvm_inject_msi) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, mem_event) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, mem_sharing) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, apic) (struct domain *d, int cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, xen_settime) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, memtype) (uint32_t access) +{ + return 0; +} + +static XSM_DEFAULT(int, microcode) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, physinfo) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, platform_quirk) (uint32_t quirk) +{ + return 0; +} + +static XSM_DEFAULT(int, firmware_info) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, efi_call) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, acpi_sleep) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, change_freq) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, getidletime) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, machine_memory_map) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, domain_memory_map) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, mmu_normal_update) (struct domain *d, struct domain *t, + struct domain *f, intpte_t fpte) +{ + return 0; +} + +static XSM_DEFAULT(int, mmu_machphys_update) (struct domain *d, struct domain *f, + unsigned long mfn) +{ + return 0; +} + +static XSM_DEFAULT(int, update_va_mapping) (struct domain *d, struct domain *f, + l1_pgentry_t pte) +{ + return 0; +} + +static XSM_DEFAULT(int, add_to_physmap) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, remove_from_physmap) (struct domain *d1, struct domain *d2) +{ + return 0; +} + +static XSM_DEFAULT(int, sendtrigger) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + return 0; +} + +static XSM_DEFAULT(int, unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + return 0; +} + +static XSM_DEFAULT(int, pin_mem_cacheattr) (struct domain *d) +{ + return 0; +} + +static XSM_DEFAULT(int, ext_vcpucontext) (struct domain *d, uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, vcpuextstate) (struct domain *d, uint32_t cmd) +{ + return 0; +} + +static XSM_DEFAULT(int, ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + return 0; +} + +static XSM_DEFAULT(int, ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + return 0; +} + +#endif diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index cbbe673..ba5a89e 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -21,12 +21,6 @@ typedef void xsm_op_t; DEFINE_XEN_GUEST_HANDLE(xsm_op_t); -#ifdef XSM_ENABLE - #define xsm_call(fn) xsm_ops->fn -#else - #define xsm_call(fn) 0 -#endif - /* policy magic number (defined by XSM_MAGIC) */ typedef u32 xsm_magic_t; #ifndef XSM_MAGIC @@ -187,645 +181,643 @@ struct xsm_operations { #endif }; -#endif - extern struct xsm_operations *xsm_ops; static inline void xsm_security_domaininfo (struct domain *d, struct xen_domctl_getdomaininfo *info) { - (void)xsm_call(security_domaininfo(d, info)); + xsm_ops->security_domaininfo(d, info); } static inline int xsm_setvcpucontext(struct domain *d) { - return xsm_call(setvcpucontext(d)); + return xsm_ops->setvcpucontext(d); } static inline int xsm_pausedomain (struct domain *d) { - return xsm_call(pausedomain(d)); + return xsm_ops->pausedomain(d); } static inline int xsm_unpausedomain (struct domain *d) { - return xsm_call(unpausedomain(d)); + return xsm_ops->unpausedomain(d); } static inline int xsm_resumedomain (struct domain *d) { - return xsm_call(resumedomain(d)); + return xsm_ops->resumedomain(d); } static inline int xsm_domain_create (struct domain *d, u32 ssidref) { - return xsm_call(domain_create(d, ssidref)); + return xsm_ops->domain_create(d, ssidref); } static inline int xsm_max_vcpus(struct domain *d) { - return xsm_call(max_vcpus(d)); + return xsm_ops->max_vcpus(d); } static inline int xsm_destroydomain (struct domain *d) { - return xsm_call(destroydomain(d)); + return xsm_ops->destroydomain(d); } static inline int xsm_vcpuaffinity (int cmd, struct domain *d) { - return xsm_call(vcpuaffinity(cmd, d)); + return xsm_ops->vcpuaffinity(cmd, d); } static inline int xsm_scheduler (struct domain *d) { - return xsm_call(scheduler(d)); + return xsm_ops->scheduler(d); } static inline int xsm_getdomaininfo (struct domain *d) { - return xsm_call(getdomaininfo(d)); + return xsm_ops->getdomaininfo(d); } static inline int xsm_getvcpucontext (struct domain *d) { - return xsm_call(getvcpucontext(d)); + return xsm_ops->getvcpucontext(d); } static inline int xsm_getvcpuinfo (struct domain *d) { - return xsm_call(getvcpuinfo(d)); + return xsm_ops->getvcpuinfo(d); } static inline int xsm_domain_settime (struct domain *d) { - return xsm_call(domain_settime(d)); + return xsm_ops->domain_settime(d); } static inline int xsm_set_target (struct domain *d, struct domain *e) { - return xsm_call(set_target(d, e)); + return xsm_ops->set_target(d, e); } static inline int xsm_domctl (struct domain *d, int cmd) { - return xsm_call(domctl(d, cmd)); + return xsm_ops->domctl(d, cmd); } static inline int xsm_set_virq_handler (struct domain *d, uint32_t virq) { - return xsm_call(set_virq_handler(d, virq)); + return xsm_ops->set_virq_handler(d, virq); } static inline int xsm_tbufcontrol (void) { - return xsm_call(tbufcontrol()); + return xsm_ops->tbufcontrol(); } static inline int xsm_readconsole (uint32_t clear) { - return xsm_call(readconsole(clear)); + return xsm_ops->readconsole(clear); } static inline int xsm_sched_id (void) { - return xsm_call(sched_id()); + return xsm_ops->sched_id(); } static inline int xsm_setdomainmaxmem (struct domain *d) { - return xsm_call(setdomainmaxmem(d)); + return xsm_ops->setdomainmaxmem(d); } static inline int xsm_setdomainhandle (struct domain *d) { - return xsm_call(setdomainhandle(d)); + return xsm_ops->setdomainhandle(d); } static inline int xsm_setdebugging (struct domain *d) { - return xsm_call(setdebugging(d)); + return xsm_ops->setdebugging(d); } static inline int xsm_perfcontrol (void) { - return xsm_call(perfcontrol()); + return xsm_ops->perfcontrol(); } static inline int xsm_debug_keys (void) { - return xsm_call(debug_keys()); + return xsm_ops->debug_keys(); } static inline int xsm_availheap (void) { - return xsm_call(availheap()); + return xsm_ops->availheap(); } static inline int xsm_getcpuinfo (void) { - return xsm_call(getcpuinfo()); + return xsm_ops->getcpuinfo(); } static inline int xsm_get_pmstat(void) { - return xsm_call(get_pmstat()); + return xsm_ops->get_pmstat(); } static inline int xsm_setpminfo(void) { - return xsm_call(setpminfo()); + return xsm_ops->setpminfo(); } static inline int xsm_pm_op(void) { - return xsm_call(pm_op()); + return xsm_ops->pm_op(); } static inline int xsm_do_mca(void) { - return xsm_call(do_mca()); + return xsm_ops->do_mca(); } static inline int xsm_evtchn_unbound (struct domain *d1, struct evtchn *chn, domid_t id2) { - return xsm_call(evtchn_unbound(d1, chn, id2)); + return xsm_ops->evtchn_unbound(d1, chn, id2); } static inline int xsm_evtchn_interdomain (struct domain *d1, struct evtchn *chan1, struct domain *d2, struct evtchn *chan2) { - return xsm_call(evtchn_interdomain(d1, chan1, d2, chan2)); + return xsm_ops->evtchn_interdomain(d1, chan1, d2, chan2); } static inline void xsm_evtchn_close_post (struct evtchn *chn) { - (void)xsm_call(evtchn_close_post(chn)); + xsm_ops->evtchn_close_post(chn); } static inline int xsm_evtchn_send (struct domain *d, struct evtchn *chn) { - return xsm_call(evtchn_send(d, chn)); + return xsm_ops->evtchn_send(d, chn); } static inline int xsm_evtchn_status (struct domain *d, struct evtchn *chn) { - return xsm_call(evtchn_status(d, chn)); + return xsm_ops->evtchn_status(d, chn); } static inline int xsm_evtchn_reset (struct domain *d1, struct domain *d2) { - return xsm_call(evtchn_reset(d1, d2)); + return xsm_ops->evtchn_reset(d1, d2); } static inline int xsm_grant_mapref (struct domain *d1, struct domain *d2, uint32_t flags) { - return xsm_call(grant_mapref(d1, d2, flags)); + return xsm_ops->grant_mapref(d1, d2, flags); } static inline int xsm_grant_unmapref (struct domain *d1, struct domain *d2) { - return xsm_call(grant_unmapref(d1, d2)); + return xsm_ops->grant_unmapref(d1, d2); } static inline int xsm_grant_setup (struct domain *d1, struct domain *d2) { - return xsm_call(grant_setup(d1, d2)); + return xsm_ops->grant_setup(d1, d2); } static inline int xsm_grant_transfer (struct domain *d1, struct domain *d2) { - return xsm_call(grant_transfer(d1, d2)); + return xsm_ops->grant_transfer(d1, d2); } static inline int xsm_grant_copy (struct domain *d1, struct domain *d2) { - return xsm_call(grant_copy(d1, d2)); + return xsm_ops->grant_copy(d1, d2); } static inline int xsm_grant_query_size (struct domain *d1, struct domain *d2) { - return xsm_call(grant_query_size(d1, d2)); + return xsm_ops->grant_query_size(d1, d2); } static inline int xsm_alloc_security_domain (struct domain *d) { - return xsm_call(alloc_security_domain(d)); + return xsm_ops->alloc_security_domain(d); } static inline void xsm_free_security_domain (struct domain *d) { - (void)xsm_call(free_security_domain(d)); + xsm_ops->free_security_domain(d); } static inline int xsm_alloc_security_evtchn (struct evtchn *chn) { - return xsm_call(alloc_security_evtchn(chn)); + return xsm_ops->alloc_security_evtchn(chn); } static inline void xsm_free_security_evtchn (struct evtchn *chn) { - (void)xsm_call(free_security_evtchn(chn)); + (void)xsm_ops->free_security_evtchn(chn); } static inline char *xsm_show_security_evtchn (struct domain *d, const struct evtchn *chn) { - return xsm_call(show_security_evtchn(d, chn)); + return xsm_ops->show_security_evtchn(d, chn); } static inline int xsm_get_pod_target (struct domain *d) { - return xsm_call(get_pod_target(d)); + return xsm_ops->get_pod_target(d); } static inline int xsm_set_pod_target (struct domain *d) { - return xsm_call(set_pod_target(d)); + return xsm_ops->set_pod_target(d); } static inline int xsm_memory_adjust_reservation (struct domain *d1, struct domain *d2) { - return xsm_call(memory_adjust_reservation(d1, d2)); + return xsm_ops->memory_adjust_reservation(d1, d2); } static inline int xsm_memory_stat_reservation (struct domain *d1, struct domain *d2) { - return xsm_call(memory_stat_reservation(d1, d2)); + return xsm_ops->memory_stat_reservation(d1, d2); } static inline int xsm_memory_pin_page(struct domain *d1, struct domain *d2, struct page_info *page) { - return xsm_call(memory_pin_page(d1, d2, page)); + return xsm_ops->memory_pin_page(d1, d2, page); } static inline int xsm_remove_from_physmap(struct domain *d1, struct domain *d2) { - return xsm_call(remove_from_physmap(d1, d2)); + return xsm_ops->remove_from_physmap(d1, d2); } static inline int xsm_console_io (struct domain *d, int cmd) { - return xsm_call(console_io(d, cmd)); + return xsm_ops->console_io(d, cmd); } static inline int xsm_profile (struct domain *d, int op) { - return xsm_call(profile(d, op)); + return xsm_ops->profile(d, op); } static inline int xsm_kexec (void) { - return xsm_call(kexec()); + return xsm_ops->kexec(); } static inline int xsm_schedop_shutdown (struct domain *d1, struct domain *d2) { - return xsm_call(schedop_shutdown(d1, d2)); + return xsm_ops->schedop_shutdown(d1, d2); } static inline char *xsm_show_irq_sid (int irq) { - return xsm_call(show_irq_sid(irq)); + return xsm_ops->show_irq_sid(irq); } static inline int xsm_map_domain_pirq (struct domain *d, int irq, void *data) { - return xsm_call(map_domain_pirq(d, irq, data)); + return xsm_ops->map_domain_pirq(d, irq, data); } static inline int xsm_unmap_domain_pirq (struct domain *d, int irq) { - return xsm_call(unmap_domain_pirq(d, irq)); + return xsm_ops->unmap_domain_pirq(d, irq); } static inline int xsm_irq_permission (struct domain *d, int pirq, uint8_t allow) { - return xsm_call(irq_permission(d, pirq, allow)); + return xsm_ops->irq_permission(d, pirq, allow); } static inline int xsm_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { - return xsm_call(iomem_permission(d, s, e, allow)); + return xsm_ops->iomem_permission(d, s, e, allow); } static inline int xsm_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { - return xsm_call(iomem_mapping(d, s, e, allow)); + return xsm_ops->iomem_mapping(d, s, e, allow); } static inline int xsm_pci_config_permission (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) { - return xsm_call(pci_config_permission(d, machine_bdf, start, end, access)); + return xsm_ops->pci_config_permission(d, machine_bdf, start, end, access); } static inline int xsm_get_device_group(uint32_t machine_bdf) { - return xsm_call(get_device_group(machine_bdf)); + return xsm_ops->get_device_group(machine_bdf); } static inline int xsm_test_assign_device(uint32_t machine_bdf) { - return xsm_call(test_assign_device(machine_bdf)); + return xsm_ops->test_assign_device(machine_bdf); } static inline int xsm_assign_device(struct domain *d, uint32_t machine_bdf) { - return xsm_call(assign_device(d, machine_bdf)); + return xsm_ops->assign_device(d, machine_bdf); } static inline int xsm_deassign_device(struct domain *d, uint32_t machine_bdf) { - return xsm_call(deassign_device(d, machine_bdf)); + return xsm_ops->deassign_device(d, machine_bdf); } static inline int xsm_resource_plug_pci (uint32_t machine_bdf) { - return xsm_call(resource_plug_pci(machine_bdf)); + return xsm_ops->resource_plug_pci(machine_bdf); } static inline int xsm_resource_unplug_pci (uint32_t machine_bdf) { - return xsm_call(resource_unplug_pci(machine_bdf)); + return xsm_ops->resource_unplug_pci(machine_bdf); } static inline int xsm_resource_plug_core (void) { - return xsm_call(resource_plug_core()); + return xsm_ops->resource_plug_core(); } static inline int xsm_resource_unplug_core (void) { - return xsm_call(resource_unplug_core()); + return xsm_ops->resource_unplug_core(); } static inline int xsm_resource_setup_pci (uint32_t machine_bdf) { - return xsm_call(resource_setup_pci(machine_bdf)); + return xsm_ops->resource_setup_pci(machine_bdf); } static inline int xsm_resource_setup_gsi (int gsi) { - return xsm_call(resource_setup_gsi(gsi)); + return xsm_ops->resource_setup_gsi(gsi); } static inline int xsm_resource_setup_misc (void) { - return xsm_call(resource_setup_misc()); + return xsm_ops->resource_setup_misc(); } static inline int xsm_page_offline(uint32_t cmd) { - return xsm_call(page_offline(cmd)); + return xsm_ops->page_offline(cmd); } static inline int xsm_lockprof(void) { - return xsm_call(lockprof()); + return xsm_ops->lockprof(); } static inline int xsm_cpupool_op(void) { - return xsm_call(cpupool_op()); + return xsm_ops->cpupool_op(); } static inline int xsm_sched_op(void) { - return xsm_call(sched_op()); + return xsm_ops->sched_op(); } -static inline long __do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) +static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { -#ifdef XSM_ENABLE return xsm_ops->__do_xsm_op(op); -#else - return -ENOSYS; -#endif -} - -#ifdef XSM_ENABLE -extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)); -extern int xsm_policy_init(unsigned long *module_map, - const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)); -extern int register_xsm(struct xsm_operations *ops); -extern int unregister_xsm(struct xsm_operations *ops); -#else -static inline int xsm_init (unsigned long *module_map, - const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)) -{ - return 0; } -#endif #ifdef CONFIG_X86 static inline int xsm_shadow_control (struct domain *d, uint32_t op) { - return xsm_call(shadow_control(d, op)); + return xsm_ops->shadow_control(d, op); } static inline int xsm_getpageframeinfo (struct domain *d) { - return xsm_call(getpageframeinfo(d)); + return xsm_ops->getpageframeinfo(d); } static inline int xsm_getmemlist (struct domain *d) { - return xsm_call(getmemlist(d)); + return xsm_ops->getmemlist(d); } static inline int xsm_hypercall_init (struct domain *d) { - return xsm_call(hypercall_init(d)); + return xsm_ops->hypercall_init(d); } static inline int xsm_hvmcontext (struct domain *d, uint32_t cmd) { - return xsm_call(hvmcontext(d, cmd)); + return xsm_ops->hvmcontext(d, cmd); } static inline int xsm_address_size (struct domain *d, uint32_t cmd) { - return xsm_call(address_size(d, cmd)); + return xsm_ops->address_size(d, cmd); } static inline int xsm_machine_address_size (struct domain *d, uint32_t cmd) { - return xsm_call(machine_address_size(d, cmd)); + return xsm_ops->machine_address_size(d, cmd); } static inline int xsm_hvm_param (struct domain *d, unsigned long op) { - return xsm_call(hvm_param(d, op)); + return xsm_ops->hvm_param(d, op); } static inline int xsm_hvm_set_pci_intx_level (struct domain *d) { - return xsm_call(hvm_set_pci_intx_level(d)); + return xsm_ops->hvm_set_pci_intx_level(d); } static inline int xsm_hvm_set_isa_irq_level (struct domain *d) { - return xsm_call(hvm_set_isa_irq_level(d)); + return xsm_ops->hvm_set_isa_irq_level(d); } static inline int xsm_hvm_set_pci_link_route (struct domain *d) { - return xsm_call(hvm_set_pci_link_route(d)); + return xsm_ops->hvm_set_pci_link_route(d); } static inline int xsm_hvm_inject_msi (struct domain *d) { - return xsm_call(hvm_inject_msi(d)); + return xsm_ops->hvm_inject_msi(d); } static inline int xsm_mem_event (struct domain *d) { - return xsm_call(mem_event(d)); + return xsm_ops->mem_event(d); } static inline int xsm_mem_sharing (struct domain *d) { - return xsm_call(mem_sharing(d)); + return xsm_ops->mem_sharing(d); } static inline int xsm_apic (struct domain *d, int cmd) { - return xsm_call(apic(d, cmd)); + return xsm_ops->apic(d, cmd); } static inline int xsm_xen_settime (void) { - return xsm_call(xen_settime()); + return xsm_ops->xen_settime(); } static inline int xsm_memtype (uint32_t access) { - return xsm_call(memtype(access)); + return xsm_ops->memtype(access); } static inline int xsm_microcode (void) { - return xsm_call(microcode()); + return xsm_ops->microcode(); } static inline int xsm_physinfo (void) { - return xsm_call(physinfo()); + return xsm_ops->physinfo(); } static inline int xsm_platform_quirk (uint32_t quirk) { - return xsm_call(platform_quirk(quirk)); + return xsm_ops->platform_quirk(quirk); } static inline int xsm_firmware_info (void) { - return xsm_call(firmware_info()); + return xsm_ops->firmware_info(); } static inline int xsm_efi_call (void) { - return xsm_call(efi_call()); + return xsm_ops->efi_call(); } static inline int xsm_acpi_sleep (void) { - return xsm_call(acpi_sleep()); + return xsm_ops->acpi_sleep(); } static inline int xsm_change_freq (void) { - return xsm_call(change_freq()); + return xsm_ops->change_freq(); } static inline int xsm_getidletime (void) { - return xsm_call(getidletime()); + return xsm_ops->getidletime(); } static inline int xsm_machine_memory_map(void) { - return xsm_call(machine_memory_map()); + return xsm_ops->machine_memory_map(); } static inline int xsm_domain_memory_map(struct domain *d) { - return xsm_call(domain_memory_map(d)); + return xsm_ops->domain_memory_map(d); } static inline int xsm_mmu_normal_update (struct domain *d, struct domain *t, struct domain *f, intpte_t fpte) { - return xsm_call(mmu_normal_update(d, t, f, fpte)); + return xsm_ops->mmu_normal_update(d, t, f, fpte); } static inline int xsm_mmu_machphys_update (struct domain *d1, struct domain *d2, unsigned long mfn) { - return xsm_call(mmu_machphys_update(d1, d2, mfn)); + return xsm_ops->mmu_machphys_update(d1, d2, mfn); } static inline int xsm_update_va_mapping(struct domain *d, struct domain *f, l1_pgentry_t pte) { - return xsm_call(update_va_mapping(d, f, pte)); + return xsm_ops->update_va_mapping(d, f, pte); } static inline int xsm_add_to_physmap(struct domain *d1, struct domain *d2) { - return xsm_call(add_to_physmap(d1, d2)); + return xsm_ops->add_to_physmap(d1, d2); } static inline int xsm_sendtrigger(struct domain *d) { - return xsm_call(sendtrigger(d)); + return xsm_ops->sendtrigger(d); } static inline int xsm_bind_pt_irq(struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - return xsm_call(bind_pt_irq(d, bind)); + return xsm_ops->bind_pt_irq(d, bind); } static inline int xsm_unbind_pt_irq(struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - return xsm_call(unbind_pt_irq(d, bind)); + return xsm_ops->unbind_pt_irq(d, bind); } static inline int xsm_pin_mem_cacheattr(struct domain *d) { - return xsm_call(pin_mem_cacheattr(d)); + return xsm_ops->pin_mem_cacheattr(d); } static inline int xsm_ext_vcpucontext(struct domain *d, uint32_t cmd) { - return xsm_call(ext_vcpucontext(d, cmd)); + return xsm_ops->ext_vcpucontext(d, cmd); } static inline int xsm_vcpuextstate(struct domain *d, uint32_t cmd) { - return xsm_call(vcpuextstate(d, cmd)); + return xsm_ops->vcpuextstate(d, cmd); } static inline int xsm_ioport_permission (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { - return xsm_call(ioport_permission(d, s, e, allow)); + return xsm_ops->ioport_permission(d, s, e, allow); } static inline int xsm_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) { - return xsm_call(ioport_mapping(d, s, e, allow)); + return xsm_ops->ioport_mapping(d, s, e, allow); } #endif /* CONFIG_X86 */ +extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)); +extern int xsm_policy_init(unsigned long *module_map, + const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)); +extern int register_xsm(struct xsm_operations *ops); +extern int unregister_xsm(struct xsm_operations *ops); + extern struct xsm_operations dummy_xsm_ops; extern void xsm_fixup_ops(struct xsm_operations *ops); +#else /* XSM_ENABLE */ + +#define XSM_DEFAULT(type, name) inline type xsm_ ## name +#include <xsm/dummy.h> + +static inline int xsm_init (unsigned long *module_map, + const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)) +{ + return 0; +} +#endif /* XSM_ENABLE */ + #endif /* __XSM_H */ diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index a5dbfe7..af532b8 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -10,621 +10,8 @@ * as published by the Free Software Foundation. */ -#include <xen/sched.h> -#include <xsm/xsm.h> - -static void dummy_security_domaininfo(struct domain *d, - struct xen_domctl_getdomaininfo *info) -{ - return; -} - -static int dummy_setvcpucontext(struct domain *d) -{ - return 0; -} - -static int dummy_pausedomain (struct domain *d) -{ - return 0; -} - -static int dummy_unpausedomain (struct domain *d) -{ - return 0; -} - -static int dummy_resumedomain (struct domain *d) -{ - return 0; -} - -static int dummy_domain_create(struct domain *d, u32 ssidref) -{ - return 0; -} - -static int dummy_max_vcpus(struct domain *d) -{ - return 0; -} - -static int dummy_destroydomain (struct domain *d) -{ - return 0; -} - -static int dummy_vcpuaffinity (int cmd, struct domain *d) -{ - return 0; -} - -static int dummy_scheduler (struct domain *d) -{ - return 0; -} - -static int dummy_getdomaininfo (struct domain *d) -{ - if ( !IS_PRIV(current->domain) ) - return -EPERM; - return 0; -} - -static int dummy_getvcpucontext (struct domain *d) -{ - return 0; -} - -static int dummy_getvcpuinfo (struct domain *d) -{ - return 0; -} - -static int dummy_domain_settime (struct domain *d) -{ - return 0; -} - -static int dummy_set_target (struct domain *d, struct domain *e) -{ - return 0; -} - -static int dummy_domctl(struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_set_virq_handler(struct domain *d, uint32_t virq) -{ - return 0; -} - -static int dummy_tbufcontrol (void) -{ - return 0; -} - -static int dummy_readconsole (uint32_t clear) -{ - return 0; -} - -static int dummy_sched_id (void) -{ - return 0; -} - -static int dummy_setdomainmaxmem (struct domain *d) -{ - return 0; -} - -static int dummy_setdomainhandle (struct domain *d) -{ - return 0; -} - -static int dummy_setdebugging (struct domain *d) -{ - return 0; -} - -static int dummy_perfcontrol (void) -{ - return 0; -} - -static int dummy_debug_keys (void) -{ - return 0; -} - -static int dummy_getcpuinfo (void) -{ - return 0; -} - -static int dummy_get_pmstat (void) -{ - return 0; -} - -static int dummy_setpminfo (void) -{ - return 0; -} - -static int dummy_pm_op (void) -{ - return 0; -} - -static int dummy_do_mca (void) -{ - return 0; -} - -static int dummy_availheap (void) -{ - return 0; -} - -static int dummy_alloc_security_domain (struct domain *d) -{ - return 0; -} - -static void dummy_free_security_domain (struct domain *d) -{ - return; -} - -static int dummy_grant_mapref (struct domain *d1, struct domain *d2, - uint32_t flags) -{ - return 0; -} - -static int dummy_grant_unmapref (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_setup (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_transfer (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_copy (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_query_size (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_memory_adjust_reservation (struct domain *d1, - struct domain *d2) -{ - return 0; -} - -static int dummy_memory_stat_reservation (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_console_io (struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_profile (struct domain *d, int op) -{ - return 0; -} - -static int dummy_kexec (void) -{ - return 0; -} - -static int dummy_schedop_shutdown (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_memory_pin_page(struct domain *d1, struct domain *d2, struct page_info *page) -{ - return 0; -} - -static int dummy_evtchn_unbound (struct domain *d, struct evtchn *chn, - domid_t id2) -{ - return 0; -} - -static int dummy_evtchn_interdomain (struct domain *d1, struct evtchn - *chan1, struct domain *d2, struct evtchn *chan2) -{ - return 0; -} - -static void dummy_evtchn_close_post (struct evtchn *chn) -{ - return; -} - -static int dummy_evtchn_send (struct domain *d, struct evtchn *chn) -{ - return 0; -} - -static int dummy_evtchn_status (struct domain *d, struct evtchn *chn) -{ - return 0; -} - -static int dummy_evtchn_reset (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_alloc_security_evtchn (struct evtchn *chn) -{ - return 0; -} - -static void dummy_free_security_evtchn (struct evtchn *chn) -{ - return; -} - -static char *dummy_show_security_evtchn (struct domain *d, const struct evtchn *chn) -{ - return NULL; -} - -static int dummy_get_pod_target(struct domain *d) -{ - return 0; -} - -static int dummy_set_pod_target(struct domain *d) -{ - return 0; -} - -static int dummy_get_device_group (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_test_assign_device (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_assign_device (struct domain *d, uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_deassign_device (struct domain *d, uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_plug_core (void) -{ - return 0; -} - -static int dummy_resource_unplug_core (void) -{ - return 0; -} - -static int dummy_resource_plug_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_unplug_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_setup_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_setup_gsi (int gsi) -{ - return 0; -} - -static int dummy_resource_setup_misc (void) -{ - return 0; -} - -static int dummy_page_offline (uint32_t cmd) -{ - return 0; -} - -static int dummy_lockprof (void) -{ - return 0; -} - -static int dummy_cpupool_op (void) -{ - return 0; -} - -static int dummy_sched_op (void) -{ - return 0; -} - -static long dummy___do_xsm_op(XEN_GUEST_HANDLE(xsm_op_t) op) -{ - return -ENOSYS; -} - -static char *dummy_show_irq_sid (int irq) -{ - return NULL; -} - -static int dummy_map_domain_pirq (struct domain *d, int irq, void *data) -{ - return 0; -} - -static int dummy_unmap_domain_pirq (struct domain *d, int irq) -{ - return 0; -} - -static int dummy_irq_permission (struct domain *d, int pirq, uint8_t allow) -{ - return 0; -} - -static int dummy_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_pci_config_permission (struct domain *d, uint32_t machine_bdf, - uint16_t start, uint16_t end, - uint8_t access) -{ - return 0; -} - -#ifdef CONFIG_X86 -static int dummy_shadow_control (struct domain *d, uint32_t op) -{ - return 0; -} - -static int dummy_getpageframeinfo (struct domain *d) -{ - return 0; -} - -static int dummy_getmemlist (struct domain *d) -{ - return 0; -} - -static int dummy_hypercall_init (struct domain *d) -{ - return 0; -} - -static int dummy_hvmcontext (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_address_size (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_machine_address_size (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_hvm_param (struct domain *d, unsigned long op) -{ - return 0; -} - -static int dummy_hvm_set_pci_intx_level (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_set_isa_irq_level (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_set_pci_link_route (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_inject_msi (struct domain *d) -{ - return 0; -} - -static int dummy_mem_event (struct domain *d) -{ - return 0; -} - -static int dummy_mem_sharing (struct domain *d) -{ - return 0; -} - -static int dummy_apic (struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_xen_settime (void) -{ - return 0; -} - -static int dummy_memtype (uint32_t access) -{ - return 0; -} - -static int dummy_microcode (void) -{ - return 0; -} - -static int dummy_physinfo (void) -{ - return 0; -} - -static int dummy_platform_quirk (uint32_t quirk) -{ - return 0; -} - -static int dummy_firmware_info (void) -{ - return 0; -} - -static int dummy_efi_call(void) -{ - return 0; -} - -static int dummy_acpi_sleep (void) -{ - return 0; -} - -static int dummy_change_freq (void) -{ - return 0; -} - -static int dummy_getidletime (void) -{ - return 0; -} - -static int dummy_machine_memory_map (void) -{ - return 0; -} - -static int dummy_domain_memory_map (struct domain *d) -{ - return 0; -} - -static int dummy_mmu_normal_update (struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte) -{ - return 0; -} - -static int dummy_mmu_machphys_update (struct domain *d, struct domain *f, unsigned long mfn) -{ - return 0; -} - -static int dummy_update_va_mapping (struct domain *d, struct domain *f, - l1_pgentry_t pte) -{ - return 0; -} - -static int dummy_add_to_physmap (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_remove_from_physmap (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_sendtrigger (struct domain *d) -{ - return 0; -} - -static int dummy_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - return 0; -} - -static int dummy_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - return 0; -} - -static int dummy_pin_mem_cacheattr (struct domain *d) -{ - return 0; -} - -static int dummy_ext_vcpucontext (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_vcpuextstate (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_ioport_permission (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) -{ - return 0; -} -#endif +#define XSM_DEFAULT(type, name) type dummy_ ## name +#include <xsm/dummy.h> struct xsm_operations dummy_xsm_ops; diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c index 96c8669..c4c85c0 100644 --- a/xen/xsm/xsm_core.c +++ b/xen/xsm/xsm_core.c @@ -113,7 +113,7 @@ int unregister_xsm(struct xsm_operations *ops) long do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { - return __do_xsm_op(op); + return xsm___do_xsm_op(op); } -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 10/22] xen: use XSM instead of IS_PRIV where duplicated
The Xen hypervisor has two basic access control function calls: IS_PRIV and the xsm_* functions. Most privileged operations currently require that both checks succeed, and many times the checks are at different locations in the code. This patch eliminates the explicit and implicit IS_PRIV checks that are duplicated in XSM hooks. When XSM_ENABLE is not defined or when the dummy XSM module is used, this patch should not change any functionality. Because the locations of privilege checks have sometimes moved below argument validation, error returns of some functions may change from EPERM to EINVAL or ESRCH if called with invalid arguments and from a domain without permission to perform the operation. Some checks are removed due to non-obvious duplicates in their callers: * acpi_enter_sleep is checked in XENPF_enter_acpi_sleep * map_domain_pirq has IS_PRIV_FOR checked in its callers: * physdev_map_pirq checks when acquiring the RCU lock * ioapic_guest_write is checked in PHYSDEVOP_apic_write * PHYSDEVOP_{manage_pci_add,manage_pci_add_ext,pci_device_add} are checked by xsm_resource_plug_pci in pci_add_device * PHYSDEVOP_manage_pci_remove is checked by xsm_resource_unplug_pci in pci_remove_device * PHYSDEVOP_{restore_msi,restore_msi_ext} are checked by xsm_resource_setup_pci in pci_restore_msi_state * do_console_io has changed to IS_PRIV from an explicit domid==0 Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/arch/x86/acpi/power.c | 2 +- xen/arch/x86/cpu/mcheck/mce.c | 3 --- xen/arch/x86/irq.c | 3 +-- xen/arch/x86/mm.c | 3 --- xen/arch/x86/physdev.c | 54 ++----------------------------------------- xen/common/kexec.c | 3 --- xen/common/schedule.c | 6 ----- xen/drivers/char/console.c | 6 ----- xen/include/xsm/dummy.h | 28 ++++++++++++++++++++++ xen/xsm/flask/hooks.c | 5 ++-- 10 files changed, 35 insertions(+), 78 deletions(-) diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c index 9e1f989..c7b37ef 100644 --- a/xen/arch/x86/acpi/power.c +++ b/xen/arch/x86/acpi/power.c @@ -238,7 +238,7 @@ static long enter_state_helper(void *data) */ int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep) { - if ( !IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt_blk.address ) + if ( !acpi_sinfo.pm1a_cnt_blk.address ) return -EPERM; /* Sanity check */ diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c index a89df6d..f399054 100644 --- a/xen/arch/x86/cpu/mcheck/mce.c +++ b/xen/arch/x86/cpu/mcheck/mce.c @@ -1379,9 +1379,6 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc) struct xen_mc_msrinject *mc_msrinject; struct xen_mc_mceinject *mc_mceinject; - if (!IS_PRIV(v->domain) ) - return x86_mcerr(NULL, -EPERM); - ret = xsm_do_mca(); if ( ret ) return x86_mcerr(NULL, ret); diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index c87027b..70b0f03 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -1853,8 +1853,7 @@ int map_domain_pirq( ASSERT(spin_is_locked(&d->event_lock)); if ( !IS_PRIV(current->domain) && - !(IS_PRIV_FOR(current->domain, d) && - irq_access_permitted(current->domain, pirq))) + !irq_access_permitted(current->domain, pirq)) return -EPERM; if ( pirq < 0 || pirq >= d->nr_pirqs || irq < 0 || irq >= nr_irqs ) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 4ea5334..b370300 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -4488,9 +4488,6 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) XEN_GUEST_HANDLE(e820entry_t) buffer; unsigned int i; - if ( !IS_PRIV(current->domain) ) - return -EINVAL; - rc = xsm_machine_memory_map(); if ( rc ) return rc; diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 13b85da..515dca3 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -109,12 +109,6 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p, if ( ret ) return ret; - if ( !IS_PRIV_FOR(current->domain, d) ) - { - ret = -EPERM; - goto free_domain; - } - /* Verify or get irq. */ switch ( type ) { @@ -238,10 +232,6 @@ int physdev_unmap_pirq(domid_t domid, int pirq) goto free_domain; } - ret = -EPERM; - if ( !IS_PRIV_FOR(current->domain, d) ) - goto free_domain; - ret = xsm_unmap_domain_pirq(d, domain_pirq_to_irq(d, pirq)); if ( ret ) goto free_domain; @@ -433,9 +423,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) ret = -EFAULT; if ( copy_from_guest(&apic, arg, 1) != 0 ) break; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; ret = xsm_apic(v->domain, cmd); if ( ret ) break; @@ -450,9 +437,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) ret = -EFAULT; if ( copy_from_guest(&apic, arg, 1) != 0 ) break; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; ret = xsm_apic(v->domain, cmd); if ( ret ) break; @@ -467,8 +451,8 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&irq_op, arg, 1) != 0 ) break; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) + ret = xsm_apic(v->domain, cmd); + if ( ret ) break; /* Vector is only used by hypervisor, and dom0 shouldn''t @@ -517,9 +501,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_manage_pci_add: { struct physdev_manage_pci manage_pci; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; ret = -EFAULT; if ( copy_from_guest(&manage_pci, arg, 1) != 0 ) break; @@ -530,9 +511,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_manage_pci_remove: { struct physdev_manage_pci manage_pci; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; ret = -EFAULT; if ( copy_from_guest(&manage_pci, arg, 1) != 0 ) break; @@ -545,10 +523,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) struct physdev_manage_pci_ext manage_pci_ext; struct pci_dev_info pdev_info; - ret = -EPERM; - if ( !IS_PRIV(current->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&manage_pci_ext, arg, 1) != 0 ) break; @@ -571,10 +545,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) struct physdev_pci_device_add add; struct pci_dev_info pdev_info; - ret = -EPERM; - if ( !IS_PRIV(current->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&add, arg, 1) != 0 ) break; @@ -595,10 +565,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_pci_device_remove: { struct physdev_pci_device dev; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&dev, arg, 1) != 0 ) break; @@ -610,10 +576,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_pci_mmcfg_reserved: { struct physdev_pci_mmcfg_reserved info; - ret = -EPERM; - if ( !IS_PRIV(current->domain) ) - break; - ret = xsm_resource_setup_misc(); if ( ret ) break; @@ -631,10 +593,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) struct physdev_restore_msi restore_msi; struct pci_dev *pdev; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&restore_msi, arg, 1) != 0 ) break; @@ -650,10 +608,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) struct physdev_pci_device dev; struct pci_dev *pdev; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&dev, arg, 1) != 0 ) break; @@ -668,10 +622,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_setup_gsi: { struct physdev_setup_gsi setup_gsi; - ret = -EPERM; - if ( !IS_PRIV(v->domain) ) - break; - ret = -EFAULT; if ( copy_from_guest(&setup_gsi, arg, 1) != 0 ) break; diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 2bc3e33..7dc6f24 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -851,9 +851,6 @@ static int do_kexec_op_internal(unsigned long op, XEN_GUEST_HANDLE(void) uarg, unsigned long flags; int ret = -EINVAL; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - ret = xsm_kexec(); if ( ret ) return ret; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index eee74be..95142c0 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -919,12 +919,6 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE(void) arg) if ( d == NULL ) break; - if ( !IS_PRIV_FOR(current->domain, d) ) - { - rcu_unlock_domain(d); - return -EPERM; - } - ret = xsm_schedop_shutdown(current->domain, d); if ( ret ) { diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index d97170c..aee3b4b 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -363,12 +363,6 @@ long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer) long rc; unsigned int idx, len; -#ifndef VERBOSE - /* Only domain 0 may access the emergency console. */ - if ( current->domain->domain_id != 0 ) - return -EPERM; -#endif - rc = xsm_console_io(current->domain, cmd); if ( rc ) return rc; diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 61c6f13..389d9f6 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -161,6 +161,8 @@ static XSM_DEFAULT(int, pm_op) (void) static XSM_DEFAULT(int, do_mca) (void) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } @@ -223,6 +225,10 @@ static XSM_DEFAULT(int, memory_stat_reservation) (struct domain *d1, struct doma static XSM_DEFAULT(int, console_io) (struct domain *d, int cmd) { +#ifndef VERBOSE + if ( !IS_PRIV(current->domain) ) + return -EPERM; +#endif return 0; } @@ -233,11 +239,15 @@ static XSM_DEFAULT(int, profile) (struct domain *d, int op) static XSM_DEFAULT(int, kexec) (void) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, schedop_shutdown) (struct domain *d1, struct domain *d2) { + if ( !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } @@ -336,26 +346,36 @@ static XSM_DEFAULT(int, resource_unplug_core) (void) static XSM_DEFAULT(int, resource_plug_pci) (uint32_t machine_bdf) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, resource_unplug_pci) (uint32_t machine_bdf) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, resource_setup_pci) (uint32_t machine_bdf) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, resource_setup_gsi) (int gsi) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, resource_setup_misc) (void) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } @@ -396,6 +416,8 @@ static XSM_DEFAULT(int, map_domain_pirq) (struct domain *d, int irq, void *data) static XSM_DEFAULT(int, unmap_domain_pirq) (struct domain *d, int irq) { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } @@ -494,6 +516,8 @@ static XSM_DEFAULT(int, mem_sharing) (struct domain *d) static XSM_DEFAULT(int, apic) (struct domain *d, int cmd) { + if ( !IS_PRIV(d) ) + return -EPERM; return 0; } @@ -534,6 +558,8 @@ static XSM_DEFAULT(int, efi_call) (void) static XSM_DEFAULT(int, acpi_sleep) (void) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } @@ -549,6 +575,8 @@ static XSM_DEFAULT(int, getidletime) (void) static XSM_DEFAULT(int, machine_memory_map) (void) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6d4b4f0..10c2163 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1147,10 +1147,11 @@ static int flask_apic(struct domain *d, int cmd) switch ( cmd ) { - case PHYSDEVOP_APIC_READ: + case PHYSDEVOP_apic_read: + case PHYSDEVOP_alloc_irq_vector: perm = XEN__READAPIC; break; - case PHYSDEVOP_APIC_WRITE: + case PHYSDEVOP_apic_write: perm = XEN__WRITEAPIC; break; default: -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 11/22] xen: avoid calling rcu_lock_*target_domain when an XSM hook exists
The rcu_lock_{,remote_}target_domain_by_id functions are wrappers around an IS_PRIV_FOR check for the current domain. This is now redundant with XSM hooks, so replace these calls with rcu_lock_domain_by_any_id or rcu_lock_remote_domain_by_id to remove the duplicate permission checks. When XSM_ENABLE is not defined or when the dummy XSM module is used, this patch should not change any functionality. Because the locations of privilege checks have sometimes moved below argument validation, error returns of some functions may change from EPERM to EINVAL when called with invalid arguments and from a domain without permission to perform the operation. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/arch/x86/hvm/hvm.c | 38 +++++++++++++++---------------- xen/arch/x86/mm.c | 22 ++++++++---------- xen/common/event_channel.c | 18 +++++++-------- xen/common/grant_table.c | 57 +++++++++++++++------------------------------- xen/common/memory.c | 15 ++++++------ xen/include/xsm/dummy.h | 34 +++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 87 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 2cb08c9..ca06976 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3335,7 +3335,7 @@ static int hvmop_set_pci_intx_level( if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) ) return -EINVAL; - rc = rcu_lock_remote_target_domain_by_id(op.domid, &d); + rc = rcu_lock_remote_domain_by_id(op.domid, &d); if ( rc != 0 ) return rc; @@ -3500,7 +3500,7 @@ static int hvmop_set_isa_irq_level( if ( op.isa_irq > 15 ) return -EINVAL; - rc = rcu_lock_remote_target_domain_by_id(op.domid, &d); + rc = rcu_lock_remote_domain_by_id(op.domid, &d); if ( rc != 0 ) return rc; @@ -3544,7 +3544,7 @@ static int hvmop_set_pci_link_route( if ( (op.link > 3) || (op.isa_irq > 15) ) return -EINVAL; - rc = rcu_lock_remote_target_domain_by_id(op.domid, &d); + rc = rcu_lock_remote_domain_by_id(op.domid, &d); if ( rc != 0 ) return rc; @@ -3574,7 +3574,7 @@ static int hvmop_inject_msi( if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(op.domid, &d); + rc = rcu_lock_remote_domain_by_id(op.domid, &d); if ( rc != 0 ) return rc; @@ -3671,9 +3671,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( a.index >= HVM_NR_PARAMS ) return -EINVAL; - rc = rcu_lock_target_domain_by_id(a.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(a.domid); + if ( d == NULL ) + return -ESRCH; rc = -EINVAL; if ( !is_hvm_domain(d) ) @@ -3917,7 +3917,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + rc = rcu_lock_remote_domain_by_id(a.domid, &d); if ( rc != 0 ) return rc; @@ -3956,7 +3956,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + rc = rcu_lock_remote_domain_by_id(a.domid, &d); if ( rc != 0 ) return rc; @@ -4006,9 +4006,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(a.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(a.domid); + if ( d == NULL ) + return -ESRCH; rc = xsm_hvm_param(d, op); if ( rc ) @@ -4053,7 +4053,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + rc = rcu_lock_remote_domain_by_id(a.domid, &d); if ( rc != 0 ) return rc; @@ -4132,7 +4132,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + rc = rcu_lock_remote_domain_by_id(a.domid, &d); if ( rc != 0 ) return rc; @@ -4167,7 +4167,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + rc = rcu_lock_remote_domain_by_id(a.domid, &d); if ( rc != 0 ) return rc; @@ -4203,9 +4203,9 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&a, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(a.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(a.domid); + if ( d == NULL ) + return -ESRCH; rc = -EINVAL; if ( !is_hvm_domain(d) || !paging_mode_shadow(d) ) @@ -4257,7 +4257,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&tr, arg, 1 ) ) return -EFAULT; - rc = rcu_lock_remote_target_domain_by_id(tr.domid, &d); + rc = rcu_lock_remote_domain_by_id(tr.domid, &d); if ( rc != 0 ) return rc; diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index b370300..5c6ea2d 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -4371,9 +4371,9 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&xatp, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(xatp.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(xatp.domid); + if ( d == NULL ) + return -ESRCH; if ( xsm_add_to_physmap(current->domain, d) ) { @@ -4410,9 +4410,9 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) if ( fmap.map.nr_entries > E820MAX ) return -EINVAL; - rc = rcu_lock_target_domain_by_id(fmap.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(fmap.domid); + if ( d == NULL ) + return -ESRCH; rc = xsm_domain_memory_map(d); if ( rc ) @@ -4563,16 +4563,12 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) struct domain *d; struct p2m_domain *p2m; - /* Support DOMID_SELF? */ - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( copy_from_guest(&target, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(target.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(target.domid); + if ( d == NULL ) + return -ESRCH; if ( op == XENMEM_set_pod_target ) rc = xsm_set_pod_target(d); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 53777f8..70becdd 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -165,9 +165,9 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc) domid_t dom = alloc->dom; long rc; - rc = rcu_lock_target_domain_by_id(dom, &d); - if ( rc ) - return rc; + d = rcu_lock_domain_by_any_id(dom); + if ( d == NULL ) + return -ESRCH; spin_lock(&d->event_lock); @@ -798,9 +798,9 @@ static long evtchn_status(evtchn_status_t *status) struct evtchn *chn; long rc = 0; - rc = rcu_lock_target_domain_by_id(dom, &d); - if ( rc ) - return rc; + d = rcu_lock_domain_by_any_id(dom); + if ( d == NULL ) + return -ESRCH; spin_lock(&d->event_lock); @@ -950,9 +950,9 @@ static long evtchn_reset(evtchn_reset_t *r) struct domain *d; int i, rc; - rc = rcu_lock_target_domain_by_id(dom, &d); - if ( rc ) - return rc; + d = rcu_lock_domain_by_any_id(dom); + if ( d == NULL ) + return -ESRCH; rc = xsm_evtchn_reset(current->domain, d); if ( rc ) diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index c23c053..10a34d6 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -230,30 +230,6 @@ double_gt_unlock(struct grant_table *lgt, struct grant_table *rgt) spin_unlock(&rgt->lock); } -static struct domain *gt_lock_target_domain_by_id(domid_t dom) -{ - struct domain *d; - int rc = GNTST_general_error; - - switch ( rcu_lock_target_domain_by_id(dom, &d) ) - { - case 0: - return d; - - case -ESRCH: - gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); - rc = GNTST_bad_domain; - break; - - case -EPERM: - rc = GNTST_permission_denied; - break; - } - - ASSERT(rc < 0 && -rc <= MAX_ERRNO); - return ERR_PTR(rc); -} - static inline int __get_maptrack_handle( struct grant_table *t) @@ -1339,11 +1315,12 @@ gnttab_setup_table( goto out1; } - d = gt_lock_target_domain_by_id(op.dom); - if ( IS_ERR(d) ) + d = rcu_lock_domain_by_any_id(op.dom); + if ( d == NULL ) { - op.status = PTR_ERR(d); - goto out1; + gdprintk(XENLOG_INFO, "Bad domid %d.\n", op.dom); + op.status = GNTST_bad_domain; + goto out2; } if ( xsm_grant_setup(current->domain, d) ) @@ -1407,10 +1384,11 @@ gnttab_query_size( return -EFAULT; } - d = gt_lock_target_domain_by_id(op.dom); - if ( IS_ERR(d) ) + d = rcu_lock_domain_by_any_id(op.dom); + if ( d == NULL ) { - op.status = PTR_ERR(d); + gdprintk(XENLOG_INFO, "Bad domid %d.\n", op.dom); + op.status = GNTST_bad_domain; goto query_out; } @@ -2280,10 +2258,10 @@ gnttab_get_status_frames(XEN_GUEST_HANDLE(gnttab_get_status_frames_t) uop, return -EFAULT; } - d = gt_lock_target_domain_by_id(op.dom); - if ( IS_ERR(d) ) + d = rcu_lock_domain_by_any_id(op.dom); + if ( d == NULL ) { - op.status = PTR_ERR(d); + op.status = GNTST_bad_domain; goto out1; } rc = xsm_grant_setup(current->domain, d); @@ -2333,14 +2311,15 @@ gnttab_get_version(XEN_GUEST_HANDLE(gnttab_get_version_t uop)) if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(op.dom, &d); - if ( rc < 0 ) - return rc; + d = rcu_lock_domain_by_any_id(op.dom); + if ( d == NULL ) + return -ESRCH; - if ( xsm_grant_query_size(current->domain, d) ) + rc = xsm_grant_query_size(current->domain, d); + if ( rc ) { rcu_unlock_domain(d); - return -EPERM; + return rc; } op.version = d->grant_table->gt_version; diff --git a/xen/common/memory.c b/xen/common/memory.c index 8779d6b..cfdd63f 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -570,7 +570,8 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) && (reservation.mem_flags & XENMEMF_populate_on_demand) ) args.memflags |= MEMF_populate_on_demand; - if ( unlikely(rcu_lock_target_domain_by_id(reservation.domid, &d)) ) + d = rcu_lock_domain_by_any_id(reservation.domid); + if ( d == NULL ) return start_extent; args.domain = d; @@ -619,9 +620,9 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&domid, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(domid, &d); - if ( rc ) - return rc; + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; rc = xsm_memory_stat_reservation(current->domain, d); if ( rc ) @@ -657,9 +658,9 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&xrfp, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(xrfp.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(xrfp.domid); + if ( d == NULL ) + return -ESRCH; if ( xsm_remove_from_physmap(current->domain, d) ) { diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 389d9f6..31f862d 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -194,6 +194,8 @@ static XSM_DEFAULT(int, grant_unmapref) (struct domain *d1, struct domain *d2) static XSM_DEFAULT(int, grant_setup) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } @@ -209,17 +211,23 @@ static XSM_DEFAULT(int, grant_copy) (struct domain *d1, struct domain *d2) static XSM_DEFAULT(int, grant_query_size) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, memory_adjust_reservation) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, memory_stat_reservation) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } @@ -260,6 +268,8 @@ static XSM_DEFAULT(int, memory_pin_page) (struct domain *d1, struct domain *d2, static XSM_DEFAULT(int, evtchn_unbound) (struct domain *d, struct evtchn *chn, domid_t id2) { + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } @@ -281,11 +291,15 @@ static XSM_DEFAULT(int, evtchn_send) (struct domain *d, struct evtchn *chn) static XSM_DEFAULT(int, evtchn_status) (struct domain *d, struct evtchn *chn) { + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, evtchn_reset) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } @@ -306,11 +320,15 @@ static XSM_DEFAULT(char *, show_security_evtchn) (struct domain *d, const struct static XSM_DEFAULT(int, get_pod_target)(struct domain *d) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, set_pod_target)(struct domain *d) { + if ( !IS_PRIV(current->domain) ) + return -EPERM; return 0; } @@ -481,26 +499,36 @@ static XSM_DEFAULT(int, machine_address_size) (struct domain *d, uint32_t cmd) static XSM_DEFAULT(int, hvm_param) (struct domain *d, unsigned long op) { + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, hvm_set_pci_intx_level) (struct domain *d) { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, hvm_set_isa_irq_level) (struct domain *d) { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, hvm_set_pci_link_route) (struct domain *d) { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, hvm_inject_msi) (struct domain *d) { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } @@ -582,6 +610,8 @@ static XSM_DEFAULT(int, machine_memory_map) (void) static XSM_DEFAULT(int, domain_memory_map) (struct domain *d) { + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; return 0; } @@ -605,11 +635,15 @@ static XSM_DEFAULT(int, update_va_mapping) (struct domain *d, struct domain *f, static XSM_DEFAULT(int, add_to_physmap) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, remove_from_physmap) (struct domain *d1, struct domain *d2) { + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; return 0; } -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 12/22] arch/x86: convert platform_hypercall to use XSM
The newly introduced xsm_platform_op hook addresses new sub-ops, while most ops already have their own XSM hooks. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/arch/x86/platform_hypercall.c | 11 ++++++++--- xen/include/xsm/dummy.h | 7 +++++++ xen/include/xsm/xsm.h | 6 ++++++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 073a2ea..50b5f1d 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -66,15 +66,16 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) ret_t ret = 0; struct xen_platform_op curop, *op = &curop; - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( copy_from_guest(op, u_xenpf_op, 1) ) return -EFAULT; if ( op->interface_version != XENPF_INTERFACE_VERSION ) return -EACCES; + ret = xsm_platform_op(op->cmd); + if ( ret ) + return ret; + /* * Trylock here avoids deadlock with an existing platform critical section * which might (for some current or future reason) want to synchronise @@ -507,6 +508,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) { struct xenpf_pcpu_version *ver = &op->u.pcpu_version; + ret = xsm_getcpuinfo(); + if ( ret ) + break; + if ( !get_cpu_maps() ) { ret = -EBUSY; diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 31f862d..3f0a6d8 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -574,6 +574,13 @@ static XSM_DEFAULT(int, platform_quirk) (uint32_t quirk) return 0; } +static XSM_DEFAULT(int, platform_op) (uint32_t op) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, firmware_info) (void) { return 0; diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index ba5a89e..171acb2 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -158,6 +158,7 @@ struct xsm_operations { int (*microcode) (void); int (*physinfo) (void); int (*platform_quirk) (uint32_t); + int (*platform_op) (uint32_t cmd); int (*firmware_info) (void); int (*efi_call) (void); int (*acpi_sleep) (void); @@ -696,6 +697,11 @@ static inline int xsm_platform_quirk (uint32_t quirk) return xsm_ops->platform_quirk(quirk); } +static inline int xsm_platform_op (uint32_t op) +{ + return xsm_ops->platform_op(op); +} + static inline int xsm_firmware_info (void) { return xsm_ops->firmware_info(); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index af532b8..7f9c753 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -142,6 +142,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, microcode); set_to_dummy_if_null(ops, physinfo); set_to_dummy_if_null(ops, platform_quirk); + set_to_dummy_if_null(ops, platform_op); set_to_dummy_if_null(ops, firmware_info); set_to_dummy_if_null(ops, efi_call); set_to_dummy_if_null(ops, acpi_sleep); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 10c2163..1cbf2f2 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1207,6 +1207,38 @@ static int flask_platform_quirk(uint32_t quirk) XEN__QUIRK, NULL); } +static int flask_platform_op(uint32_t op) +{ + switch ( op ) + { + case XENPF_settime: + case XENPF_add_memtype: + case XENPF_del_memtype: + case XENPF_read_memtype: + case XENPF_microcode_update: + case XENPF_platform_quirk: + case XENPF_firmware_info: + case XENPF_efi_runtime_call: + case XENPF_enter_acpi_sleep: + case XENPF_change_freq: + case XENPF_getidletime: + case XENPF_set_processor_pminfo: + case XENPF_get_cpuinfo: + case XENPF_get_cpu_version: + case XENPF_cpu_online: + case XENPF_cpu_offline: + case XENPF_cpu_hotadd: + case XENPF_mem_hotadd: + /* These operations have their own XSM hooks */ + return 0; + case XENPF_core_parking: + return domain_has_xen(current->domain, XEN__PM_OP); + default: + printk("flask_platform_op: Unknown op %d\n", op); + return -EPERM; + } +} + static int flask_firmware_info(void) { return domain_has_xen(current->domain, XEN__FIRMWARE); @@ -1577,6 +1609,7 @@ static struct xsm_operations flask_ops = { .microcode = flask_microcode, .physinfo = flask_physinfo, .platform_quirk = flask_platform_quirk, + .platform_op = flask_platform_op, .firmware_info = flask_firmware_info, .efi_call = flask_efi_call, .acpi_sleep = flask_acpi_sleep, -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 13/22] xen: lock target domain in do_domctl common code
Because almost all domctls need to lock the target domain, do this by default instead of repeating it in each domctl. This is not currently extended to the arch-specific domctls, but RCU locks are safe to take recursively so this only causes duplicate but correct locking. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/common/domctl.c | 267 ++++++++++++---------------------------------------- 1 file changed, 58 insertions(+), 209 deletions(-) diff --git a/xen/common/domctl.c b/xen/common/domctl.c index d99ba67..76ced4f 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -243,6 +243,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) { long ret = 0; struct xen_domctl curop, *op = &curop; + struct domain *d; if ( copy_from_guest(op, u_domctl, 1) ) return -EFAULT; @@ -252,19 +253,28 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) switch ( op->cmd ) { + case XEN_DOMCTL_createdomain: + case XEN_DOMCTL_getdomaininfo: + d = NULL; + break; + default: + d = rcu_lock_domain_by_id(op->domain); + if ( d == NULL ) + return -ESRCH; + } + + switch ( op->cmd ) + { case XEN_DOMCTL_ioport_mapping: case XEN_DOMCTL_memory_mapping: case XEN_DOMCTL_bind_pt_irq: case XEN_DOMCTL_unbind_pt_irq: { - struct domain *d; - bool_t is_priv = IS_PRIV(current->domain); - if ( !is_priv && ((d = rcu_lock_domain_by_id(op->domain)) != NULL) ) + bool_t is_priv = IS_PRIV_FOR(current->domain, d); + if ( !is_priv ) { - is_priv = IS_PRIV_FOR(current->domain, d); - rcu_unlock_domain(d); + ret = -EPERM; + goto domctl_out_unlock; } - if ( !is_priv ) - return -EPERM; break; } case XEN_DOMCTL_getdomaininfo: @@ -276,15 +286,18 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) } if ( !domctl_lock_acquire() ) + { + if ( d ) + rcu_unlock_domain(d); return hypercall_create_continuation( __HYPERVISOR_domctl, "h", u_domctl); + } switch ( op->cmd ) { case XEN_DOMCTL_setvcpucontext: { - struct domain *d = rcu_lock_domain_by_id(op->domain); vcpu_guest_context_u c = { .nat = NULL }; unsigned int vcpu = op->u.vcpucontext.vcpu; struct vcpu *v; @@ -338,77 +351,48 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) svc_out: free_vcpu_guest_context(c.nat); - rcu_unlock_domain(d); } break; case XEN_DOMCTL_pausedomain: { - struct domain *d = rcu_lock_domain_by_id(op->domain); - ret = -ESRCH; - if ( d != NULL ) - { - ret = xsm_pausedomain(d); - if ( ret ) - goto pausedomain_out; + ret = xsm_pausedomain(d); + if ( ret ) + break; - ret = -EINVAL; - if ( d != current->domain ) - { - domain_pause_by_systemcontroller(d); - ret = 0; - } - pausedomain_out: - rcu_unlock_domain(d); + ret = -EINVAL; + if ( d != current->domain ) + { + domain_pause_by_systemcontroller(d); + ret = 0; } } break; case XEN_DOMCTL_unpausedomain: { - struct domain *d = rcu_lock_domain_by_id(op->domain); - - ret = -ESRCH; - if ( d == NULL ) - break; - ret = xsm_unpausedomain(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } domain_unpause_by_systemcontroller(d); - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_resumedomain: { - struct domain *d = rcu_lock_domain_by_id(op->domain); - - ret = -ESRCH; - if ( d == NULL ) - break; - ret = xsm_resumedomain(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } domain_resume(d); - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_createdomain: { - struct domain *d; domid_t dom; static domid_t rover = 0; unsigned int domcr_flags; @@ -458,6 +442,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( IS_ERR(d) ) { ret = PTR_ERR(d); + d = NULL; break; } @@ -469,39 +454,28 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) op->domain = d->domain_id; if ( copy_to_guest(u_domctl, op, 1) ) ret = -EFAULT; + d = NULL; } break; case XEN_DOMCTL_max_vcpus: { - struct domain *d; unsigned int i, max = op->u.max_vcpus.max, cpu; cpumask_t *online; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) - break; - ret = -EINVAL; if ( (d == current->domain) || /* no domain_pause() */ (max > MAX_VIRT_CPUS) || (is_hvm_domain(d) && (max > MAX_HVM_VCPUS)) ) - { - rcu_unlock_domain(d); break; - } ret = xsm_max_vcpus(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } /* Until Xenoprof can dynamically grow its vcpu-s array... */ if ( d->xenoprof ) { - rcu_unlock_domain(d); ret = -EAGAIN; break; } @@ -576,44 +550,31 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) maxvcpu_out_novcpulock: domain_unpause(d); - rcu_unlock_domain(d); } break; case XEN_DOMCTL_destroydomain: { - struct domain *d = rcu_lock_domain_by_id(op->domain); - ret = -ESRCH; - if ( d != NULL ) - { - ret = xsm_destroydomain(d) ? : domain_kill(d); - rcu_unlock_domain(d); - } + ret = xsm_destroydomain(d) ? : domain_kill(d); } break; case XEN_DOMCTL_setvcpuaffinity: case XEN_DOMCTL_getvcpuaffinity: { - domid_t dom = op->domain; - struct domain *d = rcu_lock_domain_by_id(dom); struct vcpu *v; - ret = -ESRCH; - if ( d == NULL ) - break; - ret = xsm_vcpuaffinity(op->cmd, d); if ( ret ) - goto vcpuaffinity_out; + break; ret = -EINVAL; if ( op->u.vcpuaffinity.vcpu >= d->max_vcpus ) - goto vcpuaffinity_out; + break; ret = -ESRCH; if ( (v = d->vcpu[op->u.vcpuaffinity.vcpu]) == NULL ) - goto vcpuaffinity_out; + break; if ( op->cmd == XEN_DOMCTL_setvcpuaffinity ) { @@ -632,36 +593,23 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = cpumask_to_xenctl_cpumap( &op->u.vcpuaffinity.cpumap, v->cpu_affinity); } - - vcpuaffinity_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_scheduler_op: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) - break; - ret = xsm_scheduler(d); if ( ret ) - goto scheduler_op_out; + break; ret = sched_adjust(d, &op->u.scheduler_op); if ( copy_to_guest(u_domctl, op, 1) ) ret = -EFAULT; - - scheduler_op_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_getdomaininfo: { - struct domain *d; domid_t dom = op->domain; rcu_read_lock(&domlist_read_lock); @@ -689,19 +637,15 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) getdomaininfo_out: rcu_read_unlock(&domlist_read_lock); + d = NULL; } break; case XEN_DOMCTL_getvcpucontext: { vcpu_guest_context_u c = { .nat = NULL }; - struct domain *d; struct vcpu *v; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) - break; - ret = xsm_getvcpucontext(d); if ( ret ) goto getvcpucontext_out; @@ -750,31 +694,25 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) getvcpucontext_out: xfree(c.nat); - rcu_unlock_domain(d); } break; case XEN_DOMCTL_getvcpuinfo: { - struct domain *d; struct vcpu *v; struct vcpu_runstate_info runstate; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) - break; - ret = xsm_getvcpuinfo(d); if ( ret ) - goto getvcpuinfo_out; + break; ret = -EINVAL; if ( op->u.getvcpuinfo.vcpu >= d->max_vcpus ) - goto getvcpuinfo_out; + break; ret = -ESRCH; if ( (v = d->vcpu[op->u.getvcpuinfo.vcpu]) == NULL ) - goto getvcpuinfo_out; + break; vcpu_runstate_get(v, &runstate); @@ -787,25 +725,16 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( copy_to_guest(u_domctl, op, 1) ) ret = -EFAULT; - - getvcpuinfo_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_max_mem: { - struct domain *d; unsigned long new_max; - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - ret = xsm_setdomainmaxmem(d); if ( ret ) - goto max_mem_out; + break; ret = -EINVAL; new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT-10); @@ -819,77 +748,43 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) d->max_pages = new_max; ret = 0; spin_unlock(&d->page_alloc_lock); - - max_mem_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_setdomainhandle: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - ret = xsm_setdomainhandle(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } memcpy(d->handle, op->u.setdomainhandle.handle, sizeof(xen_domain_handle_t)); - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_setdebugging: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - ret = -EINVAL; if ( d == current->domain ) /* no domain_pause() */ - { - rcu_unlock_domain(d); break; - } ret = xsm_setdebugging(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } domain_pause(d); d->debugger_attached = !!op->u.setdebugging.enable; domain_unpause(d); /* causes guest to latch new status */ - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_irq_permission: { - struct domain *d; unsigned int pirq = op->u.irq_permission.pirq; int allow = op->u.irq_permission.allow_access; - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - if ( pirq >= d->nr_pirqs ) ret = -EINVAL; else if ( xsm_irq_permission(d, pirq, allow) ) @@ -898,14 +793,11 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) ret = irq_permit_access(d, pirq); else ret = irq_deny_access(d, pirq); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_iomem_permission: { - struct domain *d; unsigned long mfn = op->u.iomem_permission.first_mfn; unsigned long nr_mfns = op->u.iomem_permission.nr_mfns; int allow = op->u.iomem_permission.allow_access; @@ -914,125 +806,78 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */ break; - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - if ( xsm_iomem_permission(d, mfn, mfn + nr_mfns - 1, allow) ) ret = -EPERM; else if ( allow ) ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1); else ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_settimeoffset: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; - ret = xsm_domain_settime(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds); - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_set_target: { - struct domain *d, *e; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d == NULL ) - break; + struct domain *e; ret = -ESRCH; e = get_domain_by_id(op->u.set_target.target); if ( e == NULL ) - goto set_target_out; + break; ret = -EINVAL; if ( (d == e) || (d->target != NULL) ) { put_domain(e); - goto set_target_out; + break; } ret = xsm_set_target(d, e); if ( ret ) { put_domain(e); - goto set_target_out; + break; } /* Hold reference on @e until we destroy @d. */ d->target = e; ret = 0; - - set_target_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_subscribe: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d != NULL ) - { - ret = xsm_domctl(d, op->cmd); - if ( !ret ) - d->suspend_evtchn = op->u.subscribe.port; - rcu_unlock_domain(d); - } + ret = xsm_domctl(d, op->cmd); + if ( !ret ) + d->suspend_evtchn = op->u.subscribe.port; } break; case XEN_DOMCTL_disable_migrate: { - struct domain *d; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(op->domain)) != NULL ) - { - ret = xsm_domctl(d, op->cmd); - if ( !ret ) - d->disable_migrate = op->u.disable_migrate.disable; - rcu_unlock_domain(d); - } + ret = xsm_domctl(d, op->cmd); + if ( !ret ) + d->disable_migrate = op->u.disable_migrate.disable; } break; case XEN_DOMCTL_set_virq_handler: { - struct domain *d; uint32_t virq = op->u.set_virq_handler.virq; - ret = -ESRCH; - d = rcu_lock_domain_by_id(op->domain); - if ( d != NULL ) - { - ret = xsm_set_virq_handler(d, virq); - if ( !ret ) - ret = set_global_virq_handler(d, virq); - rcu_unlock_domain(d); - } + ret = xsm_set_virq_handler(d, virq); + if ( !ret ) + ret = set_global_virq_handler(d, virq); } break; @@ -1043,6 +888,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) domctl_lock_release(); + domctl_out_unlock: + if ( d ) + rcu_unlock_domain(d); + return ret; } -- 1.7.11.4
The xsm_domctl hook now covers every domctl, in addition to the more fine-grained XSM hooks in most sub-functions. This also removes the need to special-case XEN_DOMCTL_getdomaininfo. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/arch/x86/domctl.c | 2 +- xen/common/domctl.c | 32 +++---------------- xen/include/xsm/dummy.h | 16 ++++++++-- xen/xsm/flask/hooks.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 31 deletions(-) diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 9eebd3b..a0ecd95 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1480,7 +1480,7 @@ long arch_do_domctl( { struct domain *d; - ret = rcu_lock_remote_target_domain_by_id(domctl->domain, &d); + ret = rcu_lock_remote_domain_by_id(domctl->domain, &d); if ( ret != 0 ) break; diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 76ced4f..48b5f6f 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -263,27 +263,9 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) return -ESRCH; } - switch ( op->cmd ) - { - case XEN_DOMCTL_ioport_mapping: - case XEN_DOMCTL_memory_mapping: - case XEN_DOMCTL_bind_pt_irq: - case XEN_DOMCTL_unbind_pt_irq: { - bool_t is_priv = IS_PRIV_FOR(current->domain, d); - if ( !is_priv ) - { - ret = -EPERM; - goto domctl_out_unlock; - } - break; - } - case XEN_DOMCTL_getdomaininfo: - break; - default: - if ( !IS_PRIV(current->domain) ) - return -EPERM; - break; - } + ret = xsm_domctl(d, op->cmd); + if ( ret ) + goto domctl_out_unlock; if ( !domctl_lock_acquire() ) { @@ -857,17 +839,13 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) case XEN_DOMCTL_subscribe: { - ret = xsm_domctl(d, op->cmd); - if ( !ret ) - d->suspend_evtchn = op->u.subscribe.port; + d->suspend_evtchn = op->u.subscribe.port; } break; case XEN_DOMCTL_disable_migrate: { - ret = xsm_domctl(d, op->cmd); - if ( !ret ) - d->disable_migrate = op->u.disable_migrate.disable; + d->disable_migrate = op->u.disable_migrate.disable; } break; diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 3f0a6d8..6aa6aea 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -64,8 +64,6 @@ static XSM_DEFAULT(int, scheduler) (struct domain *d) static XSM_DEFAULT(int, getdomaininfo) (struct domain *d) { - if ( !IS_PRIV(current->domain) ) - return -EPERM; return 0; } @@ -91,6 +89,20 @@ static XSM_DEFAULT(int, set_target) (struct domain *d, struct domain *e) static XSM_DEFAULT(int, domctl)(struct domain *d, int cmd) { + switch ( cmd ) + { + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: { + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + break; + } + default: + if ( !IS_PRIV(current->domain) ) + return -EPERM; + } return 0; } diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 1cbf2f2..6d03189 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -589,7 +589,90 @@ static int flask_set_target(struct domain *d, struct domain *e) static int flask_domctl(struct domain *d, int cmd) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO); + switch ( cmd ) + { + /* These have individual XSM hooks (common/domctl.c) */ + case XEN_DOMCTL_createdomain: + case XEN_DOMCTL_destroydomain: + case XEN_DOMCTL_pausedomain: + case XEN_DOMCTL_unpausedomain: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_setvcpuaffinity: + case XEN_DOMCTL_max_mem: + case XEN_DOMCTL_setvcpucontext: + case XEN_DOMCTL_getvcpucontext: + case XEN_DOMCTL_getvcpuinfo: + case XEN_DOMCTL_max_vcpus: + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_setdomainhandle: + case XEN_DOMCTL_setdebugging: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_settimeoffset: + case XEN_DOMCTL_getvcpuaffinity: + case XEN_DOMCTL_resumedomain: + case XEN_DOMCTL_set_target: + case XEN_DOMCTL_set_virq_handler: +#ifdef CONFIG_X86 + /* These have individual XSM hooks (arch/x86/domctl.c) */ + case XEN_DOMCTL_shadow_op: + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_getpageframeinfo: + case XEN_DOMCTL_getpageframeinfo2: + case XEN_DOMCTL_getpageframeinfo3: + case XEN_DOMCTL_getmemlist: + case XEN_DOMCTL_hypercall_init: + case XEN_DOMCTL_sethvmcontext: + case XEN_DOMCTL_gethvmcontext: + case XEN_DOMCTL_gethvmcontext_partial: + case XEN_DOMCTL_set_address_size: + case XEN_DOMCTL_get_address_size: + case XEN_DOMCTL_set_machine_address_size: + case XEN_DOMCTL_get_machine_address_size: + case XEN_DOMCTL_sendtrigger: + case XEN_DOMCTL_bind_pt_irq: + case XEN_DOMCTL_unbind_pt_irq: + case XEN_DOMCTL_memory_mapping: + case XEN_DOMCTL_ioport_mapping: + case XEN_DOMCTL_pin_mem_cacheattr: + case XEN_DOMCTL_set_ext_vcpucontext: + case XEN_DOMCTL_get_ext_vcpucontext: + case XEN_DOMCTL_setvcpuextstate: + case XEN_DOMCTL_getvcpuextstate: + case XEN_DOMCTL_mem_event_op: + case XEN_DOMCTL_mem_sharing_op: + case XEN_DOMCTL_set_access_required: + /* These have individual XSM hooks (drivers/passthrough/iommu.c) */ + case XEN_DOMCTL_get_device_group: + case XEN_DOMCTL_test_assign_device: + case XEN_DOMCTL_assign_device: + case XEN_DOMCTL_deassign_device: +#endif + return 0; + + case XEN_DOMCTL_subscribe: + case XEN_DOMCTL_disable_migrate: + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, + DOMAIN__SET_MISC_INFO); + + case XEN_DOMCTL_set_cpuid: + case XEN_DOMCTL_suppress_spurious_page_faults: + case XEN_DOMCTL_debug_op: + case XEN_DOMCTL_gettscinfo: + case XEN_DOMCTL_settscinfo: + case XEN_DOMCTL_audit_p2m: + case XEN_DOMCTL_gdbsx_guestmemio: + case XEN_DOMCTL_gdbsx_pausevcpu: + case XEN_DOMCTL_gdbsx_unpausevcpu: + case XEN_DOMCTL_gdbsx_domstatus: + /* TODO add per-subfunction hooks */ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; + default: + printk("flask_domctl: Unknown op %d\n", cmd); + return -EPERM; + } } static int flask_set_virq_handler(struct domain *d, uint32_t virq) -- 1.7.11.4
The xsm_sysctl hook now covers every sysctl, in addition to the more fine-grained XSM hooks in most sub-functions. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/common/sysctl.c | 7 ++++--- xen/include/xsm/dummy.h | 7 +++++++ xen/include/xsm/xsm.h | 6 ++++++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index ea68278..e009baa 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -33,15 +33,16 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) struct xen_sysctl curop, *op = &curop; static DEFINE_SPINLOCK(sysctl_lock); - if ( !IS_PRIV(current->domain) ) - return -EPERM; - if ( copy_from_guest(op, u_sysctl, 1) ) return -EFAULT; if ( op->interface_version != XEN_SYSCTL_INTERFACE_VERSION ) return -EACCES; + ret = xsm_sysctl(op->cmd); + if ( ret ) + return ret; + /* * Trylock here avoids deadlock with an existing sysctl critical section * which might (for some current or future reason) want to synchronise diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 6aa6aea..a9784f5 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -106,6 +106,13 @@ static XSM_DEFAULT(int, domctl)(struct domain *d, int cmd) return 0; } +static XSM_DEFAULT(int, sysctl)(int cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, set_virq_handler)(struct domain *d, uint32_t virq) { return 0; diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 171acb2..ef3329f 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -58,6 +58,7 @@ struct xsm_operations { int (*domain_settime) (struct domain *d); int (*set_target) (struct domain *d, struct domain *e); int (*domctl) (struct domain *d, int cmd); + int (*sysctl) (int cmd); int (*set_virq_handler) (struct domain *d, uint32_t virq); int (*tbufcontrol) (void); int (*readconsole) (uint32_t clear); @@ -265,6 +266,11 @@ static inline int xsm_domctl (struct domain *d, int cmd) return xsm_ops->domctl(d, cmd); } +static inline int xsm_sysctl (int cmd) +{ + return xsm_ops->sysctl(cmd); +} + static inline int xsm_set_virq_handler (struct domain *d, uint32_t virq) { return xsm_ops->set_virq_handler(d, virq); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 7f9c753..c76212d 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -44,6 +44,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, domain_settime); set_to_dummy_if_null(ops, set_target); set_to_dummy_if_null(ops, domctl); + set_to_dummy_if_null(ops, sysctl); set_to_dummy_if_null(ops, set_virq_handler); set_to_dummy_if_null(ops, tbufcontrol); set_to_dummy_if_null(ops, readconsole); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6d03189..16af92b 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -675,6 +675,36 @@ static int flask_domctl(struct domain *d, int cmd) } } +static int flask_sysctl(int cmd) +{ + switch ( cmd ) + { + /* These have individual XSM hooks */ + case XEN_SYSCTL_readconsole: + case XEN_SYSCTL_tbuf_op: + case XEN_SYSCTL_physinfo: + case XEN_SYSCTL_sched_id: + case XEN_SYSCTL_perfc_op: + case XEN_SYSCTL_getdomaininfolist: + case XEN_SYSCTL_debug_keys: + case XEN_SYSCTL_getcpuinfo: + case XEN_SYSCTL_availheap: + case XEN_SYSCTL_get_pmstat: + case XEN_SYSCTL_cpu_hotplug: + case XEN_SYSCTL_pm_op: + case XEN_SYSCTL_page_offline_op: + case XEN_SYSCTL_lockprof_op: + case XEN_SYSCTL_topologyinfo: + case XEN_SYSCTL_numainfo: + case XEN_SYSCTL_cpupool_op: + case XEN_SYSCTL_scheduler_op: + return 0; + default: + printk("flask_sysctl: Unknown op %d\n", cmd); + return -EPERM; + } +} + static int flask_set_virq_handler(struct domain *d, uint32_t virq) { return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER); @@ -1601,6 +1631,7 @@ static struct xsm_operations flask_ops = { .domain_settime = flask_domain_settime, .set_target = flask_set_target, .domctl = flask_domctl, + .sysctl = flask_sysctl, .set_virq_handler = flask_set_virq_handler, .tbufcontrol = flask_tbufcontrol, .readconsole = flask_readconsole, -- 1.7.11.4
The FLASK module was missing implementations of some hooks and did not have access vectors defined for 10 domctls; define these now. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/access_vectors | 5 ++ tools/flask/policy/policy/modules/xen/xen.if | 4 +- xen/xsm/flask/hooks.c | 66 +++++++++++++++++++++----- xen/xsm/flask/include/av_perm_to_string.h | 5 ++ xen/xsm/flask/include/av_permissions.h | 5 ++ 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 11d02da..ea65e45 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -80,6 +80,9 @@ class domain2 relabelself make_priv_for set_as_target + set_cpuid + gettsc + settsc } class hvm @@ -97,6 +100,8 @@ class hvm hvmctl mem_event mem_sharing + audit_p2m + send_irq } class event diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index 2ad11b2..59ba171 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -29,6 +29,7 @@ define(`create_domain_common'', ` getdomaininfo hypercall setvcpucontext setextvcpucontext scheduler getvcpuinfo getvcpuextstate getaddrsize getvcpuaffinity setvcpuaffinity }; + allow $1 $2:domain2 { set_cpuid settsc }; allow $1 $2:security check_context; allow $1 $2:shadow enable; allow $1 $2:mmu {map_read map_write adjust memorymap physmap pinpage}; @@ -67,6 +68,7 @@ define(`migrate_domain_out'', ` allow $1 $2:hvm { gethvmc getparam irqlevel }; allow $1 $2:mmu { stat pageinfo map_read }; allow $1 $2:domain { getaddrsize getvcpucontext getextvcpucontext getvcpuextstate pause destroy }; + allow $1 $2:domain2 gettsc; '') ################################################################################ @@ -112,7 +114,7 @@ define(`device_model'', ` domain_comms($1, $2) allow $1 $2:domain { set_target shutdown }; allow $1 $2:mmu { map_read map_write adjust physmap }; - allow $1 $2:hvm { getparam setparam trackdirtyvram hvmctl irqlevel pciroute }; + allow $1 $2:hvm { getparam setparam trackdirtyvram hvmctl irqlevel pciroute cacheattr send_irq }; '') ################################################################################ # diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 16af92b..3cb814d 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -650,25 +650,32 @@ static int flask_domctl(struct domain *d, int cmd) #endif return 0; + case XEN_DOMCTL_debug_op: + case XEN_DOMCTL_gdbsx_guestmemio: + case XEN_DOMCTL_gdbsx_pausevcpu: + case XEN_DOMCTL_gdbsx_unpausevcpu: + case XEN_DOMCTL_gdbsx_domstatus: + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, + DOMAIN__SETDEBUGGING); + case XEN_DOMCTL_subscribe: case XEN_DOMCTL_disable_migrate: + case XEN_DOMCTL_suppress_spurious_page_faults: return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO); case XEN_DOMCTL_set_cpuid: - case XEN_DOMCTL_suppress_spurious_page_faults: - case XEN_DOMCTL_debug_op: + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); + case XEN_DOMCTL_gettscinfo: + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); + case XEN_DOMCTL_settscinfo: + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); + case XEN_DOMCTL_audit_p2m: - case XEN_DOMCTL_gdbsx_guestmemio: - case XEN_DOMCTL_gdbsx_pausevcpu: - case XEN_DOMCTL_gdbsx_unpausevcpu: - case XEN_DOMCTL_gdbsx_domstatus: - /* TODO add per-subfunction hooks */ - if ( !IS_PRIV(current->domain) ) - return -EPERM; - return 0; + return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__AUDIT_P2M); + default: printk("flask_domctl: Unknown op %d\n", cmd); return -EPERM; @@ -919,6 +926,11 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data); } +static int flask_iomem_mapping(struct domain *d, uint64_t start, uint64_t end, uint8_t access) +{ + return flask_iomem_permission(d, start, end, access); +} + static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) { u32 rsid; @@ -1126,7 +1138,6 @@ static int _ioport_has_perm(void *v, u32 sid, unsigned long start, unsigned long return avc_has_perm(data->tsec->sid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } - static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t end, uint8_t access) { int rc; @@ -1149,6 +1160,11 @@ static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t en return security_iterate_ioport_sids(start, end, _ioport_has_perm, &data); } +static int flask_ioport_mapping(struct domain *d, uint32_t start, uint32_t end, uint8_t access) +{ + return flask_ioport_permission(d, start, end, access); +} + static int flask_getpageframeinfo(struct domain *d) { return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGEINFO); @@ -1207,6 +1223,25 @@ static int flask_address_size(struct domain *d, uint32_t cmd) return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm); } +static int flask_machine_address_size(struct domain *d, uint32_t cmd) +{ + u32 perm; + + switch ( cmd ) + { + case XEN_DOMCTL_set_machine_address_size: + perm = DOMAIN__SETADDRSIZE; + break; + case XEN_DOMCTL_get_machine_address_size: + perm = DOMAIN__GETADDRSIZE; + break; + default: + return -EPERM; + } + + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm); +} + static int flask_hvm_param(struct domain *d, unsigned long op) { u32 perm; @@ -1244,6 +1279,11 @@ static int flask_hvm_set_pci_link_route(struct domain *d) return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCIROUTE); } +static int flask_hvm_inject_msi(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__SEND_IRQ); +} + static int flask_mem_event(struct domain *d) { return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_EVENT); @@ -1687,6 +1727,7 @@ static struct xsm_operations flask_ops = { .unmap_domain_pirq = flask_unmap_domain_pirq, .irq_permission = flask_irq_permission, .iomem_permission = flask_iomem_permission, + .iomem_mapping = flask_iomem_mapping, .pci_config_permission = flask_pci_config_permission, .resource_plug_core = flask_resource_plug_core, @@ -1711,10 +1752,12 @@ static struct xsm_operations flask_ops = { .hypercall_init = flask_hypercall_init, .hvmcontext = flask_hvmcontext, .address_size = flask_address_size, + .machine_address_size = flask_machine_address_size, .hvm_param = flask_hvm_param, .hvm_set_pci_intx_level = flask_hvm_set_pci_intx_level, .hvm_set_isa_irq_level = flask_hvm_set_isa_irq_level, .hvm_set_pci_link_route = flask_hvm_set_pci_link_route, + .hvm_inject_msi = flask_hvm_inject_msi, .mem_event = flask_mem_event, .mem_sharing = flask_mem_sharing, .apic = flask_apic, @@ -1747,6 +1790,7 @@ static struct xsm_operations flask_ops = { .ext_vcpucontext = flask_ext_vcpucontext, .vcpuextstate = flask_vcpuextstate, .ioport_permission = flask_ioport_permission, + .ioport_mapping = flask_ioport_mapping, #endif }; diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 10f8e80..894910c 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -66,6 +66,9 @@ S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, "relabelself") S_(SECCLASS_DOMAIN2, DOMAIN2__MAKE_PRIV_FOR, "make_priv_for") S_(SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET, "set_as_target") + S_(SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID, "set_cpuid") + S_(SECCLASS_DOMAIN2, DOMAIN2__GETTSC, "gettsc") + S_(SECCLASS_DOMAIN2, DOMAIN2__SETTSC, "settsc") S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc") S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc") S_(SECCLASS_HVM, HVM__SETPARAM, "setparam") @@ -79,6 +82,8 @@ S_(SECCLASS_HVM, HVM__HVMCTL, "hvmctl") S_(SECCLASS_HVM, HVM__MEM_EVENT, "mem_event") S_(SECCLASS_HVM, HVM__MEM_SHARING, "mem_sharing") + S_(SECCLASS_HVM, HVM__AUDIT_P2M, "audit_p2m") + S_(SECCLASS_HVM, HVM__SEND_IRQ, "send_irq") S_(SECCLASS_EVENT, EVENT__BIND, "bind") S_(SECCLASS_EVENT, EVENT__SEND, "send") S_(SECCLASS_EVENT, EVENT__STATUS, "status") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index f7cfee1..1bdb515 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -68,6 +68,9 @@ #define DOMAIN2__RELABELSELF 0x00000004UL #define DOMAIN2__MAKE_PRIV_FOR 0x00000008UL #define DOMAIN2__SET_AS_TARGET 0x00000010UL +#define DOMAIN2__SET_CPUID 0x00000020UL +#define DOMAIN2__GETTSC 0x00000040UL +#define DOMAIN2__SETTSC 0x00000080UL #define HVM__SETHVMC 0x00000001UL #define HVM__GETHVMC 0x00000002UL @@ -82,6 +85,8 @@ #define HVM__HVMCTL 0x00000400UL #define HVM__MEM_EVENT 0x00000800UL #define HVM__MEM_SHARING 0x00001000UL +#define HVM__AUDIT_P2M 0x00002000UL +#define HVM__SEND_IRQ 0x00004000UL #define EVENT__BIND 0x00000001UL #define EVENT__SEND 0x00000002UL -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 17/22] xsm/flask: add distinct SIDs for self/target access
Because the FLASK XSM module no longer checks IS_PRIV for remote domain accesses covered by XSM permissions, domains now have the ability to perform memory management and other functions on all domains that have the same type. While it is possible to prevent this by only creating one domain per type, this solution significantly limits the flexibility of the type system. This patch introduces a domain type transition to represent a domain that is operating on itself. In the example policy, this is demonstrated by creating a type with _self appended when declaring a domain type which will be used for reflexive operations. AVCs for a domain of type domU_t will look like the following: scontext=system_u:system_r:domU_t tcontext=system_u:system_r:domU_t_self This change also allows policy to distinguish between event channels a domain creates to itself and event channels created between domains of the same type. The IS_PRIV_FOR check used for device model domains is also no longer checked by FLASK; a similar transition is performed when the target is set and used when the device model accesses its target domain. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- docs/misc/xsm-flask.txt | 43 ++- tools/flask/policy/policy/modules/xen/xen.if | 60 +++- tools/flask/policy/policy/modules/xen/xen.te | 13 +- xen/xsm/flask/flask_op.c | 9 + xen/xsm/flask/hooks.c | 422 +++++++++++++-------------- xen/xsm/flask/include/objsec.h | 2 + 6 files changed, 307 insertions(+), 242 deletions(-) diff --git a/docs/misc/xsm-flask.txt b/docs/misc/xsm-flask.txt index 0778a28..ff81b01 100644 --- a/docs/misc/xsm-flask.txt +++ b/docs/misc/xsm-flask.txt @@ -68,9 +68,43 @@ HVM domains with stubdomain device models use two types (one per domain): - dm_dom_t is the device model for a domain with type domHVM_t One disadvantage of using type enforcement to enforce isolation is that a new -type is needed for each group of domains. In addition, it is not possible to -allow isolated_domU_t cannot to create loopback event channels without allowing -two domains of type isolated_domU_t to communicate with one another. +type is needed for each group of domains. The user field can be used to address +this for the most common case of groups that can communicate internally but not +externally; see "Users and roles" below. + +Type transitions +---------------- + +Xen defines a number of operations such as memory mapping that are necessary for +a domain to perform on itself, but are also undesirable to allow a domain to +perform on every other domain of the same label. While it is possible to address +this by only creating one domain per type, this solution significantly limits +the flexibility of the type system. Another method to address this issue is to +duplicate the permission names for every operation that can be performed on the +current domain or on other domains; however, this significantly increases the +necessary number of permissions and complicates the XSM hooks. Instead, this is +addressed by allowing a distinct type to be used for a domain''s access to +itself. The same applies for a device model domain''s access to its designated +target, allowing the IS_PRIV_FOR checks used in Xen''s DAC model to be +implemented in FLASK. + +Upon domain creation (or relabel), a type transition is computed using the +domain''s label as the source and target. The result of this computation is used +as the target when the domain accesses itself. In the example policy, this +computed type is the result of appending _self to a domain''s type: domU_t_self +for domU_t. If no type transition rule exists, the domain will continue to use +its own label for both the source and target. An AVC message will look like: + + scontext=system_u:system_r:domU_t tcontext=system_u:system_r:domU_t_self + +A similar type transition is done when a device model domain is associated with +its target using the set_target operation. The transition is computed with the +target domain as the source and the device model domain as the target: this +ordering was chosen in order to preserve the original label for the target when +no type transition rule exists. In the example policy, these computed types are +the result of appending _target to the domain. + +Type transitions are also used to compute the labels of event channels. Users and roles --------------- @@ -84,7 +118,8 @@ the customer_1 user. Access control rules involving users and roles are defined in the policy constraints file (tools/flask/policy/policy/constraints). The example policy provides constraints that prevent different users from communicating using -grants or event channels, while still allowing communication with dom0. +grants or event channels, while still allowing communication with the system_u +user where dom0 resides. Resource Policy --------------- diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index 59ba171..d630f47 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -5,15 +5,34 @@ # Domain creation and setup # ################################################################################ +define(`declare_domain_common'', ` + allow $1 $2:grant { query setup }; + allow $1 $2:mmu { adjust physmap map_read map_write stat pinpage updatemp }; + allow $1 $2:hvm { getparam setparam }; +'') + # declare_domain(type, attrs...) -# Declare a type as a domain type, and allow basic domain setup +# Declare a domain type, along with associated _self and _channel types +# Allow the domain to perform basic operations on itself define(`declare_domain'', ` type $1, domain_type`''ifelse(`$#'', `1'', `'', `,shift($@)''); + type $1_self, domain_type, domain_self_type; + type_transition $1 $1:domain $1_self; + type $1_channel, event_type; + type_transition $1 domain_type:event $1_channel; + declare_domain_common($1, $1_self) +'') + +# declare_singleton_domain(type, attrs...) +# Declare a domain type and associated _channel types. +# Note: Because the domain can perform basic operations on itself and any +# other domain of the same type, this constructor should be used for types +# containing at most one domain. This is not enforced by policy. +define(`declare_singleton_domain'', ` + type $1, domain_type`''ifelse(`$#'', `1'', `'', `,shift($@)''); type $1_channel, event_type; type_transition $1 domain_type:event $1_channel; - allow $1 $1:grant { query setup }; - allow $1 $1:mmu { adjust physmap map_read map_write stat pinpage }; - allow $1 $1:hvm { getparam setparam }; + declare_domain_common($1, $1) '') # declare_build_label(type) @@ -51,6 +70,7 @@ define(`create_domain_build_label'', ` allow $1 $2_channel:event create; allow $1 $2_building:domain2 relabelfrom; allow $1 $2:domain2 relabelto; + allow $2_building $2:domain transition; '') # manage_domain(priv, target) @@ -101,20 +121,36 @@ define(`domain_comms'', ` '') # domain_self_comms(domain) -# Allow a domain types to communicate with others of its type using grants -# and event channels (this includes event channels to DOMID_SELF) +# Allow a non-singleton domain type to communicate with itself using grants +# and event channels define(`domain_self_comms'', ` - create_channel($1, $1, $1_channel) - allow $1 $1:grant { map_read map_write copy unmap }; + create_channel($1, $1_self, $1_channel) + allow $1 $1_self:grant { map_read map_write copy unmap }; '') # device_model(dm_dom, hvm_dom) # Define how a device model domain interacts with its target define(`device_model'', ` - domain_comms($1, $2) - allow $1 $2:domain { set_target shutdown }; - allow $1 $2:mmu { map_read map_write adjust physmap }; - allow $1 $2:hvm { getparam setparam trackdirtyvram hvmctl irqlevel pciroute cacheattr send_irq }; + type $2_target, domain_type, domain_target_type; + type_transition $2 $1:domain $2_target; + allow $1 $2:domain set_target; + + type_transition $2_target domain_type:event $2_channel; + create_channel($1, $2_target, $1_channel) + create_channel($2, $1, $2_channel) + allow $1 $2_channel:event create; + + allow $1 $2_target:domain shutdown; + allow $1 $2_target:mmu { map_read map_write adjust physmap }; + allow $1 $2_target:hvm { getparam setparam trackdirtyvram hvmctl irqlevel pciroute cacheattr send_irq }; +'') + +# make_device_model(priv, dm_dom, hvm_dom) +# Allow creation of a device model and HVM domain pair +define(`make_device_model'', ` + device_model($2, $3) + allow $1 $2:domain2 make_priv_for; + allow $1 $3:domain2 set_as_target; '') ################################################################################ # diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index 1162153..8d33285 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -8,6 +8,8 @@ ################################################################################ attribute xen_type; attribute domain_type; +attribute domain_self_type; +attribute domain_target_type; attribute resource_type; attribute event_type; attribute mls_priv; @@ -25,7 +27,7 @@ attribute mls_priv; type xen_t, xen_type, mls_priv; # Domain 0 -declare_domain(dom0_t, mls_priv); +declare_singleton_domain(dom0_t, mls_priv); # Untracked I/O memory (pseudo-domain) type domio_t, xen_type; @@ -69,7 +71,7 @@ admin_device(dom0_t, ioport_t) admin_device(dom0_t, iomem_t) allow dom0_t domio_t:mmu { map_read map_write }; -domain_self_comms(dom0_t) +domain_comms(dom0_t, dom0_t) auditallow dom0_t security_t:security { load_policy setenforce setbool }; @@ -84,11 +86,14 @@ domain_self_comms(domU_t) create_domain(dom0_t, domU_t) manage_domain(dom0_t, domU_t) domain_comms(dom0_t, domU_t) +domain_comms(domU_t, domU_t) +domain_self_comms(domU_t) declare_domain(isolated_domU_t) create_domain(dom0_t, isolated_domU_t) manage_domain(dom0_t, isolated_domU_t) domain_comms(dom0_t, isolated_domU_t) +domain_self_comms(isolated_domU_t) # Declare a boolean that denies creation of prot_domU_t domains gen_bool(prot_doms_locked, false) @@ -98,6 +103,8 @@ if (!prot_doms_locked) { } domain_comms(dom0_t, prot_domU_t) domain_comms(domU_t, prot_domU_t) +domain_comms(prot_domU_t, prot_domU_t) +domain_self_comms(prot_domU_t) # domHVM_t is meant to be paired with a qemu-dm stub domain of type dm_dom_t declare_domain(domHVM_t) @@ -110,7 +117,7 @@ declare_domain(dm_dom_t) create_domain(dom0_t, dm_dom_t) manage_domain(dom0_t, dm_dom_t) domain_comms(dom0_t, dm_dom_t) -device_model(dm_dom_t, domHVM_t) +make_device_model(dom0_t, dm_dom_t, domHVM_t) # nomigrate_t must be built via the nomigrate_t_building label; once built, # dom0 cannot read its memory. diff --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c index 9c8dfe7..f8fc108 100644 --- a/xen/xsm/flask/flask_op.c +++ b/xen/xsm/flask/flask_op.c @@ -612,6 +612,15 @@ static int flask_relabel_domain(struct xen_flask_relabel *arg) goto out; dsec->sid = arg->sid; + dsec->self_sid = arg->sid; + security_transition_sid(dsec->sid, dsec->sid, SECCLASS_DOMAIN, + &dsec->self_sid); + if ( d->target ) + { + struct domain_security_struct *tsec = d->target->ssid; + security_transition_sid(tsec->sid, dsec->sid, SECCLASS_DOMAIN, + &dsec->target_sid); + } out: rcu_unlock_domain(d); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 3cb814d..421087f 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -33,38 +33,69 @@ struct xsm_operations *original_ops = NULL; +static u32 domain_sid(struct domain *dom) +{ + struct domain_security_struct *dsec = dom->ssid; + return dsec->sid; +} + +static u32 domain_target_sid(struct domain *src, struct domain *dst) +{ + struct domain_security_struct *ssec = src->ssid; + struct domain_security_struct *dsec = dst->ssid; + if (src == dst) + return ssec->self_sid; + if (src->target == dst) + return ssec->target_sid; + return dsec->sid; +} + +static u32 evtchn_sid(const struct evtchn *chn) +{ + struct evtchn_security_struct *esec = chn->ssid; + return esec->sid; +} + static int domain_has_perm(struct domain *dom1, struct domain *dom2, u16 class, u32 perms) { - struct domain_security_struct *dsec1, *dsec2; + u32 ssid, tsid; struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad, NONE); ad.sdom = dom1; ad.tdom = dom2; - dsec1 = dom1->ssid; - dsec2 = dom2->ssid; + ssid = domain_sid(dom1); + tsid = domain_target_sid(dom1, dom2); - return avc_has_perm(dsec1->sid, dsec2->sid, class, perms, &ad); + return avc_has_perm(ssid, tsid, class, perms, &ad); } -static int domain_has_evtchn(struct domain *d, struct evtchn *chn, u32 perms) +static int avc_current_has_perm(u32 tsid, u16 class, u32 perm, + struct avc_audit_data *ad) { - struct domain_security_struct *dsec; - struct evtchn_security_struct *esec; + u32 csid = domain_sid(current->domain); + return avc_has_perm(csid, tsid, class, perm, ad); +} - dsec = d->ssid; - esec = chn->ssid; +static int current_has_perm(struct domain *d, u16 class, u32 perms) +{ + return domain_has_perm(current->domain, d, class, perms); +} - return avc_has_perm(dsec->sid, esec->sid, SECCLASS_EVENT, perms, NULL); +static int domain_has_evtchn(struct domain *d, struct evtchn *chn, u32 perms) +{ + u32 dsid = domain_sid(d); + u32 esid = evtchn_sid(chn); + + return avc_has_perm(dsid, esid, SECCLASS_EVENT, perms, NULL); } static int domain_has_xen(struct domain *d, u32 perms) { - struct domain_security_struct *dsec; - dsec = d->ssid; + u32 dsid = domain_sid(d); - return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, perms, NULL); + return avc_has_perm(dsid, SECINITSID_XEN, SECCLASS_XEN, perms, NULL); } static int get_irq_sid(int irq, u32 *sid, struct avc_audit_data *ad) @@ -123,6 +154,7 @@ static int flask_domain_alloc_security(struct domain *d) dsec->sid = SECINITSID_UNLABELED; } + dsec->self_sid = dsec->sid; d->ssid = dsec; return 0; @@ -142,68 +174,55 @@ static void flask_domain_free_security(struct domain *d) static int flask_evtchn_unbound(struct domain *d1, struct evtchn *chn, domid_t id2) { - u32 newsid; + u32 sid1, sid2, newsid; int rc; - domid_t id; struct domain *d2; - struct domain_security_struct *dsec, *dsec1, *dsec2; struct evtchn_security_struct *esec; - dsec = current->domain->ssid; - dsec1 = d1->ssid; - esec = chn->ssid; - - if ( id2 == DOMID_SELF ) - id = current->domain->domain_id; - else - id = id2; - - d2 = get_domain_by_id(id); + d2 = rcu_lock_domain_by_any_id(id2); if ( d2 == NULL ) return -EPERM; - dsec2 = d2->ssid; - rc = security_transition_sid(dsec1->sid, dsec2->sid, SECCLASS_EVENT, - &newsid); + sid1 = domain_sid(d1); + sid2 = domain_target_sid(d1, d2); + esec = chn->ssid; + + rc = security_transition_sid(sid1, sid2, SECCLASS_EVENT, &newsid); if ( rc ) goto out; - rc = avc_has_perm(dsec->sid, newsid, SECCLASS_EVENT, EVENT__CREATE, NULL); + rc = avc_current_has_perm(newsid, SECCLASS_EVENT, EVENT__CREATE, NULL); if ( rc ) goto out; - rc = avc_has_perm(newsid, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL); + rc = avc_has_perm(newsid, sid2, SECCLASS_EVENT, EVENT__BIND, NULL); if ( rc ) goto out; - else - esec->sid = newsid; + + esec->sid = newsid; out: - put_domain(d2); + rcu_unlock_domain(d2); return rc; } static int flask_evtchn_interdomain(struct domain *d1, struct evtchn *chn1, struct domain *d2, struct evtchn *chn2) { - u32 newsid; + u32 sid1, sid2, newsid, reverse_sid; int rc; - struct domain_security_struct *dsec, *dsec1, *dsec2; - struct evtchn_security_struct *esec1, *esec2; + struct evtchn_security_struct *esec1; struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad, NONE); ad.sdom = d1; ad.tdom = d2; - dsec = current->domain->ssid; - dsec1 = d1->ssid; - dsec2 = d2->ssid; + sid1 = domain_sid(d1); + sid2 = domain_target_sid(d1, d2); esec1 = chn1->ssid; - esec2 = chn2->ssid; - rc = security_transition_sid(dsec1->sid, dsec2->sid, - SECCLASS_EVENT, &newsid); + rc = security_transition_sid(sid1, sid2, SECCLASS_EVENT, &newsid); if ( rc ) { printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n", @@ -211,15 +230,20 @@ static int flask_evtchn_interdomain(struct domain *d1, struct evtchn *chn1, return rc; } - rc = avc_has_perm(dsec->sid, newsid, SECCLASS_EVENT, EVENT__CREATE, &ad); + rc = avc_current_has_perm(newsid, SECCLASS_EVENT, EVENT__CREATE, &ad); if ( rc ) return rc; - rc = avc_has_perm(newsid, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, &ad); + rc = avc_has_perm(newsid, sid2, SECCLASS_EVENT, EVENT__BIND, &ad); if ( rc ) return rc; - rc = avc_has_perm(esec2->sid, dsec1->sid, SECCLASS_EVENT, EVENT__BIND, &ad); + /* It''s possible the target domain has changed (relabel or destroy/create) + * since the unbound part was created; re-validate this binding now. + */ + reverse_sid = evtchn_sid(chn2); + sid1 = domain_target_sid(d2, d1); + rc = avc_has_perm(reverse_sid, sid1, SECCLASS_EVENT, EVENT__BIND, &ad); if ( rc ) return rc; @@ -302,7 +326,6 @@ static void flask_free_security_evtchn(struct evtchn *chn) static char *flask_show_security_evtchn(struct domain *d, const struct evtchn *chn) { - struct evtchn_security_struct *esec; int irq; u32 sid = 0; char *ctx; @@ -312,9 +335,7 @@ static char *flask_show_security_evtchn(struct domain *d, const struct evtchn *c { case ECS_UNBOUND: case ECS_INTERDOMAIN: - esec = chn->ssid; - if ( esec ) - sid = esec->sid; + sid = evtchn_sid(chn); break; case ECS_PIRQ: irq = domain_pirq_to_irq(d, chn->u.pirq.irq); @@ -367,12 +388,12 @@ static int flask_grant_query_size(struct domain *d1, struct domain *d2) static int flask_get_pod_target(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__GETPODTARGET); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETPODTARGET); } static int flask_set_pod_target(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SETPODTARGET); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETPODTARGET); } static int flask_memory_adjust_reservation(struct domain *d1, struct domain *d2) @@ -455,70 +476,65 @@ static int flask_schedop_shutdown(struct domain *d1, struct domain *d2) static void flask_security_domaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info) { - struct domain_security_struct *dsec; - - dsec = d->ssid; - info->ssidref = dsec->sid; + info->ssidref = domain_sid(d); } static int flask_setvcpucontext(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SETVCPUCONTEXT); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETVCPUCONTEXT); } static int flask_pausedomain(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__PAUSE); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__PAUSE); } static int flask_unpausedomain(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__UNPAUSE); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__UNPAUSE); } static int flask_resumedomain(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__RESUME); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__RESUME); } static int flask_domain_create(struct domain *d, u32 ssidref) { int rc; - struct domain_security_struct *dsec1; - struct domain_security_struct *dsec2; + struct domain_security_struct *dsec = d->ssid; static int dom0_created = 0; - dsec1 = current->domain->ssid; - dsec2 = d->ssid; - if ( is_idle_domain(current->domain) && !dom0_created ) { - dsec2->sid = SECINITSID_DOM0; + dsec->sid = SECINITSID_DOM0; dom0_created = 1; - return 0; } + else + { + rc = avc_current_has_perm(ssidref, SECCLASS_DOMAIN, + DOMAIN__CREATE, NULL); + if ( rc ) + return rc; - rc = avc_has_perm(dsec1->sid, ssidref, SECCLASS_DOMAIN, - DOMAIN__CREATE, NULL); - if ( rc ) - return rc; + dsec->sid = ssidref; + } + dsec->self_sid = dsec->sid; - dsec2->sid = ssidref; + rc = security_transition_sid(dsec->sid, dsec->sid, SECCLASS_DOMAIN, + &dsec->self_sid); return rc; } static int flask_max_vcpus(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__MAX_VCPUS); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__MAX_VCPUS); } static int flask_destroydomain(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__DESTROY); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__DESTROY); } static int flask_vcpuaffinity(int cmd, struct domain *d) @@ -537,7 +553,7 @@ static int flask_vcpuaffinity(int cmd, struct domain *d) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm ); + return current_has_perm(d, SECCLASS_DOMAIN, perm ); } static int flask_scheduler(struct domain *d) @@ -548,43 +564,51 @@ static int flask_scheduler(struct domain *d) if ( rc ) return rc; - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SCHEDULER); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SCHEDULER); } static int flask_getdomaininfo(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__GETDOMAININFO); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO); } static int flask_getvcpucontext(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__GETVCPUCONTEXT); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETVCPUCONTEXT); } static int flask_getvcpuinfo(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__GETVCPUINFO); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETVCPUINFO); } static int flask_domain_settime(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SETTIME); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETTIME); } -static int flask_set_target(struct domain *d, struct domain *e) +static int flask_set_target(struct domain *d, struct domain *t) { int rc; - rc = domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__MAKE_PRIV_FOR); + struct domain_security_struct *dsec, *tsec; + dsec = d->ssid; + tsec = t->ssid; + + rc = current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__MAKE_PRIV_FOR); if ( rc ) return rc; - rc = domain_has_perm(current->domain, e, SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET); + rc = current_has_perm(t, SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET); if ( rc ) return rc; - return domain_has_perm(d, e, SECCLASS_DOMAIN, DOMAIN__SET_TARGET); + /* Use avc_has_perm to avoid resolving target/current SID */ + rc = avc_has_perm(dsec->sid, tsec->sid, SECCLASS_DOMAIN, DOMAIN__SET_TARGET, NULL); + if ( rc ) + return rc; + + /* (tsec, dsec) defaults the label to tsec, as it should here */ + rc = security_transition_sid(tsec->sid, dsec->sid, SECCLASS_DOMAIN, + &dsec->target_sid); + return rc; } static int flask_domctl(struct domain *d, int cmd) @@ -655,26 +679,24 @@ static int flask_domctl(struct domain *d, int cmd) case XEN_DOMCTL_gdbsx_pausevcpu: case XEN_DOMCTL_gdbsx_unpausevcpu: case XEN_DOMCTL_gdbsx_domstatus: - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SETDEBUGGING); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDEBUGGING); case XEN_DOMCTL_subscribe: case XEN_DOMCTL_disable_migrate: case XEN_DOMCTL_suppress_spurious_page_faults: - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SET_MISC_INFO); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO); case XEN_DOMCTL_set_cpuid: - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); case XEN_DOMCTL_gettscinfo: - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); case XEN_DOMCTL_settscinfo: - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); case XEN_DOMCTL_audit_p2m: - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__AUDIT_P2M); + return current_has_perm(d, SECCLASS_HVM, HVM__AUDIT_P2M); default: printk("flask_domctl: Unknown op %d\n", cmd); @@ -714,7 +736,7 @@ static int flask_sysctl(int cmd) static int flask_set_virq_handler(struct domain *d, uint32_t virq) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER); } static int flask_tbufcontrol(void) @@ -739,20 +761,17 @@ static int flask_sched_id(void) static int flask_setdomainmaxmem(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SETDOMAINMAXMEM); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDOMAINMAXMEM); } static int flask_setdomainhandle(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SETDOMAINHANDLE); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE); } static int flask_setdebugging(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__SETDEBUGGING); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDEBUGGING); } static int flask_debug_keys(void) @@ -814,14 +833,12 @@ static char *flask_show_irq_sid (int irq) static int flask_map_domain_pirq (struct domain *d, int irq, void *data) { - u32 sid; + u32 sid, dsid; int rc = -EPERM; struct msi_info *msi = data; - - struct domain_security_struct *ssec, *tsec; struct avc_audit_data ad; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__ADD); + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); if ( rc ) return rc; @@ -837,14 +854,13 @@ static int flask_map_domain_pirq (struct domain *d, int irq, void *data) if ( rc ) return rc; - ssec = current->domain->ssid; - tsec = d->ssid; + dsid = domain_sid(d); - rc = avc_has_perm(ssec->sid, sid, SECCLASS_RESOURCE, RESOURCE__ADD_IRQ, &ad); + rc = avc_current_has_perm(sid, SECCLASS_RESOURCE, RESOURCE__ADD_IRQ, &ad); if ( rc ) return rc; - rc = avc_has_perm(tsec->sid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); + rc = avc_has_perm(dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); return rc; } @@ -852,16 +868,12 @@ static int flask_unmap_domain_pirq (struct domain *d, int irq) { u32 sid; int rc = -EPERM; - - struct domain_security_struct *ssec; struct avc_audit_data ad; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__REMOVE); + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE); if ( rc ) return rc; - ssec = current->domain->ssid; - if ( irq >= nr_irqs_gsi ) { /* TODO support for MSI here */ return 0; @@ -871,19 +883,19 @@ static int flask_unmap_domain_pirq (struct domain *d, int irq) if ( rc ) return rc; - rc = avc_has_perm(ssec->sid, sid, SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, &ad); + rc = avc_current_has_perm(sid, SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, &ad); return rc; } static int flask_irq_permission (struct domain *d, int pirq, uint8_t access) { /* the PIRQ number is not useful; real IRQ is checked during mapping */ - return domain_has_perm(current->domain, d, SECCLASS_RESOURCE, - resource_to_perm(access)); + return current_has_perm(d, SECCLASS_RESOURCE, resource_to_perm(access)); } struct iomem_has_perm_data { - struct domain_security_struct *ssec, *tsec; + u32 ssid; + u32 dsid; u32 perm; }; @@ -897,12 +909,12 @@ static int _iomem_has_perm(void *v, u32 sid, unsigned long start, unsigned long ad.range.start = start; ad.range.end = end; - rc = avc_has_perm(data->ssec->sid, sid, SECCLASS_RESOURCE, data->perm, &ad); + rc = avc_has_perm(data->ssid, sid, SECCLASS_RESOURCE, data->perm, &ad); if ( rc ) return rc; - return avc_has_perm(data->tsec->sid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); + return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end, uint8_t access) @@ -910,7 +922,7 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end struct iomem_has_perm_data data; int rc; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, + rc = current_has_perm(d, SECCLASS_RESOURCE, resource_to_perm(access)); if ( rc ) return rc; @@ -920,8 +932,8 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end else data.perm = RESOURCE__REMOVE_IOMEM; - data.ssec = current->domain->ssid; - data.tsec = d->ssid; + data.ssid = domain_sid(current->domain); + data.dsid = domain_sid(d); return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data); } @@ -933,10 +945,9 @@ static int flask_iomem_mapping(struct domain *d, uint64_t start, uint64_t end, u static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) { - u32 rsid; + u32 dsid, rsid; int rc = -EPERM; struct avc_audit_data ad; - struct domain_security_struct *ssec; u32 perm = RESOURCE__USE; rc = security_device_sid(machine_bdf, &rsid); @@ -949,33 +960,24 @@ static int flask_pci_config_permission(struct domain *d, uint32_t machine_bdf, u AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; - ssec = d->ssid; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad); + dsid = domain_sid(d); + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, perm, &ad); } static int flask_resource_plug_core(void) { - struct domain_security_struct *ssec; - - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__PLUG, NULL); + return avc_current_has_perm(SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__PLUG, NULL); } static int flask_resource_unplug_core(void) { - struct domain_security_struct *ssec; - - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__UNPLUG, NULL); + return avc_current_has_perm(SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__UNPLUG, NULL); } static int flask_resource_use_core(void) { - struct domain_security_struct *ssec; - - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__USE, NULL); + return avc_current_has_perm(SECINITSID_DOMXEN, SECCLASS_RESOURCE, RESOURCE__USE, NULL); } static int flask_resource_plug_pci(uint32_t machine_bdf) @@ -983,7 +985,6 @@ static int flask_resource_plug_pci(uint32_t machine_bdf) u32 rsid; int rc = -EPERM; struct avc_audit_data ad; - struct domain_security_struct *ssec; rc = security_device_sid(machine_bdf, &rsid); if ( rc ) @@ -991,8 +992,7 @@ static int flask_resource_plug_pci(uint32_t machine_bdf) AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__PLUG, &ad); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__PLUG, &ad); } static int flask_resource_unplug_pci(uint32_t machine_bdf) @@ -1000,7 +1000,6 @@ static int flask_resource_unplug_pci(uint32_t machine_bdf) u32 rsid; int rc = -EPERM; struct avc_audit_data ad; - struct domain_security_struct *ssec; rc = security_device_sid(machine_bdf, &rsid); if ( rc ) @@ -1008,8 +1007,7 @@ static int flask_resource_unplug_pci(uint32_t machine_bdf) AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__UNPLUG, &ad); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__UNPLUG, &ad); } static int flask_resource_setup_pci(uint32_t machine_bdf) @@ -1017,7 +1015,6 @@ static int flask_resource_setup_pci(uint32_t machine_bdf) u32 rsid; int rc = -EPERM; struct avc_audit_data ad; - struct domain_security_struct *ssec; rc = security_device_sid(machine_bdf, &rsid); if ( rc ) @@ -1025,8 +1022,7 @@ static int flask_resource_setup_pci(uint32_t machine_bdf) AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__SETUP, &ad); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__SETUP, &ad); } static int flask_resource_setup_gsi(int gsi) @@ -1034,22 +1030,17 @@ static int flask_resource_setup_gsi(int gsi) u32 rsid; int rc = -EPERM; struct avc_audit_data ad; - struct domain_security_struct *ssec; rc = get_irq_sid(gsi, &rsid, &ad); if ( rc ) return rc; - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__SETUP, &ad); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__SETUP, &ad); } static int flask_resource_setup_misc(void) { - struct domain_security_struct *ssec; - - ssec = current->domain->ssid; - return avc_has_perm(ssec->sid, SECINITSID_XEN, SECCLASS_RESOURCE, RESOURCE__SETUP, NULL); + return avc_current_has_perm(SECINITSID_XEN, SECCLASS_RESOURCE, RESOURCE__SETUP, NULL); } static inline int flask_page_offline(uint32_t cmd) @@ -1112,11 +1103,12 @@ static int flask_shadow_control(struct domain *d, uint32_t op) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_SHADOW, perm); + return current_has_perm(d, SECCLASS_SHADOW, perm); } struct ioport_has_perm_data { - struct domain_security_struct *ssec, *tsec; + u32 ssid; + u32 dsid; u32 perm; }; @@ -1130,12 +1122,12 @@ static int _ioport_has_perm(void *v, u32 sid, unsigned long start, unsigned long ad.range.start = start; ad.range.end = end; - rc = avc_has_perm(data->ssec->sid, sid, SECCLASS_RESOURCE, data->perm, &ad); + rc = avc_has_perm(data->ssid, sid, SECCLASS_RESOURCE, data->perm, &ad); if ( rc ) return rc; - return avc_has_perm(data->tsec->sid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); + return avc_has_perm(data->dsid, sid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t end, uint8_t access) @@ -1143,7 +1135,7 @@ static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t en int rc; struct ioport_has_perm_data data; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, + rc = current_has_perm(d, SECCLASS_RESOURCE, resource_to_perm(access)); if ( rc ) @@ -1154,8 +1146,8 @@ static int flask_ioport_permission(struct domain *d, uint32_t start, uint32_t en else data.perm = RESOURCE__REMOVE_IOPORT; - data.ssec = current->domain->ssid; - data.tsec = d->ssid; + data.ssid = domain_sid(current->domain); + data.dsid = domain_sid(d); return security_iterate_ioport_sids(start, end, _ioport_has_perm, &data); } @@ -1167,18 +1159,17 @@ static int flask_ioport_mapping(struct domain *d, uint32_t start, uint32_t end, static int flask_getpageframeinfo(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGEINFO); + return current_has_perm(d, SECCLASS_MMU, MMU__PAGEINFO); } static int flask_getmemlist(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGELIST); + return current_has_perm(d, SECCLASS_MMU, MMU__PAGELIST); } static int flask_hypercall_init(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, - DOMAIN__HYPERCALL); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__HYPERCALL); } static int flask_hvmcontext(struct domain *d, uint32_t cmd) @@ -1201,7 +1192,7 @@ static int flask_hvmcontext(struct domain *d, uint32_t cmd) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_HVM, perm); + return current_has_perm(d, SECCLASS_HVM, perm); } static int flask_address_size(struct domain *d, uint32_t cmd) @@ -1220,7 +1211,7 @@ static int flask_address_size(struct domain *d, uint32_t cmd) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm); + return current_has_perm(d, SECCLASS_DOMAIN, perm); } static int flask_machine_address_size(struct domain *d, uint32_t cmd) @@ -1261,37 +1252,37 @@ static int flask_hvm_param(struct domain *d, unsigned long op) perm = HVM__HVMCTL; } - return domain_has_perm(current->domain, d, SECCLASS_HVM, perm); + return current_has_perm(d, SECCLASS_HVM, perm); } static int flask_hvm_set_pci_intx_level(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCILEVEL); + return current_has_perm(d, SECCLASS_HVM, HVM__PCILEVEL); } static int flask_hvm_set_isa_irq_level(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__IRQLEVEL); + return current_has_perm(d, SECCLASS_HVM, HVM__IRQLEVEL); } static int flask_hvm_set_pci_link_route(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCIROUTE); + return current_has_perm(d, SECCLASS_HVM, HVM__PCIROUTE); } static int flask_hvm_inject_msi(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__SEND_IRQ); + return current_has_perm(d, SECCLASS_HVM, HVM__SEND_IRQ); } static int flask_mem_event(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_EVENT); + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT); } static int flask_mem_sharing(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_SHARING); + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING); } static int flask_apic(struct domain *d, int cmd) @@ -1353,11 +1344,7 @@ static int flask_physinfo(void) static int flask_platform_quirk(uint32_t quirk) { - struct domain_security_struct *dsec; - dsec = current->domain->ssid; - - return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, - XEN__QUIRK, NULL); + return avc_current_has_perm(SECINITSID_XEN, SECCLASS_XEN, XEN__QUIRK, NULL); } static int flask_platform_op(uint32_t op) @@ -1419,16 +1406,12 @@ static int flask_getidletime(void) static int flask_machine_memory_map(void) { - struct domain_security_struct *dsec; - dsec = current->domain->ssid; - - return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_MMU, - MMU__MEMORYMAP, NULL); + return avc_current_has_perm(SECINITSID_XEN, SECCLASS_MMU, MMU__MEMORYMAP, NULL); } static int flask_domain_memory_map(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__MEMORYMAP); + return current_has_perm(d, SECCLASS_MMU, MMU__MEMORYMAP); } static int domain_memory_perm(struct domain *d, struct domain *f, l1_pgentry_t pte) @@ -1451,17 +1434,17 @@ static int domain_memory_perm(struct domain *d, struct domain *f, l1_pgentry_t p if ( f->domain_id == DOMID_IO || !mfn_valid(fmfn) ) { struct avc_audit_data ad; - struct domain_security_struct *dsec = d->ssid; - u32 fsid; + u32 dsid, fsid; + rc = security_iomem_sid(fmfn, &fsid); + if ( rc ) + return rc; AVC_AUDIT_DATA_INIT(&ad, MEMORY); ad.sdom = d; ad.tdom = f; ad.memory.pte = pte.l1; ad.memory.mfn = fmfn; - rc = security_iomem_sid(fmfn, &fsid); - if ( rc ) - return rc; - return avc_has_perm(dsec->sid, fsid, SECCLASS_MMU, map_perms, &ad); + dsid = domain_sid(d); + return avc_has_perm(dsid, fsid, SECCLASS_MMU, map_perms, &ad); } return domain_has_perm(d, f, SECCLASS_MMU, map_perms); @@ -1504,43 +1487,40 @@ static int flask_remove_from_physmap(struct domain *d1, struct domain *d2) static int flask_sendtrigger(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__TRIGGER); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__TRIGGER); } static int flask_get_device_group(uint32_t machine_bdf) { u32 rsid; int rc = -EPERM; - struct domain_security_struct *ssec = current->domain->ssid; rc = security_device_sid(machine_bdf, &rsid); if ( rc ) return rc; - return avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); } static int flask_test_assign_device(uint32_t machine_bdf) { u32 rsid; int rc = -EPERM; - struct domain_security_struct *ssec = current->domain->ssid; rc = security_device_sid(machine_bdf, &rsid); if ( rc ) return rc; - return rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL); } static int flask_assign_device(struct domain *d, uint32_t machine_bdf) { - u32 rsid; + u32 dsid, rsid; int rc = -EPERM; - struct domain_security_struct *ssec, *tsec; struct avc_audit_data ad; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__ADD); + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); if ( rc ) return rc; @@ -1550,22 +1530,20 @@ static int flask_assign_device(struct domain *d, uint32_t machine_bdf) AVC_AUDIT_DATA_INIT(&ad, DEV); ad.device = (unsigned long) machine_bdf; - ssec = current->domain->ssid; - rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__ADD_DEVICE, &ad); + rc = avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__ADD_DEVICE, &ad); if ( rc ) return rc; - tsec = d->ssid; - return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); + dsid = domain_sid(d); + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } static int flask_deassign_device(struct domain *d, uint32_t machine_bdf) { u32 rsid; int rc = -EPERM; - struct domain_security_struct *ssec = current->domain->ssid; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__REMOVE); + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE); if ( rc ) return rc; @@ -1573,18 +1551,17 @@ static int flask_deassign_device(struct domain *d, uint32_t machine_bdf) if ( rc ) return rc; - return rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__REMOVE_DEVICE, NULL); + return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__REMOVE_DEVICE, NULL); } static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - u32 rsid; + u32 dsid, rsid; int rc = -EPERM; int irq; - struct domain_security_struct *ssec, *tsec; struct avc_audit_data ad; - rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__ADD); + rc = current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__ADD); if ( rc ) return rc; @@ -1594,23 +1571,22 @@ static int flask_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *b if ( rc ) return rc; - ssec = current->domain->ssid; - rc = avc_has_perm(ssec->sid, rsid, SECCLASS_HVM, HVM__BIND_IRQ, &ad); + rc = avc_current_has_perm(rsid, SECCLASS_HVM, HVM__BIND_IRQ, &ad); if ( rc ) return rc; - tsec = d->ssid; - return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); + dsid = domain_sid(d); + return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, RESOURCE__USE, &ad); } static int flask_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) { - return domain_has_perm(current->domain, d, SECCLASS_RESOURCE, RESOURCE__REMOVE); + return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__REMOVE); } static int flask_pin_mem_cacheattr (struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__CACHEATTR); + return current_has_perm(d, SECCLASS_HVM, HVM__CACHEATTR); } static int flask_ext_vcpucontext (struct domain *d, uint32_t cmd) @@ -1629,7 +1605,7 @@ static int flask_ext_vcpucontext (struct domain *d, uint32_t cmd) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm); + return current_has_perm(d, SECCLASS_DOMAIN, perm); } static int flask_vcpuextstate (struct domain *d, uint32_t cmd) @@ -1648,7 +1624,7 @@ static int flask_vcpuextstate (struct domain *d, uint32_t cmd) return -EPERM; } - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm); + return current_has_perm(d, SECCLASS_DOMAIN, perm); } #endif diff --git a/xen/xsm/flask/include/objsec.h b/xen/xsm/flask/include/objsec.h index 4ff52be..6595dc3 100644 --- a/xen/xsm/flask/include/objsec.h +++ b/xen/xsm/flask/include/objsec.h @@ -19,6 +19,8 @@ struct domain_security_struct { u32 sid; /* current SID */ + u32 self_sid; /* SID for target when operating on DOMID_SELF */ + u32 target_sid; /* SID for device model target domain */ }; struct evtchn_security_struct { -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 18/22] arch/x86: Add missing mem_sharing XSM hooks
This patch adds splits up the mem_sharing and mem_event XSM hooks to better cover what the code is doing. It also completes the support for arch-specific domctls in FLASK. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> Cc: Tim Deegan <tim@xen.org> --- tools/flask/policy/policy/flask/access_vectors | 1 + xen/arch/x86/domctl.c | 8 ++--- xen/arch/x86/mm/mem_event.c | 45 +++++++++----------------- xen/arch/x86/mm/mem_sharing.c | 25 +++++++++++--- xen/include/asm-x86/mem_event.h | 1 - xen/include/xsm/dummy.h | 23 ++++++++++++- xen/include/xsm/xsm.h | 24 ++++++++++++-- xen/xsm/dummy.c | 5 ++- xen/xsm/flask/hooks.c | 25 ++++++++++++-- xen/xsm/flask/include/av_perm_to_string.h | 1 + xen/xsm/flask/include/av_permissions.h | 1 + 11 files changed, 113 insertions(+), 46 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index ea65e45..45ac437 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -102,6 +102,7 @@ class hvm mem_sharing audit_p2m send_irq + share_mem } class event diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index a0ecd95..4a188e5 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1449,10 +1449,8 @@ long arch_do_domctl( d = rcu_lock_domain_by_id(domctl->domain); if ( d != NULL ) { - ret = xsm_mem_event(d); - if ( !ret ) - ret = mem_event_domctl(d, &domctl->u.mem_event_op, - guest_handle_cast(u_domctl, void)); + ret = mem_event_domctl(d, &domctl->u.mem_event_op, + guest_handle_cast(u_domctl, void)); rcu_unlock_domain(d); copy_to_guest(u_domctl, domctl, 1); } @@ -1508,7 +1506,7 @@ long arch_do_domctl( d = rcu_lock_domain_by_id(domctl->domain); if ( d != NULL ) { - ret = xsm_mem_event(d); + ret = xsm_mem_event_setup(d); if ( !ret ) { p2m = p2m_get_hostp2m(d); p2m->access_required = domctl->u.access_required.access_required; diff --git a/xen/arch/x86/mm/mem_event.c b/xen/arch/x86/mm/mem_event.c index d728889..d574541 100644 --- a/xen/arch/x86/mm/mem_event.c +++ b/xen/arch/x86/mm/mem_event.c @@ -29,6 +29,7 @@ #include <asm/mem_paging.h> #include <asm/mem_access.h> #include <asm/mem_sharing.h> +#include <xsm/xsm.h> /* for public/io/ring.h macros */ #define xen_mb() mb() @@ -439,34 +440,22 @@ static void mem_sharing_notification(struct vcpu *v, unsigned int port) mem_sharing_sharing_resume(v->domain); } -struct domain *get_mem_event_op_target(uint32_t domain, int *rc) -{ - struct domain *d; - - /* Get the target domain */ - *rc = rcu_lock_remote_target_domain_by_id(domain, &d); - if ( *rc != 0 ) - return NULL; - - /* Not dying? */ - if ( d->is_dying ) - { - rcu_unlock_domain(d); - *rc = -EINVAL; - return NULL; - } - - return d; -} - int do_mem_event_op(int op, uint32_t domain, void *arg) { int ret; struct domain *d; - d = get_mem_event_op_target(domain, &ret); + d = rcu_lock_domain_by_any_id(domain); if ( !d ) - return ret; + return -ESRCH; + + ret = -EINVAL; + if ( d->is_dying || d == current->domain ) + goto out; + + ret = xsm_mem_event_op(d, op); + if ( ret ) + goto out; switch (op) { @@ -483,6 +472,7 @@ int do_mem_event_op(int op, uint32_t domain, void *arg) ret = -ENOSYS; } + out: rcu_unlock_domain(d); return ret; } @@ -516,6 +506,10 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, { int rc; + rc = xsm_mem_event_control(d, mec->mode, mec->op); + if ( rc ) + return rc; + if ( unlikely(d == current->domain) ) { gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n"); @@ -537,13 +531,6 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, return -EINVAL; } - /* TODO: XSM hook */ -#if 0 - rc = xsm_mem_event_control(d, mec->op); - if ( rc ) - return rc; -#endif - rc = -ENOSYS; switch ( mec->mode ) diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index 5103285..eff8ae5 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -34,6 +34,7 @@ #include <asm/atomic.h> #include <xen/rcupdate.h> #include <asm/event.h> +#include <xsm/xsm.h> #include "mm-locks.h" @@ -1345,11 +1346,19 @@ int mem_sharing_memop(struct domain *d, xen_mem_sharing_op_t *mec) if ( !mem_sharing_enabled(d) ) return -EINVAL; - cd = get_mem_event_op_target(mec->u.share.client_domain, &rc); + cd = rcu_lock_domain_by_any_id(mec->u.share.client_domain); if ( !cd ) + return -ESRCH; + + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); return rc; + } - if ( !mem_sharing_enabled(cd) ) + if ( cd == current->domain || cd->is_dying || + !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); return -EINVAL; @@ -1401,11 +1410,19 @@ int mem_sharing_memop(struct domain *d, xen_mem_sharing_op_t *mec) if ( !mem_sharing_enabled(d) ) return -EINVAL; - cd = get_mem_event_op_target(mec->u.share.client_domain, &rc); + cd = rcu_lock_domain_by_any_id(mec->u.share.client_domain); if ( !cd ) + return -ESRCH; + + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); return rc; + } - if ( !mem_sharing_enabled(cd) ) + if ( cd == current->domain || cd->is_dying || + !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); return -EINVAL; diff --git a/xen/include/asm-x86/mem_event.h b/xen/include/asm-x86/mem_event.h index 23d71c1..448be4f 100644 --- a/xen/include/asm-x86/mem_event.h +++ b/xen/include/asm-x86/mem_event.h @@ -62,7 +62,6 @@ void mem_event_put_request(struct domain *d, struct mem_event_domain *med, int mem_event_get_response(struct domain *d, struct mem_event_domain *med, mem_event_response_t *rsp); -struct domain *get_mem_event_op_target(uint32_t domain, int *rc); int do_mem_event_op(int op, uint32_t domain, void *arg); int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, XEN_GUEST_HANDLE(void) u_domctl); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index a9784f5..1760cd9 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -551,16 +551,37 @@ static XSM_DEFAULT(int, hvm_inject_msi) (struct domain *d) return 0; } -static XSM_DEFAULT(int, mem_event) (struct domain *d) +static XSM_DEFAULT(int, mem_event_setup) (struct domain *d) { return 0; } +static XSM_DEFAULT(int, mem_event_control) (struct domain *d, int mode, int op) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, mem_event_op) (struct domain *d, int op) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, mem_sharing) (struct domain *d) { return 0; } +static XSM_DEFAULT(int, mem_sharing_op) (struct domain *d, struct domain *cd, int op) +{ + if ( !IS_PRIV_FOR(current->domain, cd) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, apic) (struct domain *d, int cmd) { if ( !IS_PRIV(d) ) diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index ef3329f..c2c1efa 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -151,8 +151,11 @@ struct xsm_operations { int (*hvm_set_isa_irq_level) (struct domain *d); int (*hvm_set_pci_link_route) (struct domain *d); int (*hvm_inject_msi) (struct domain *d); - int (*mem_event) (struct domain *d); + int (*mem_event_setup) (struct domain *d); + int (*mem_event_control) (struct domain *d, int mode, int op); + int (*mem_event_op) (struct domain *d, int op); int (*mem_sharing) (struct domain *d); + int (*mem_sharing_op) (struct domain *d, struct domain *cd, int op); int (*apic) (struct domain *d, int cmd); int (*xen_settime) (void); int (*memtype) (uint32_t access); @@ -663,9 +666,19 @@ static inline int xsm_hvm_inject_msi (struct domain *d) return xsm_ops->hvm_inject_msi(d); } -static inline int xsm_mem_event (struct domain *d) +static inline int xsm_mem_event_setup (struct domain *d) { - return xsm_ops->mem_event(d); + return xsm_ops->mem_event_setup(d); +} + +static inline int xsm_mem_event_control (struct domain *d, int mode, int op) +{ + return xsm_ops->mem_event_control(d, mode, op); +} + +static inline int xsm_mem_event_op (struct domain *d, int op) +{ + return xsm_ops->mem_event_op(d, op); } static inline int xsm_mem_sharing (struct domain *d) @@ -673,6 +686,11 @@ static inline int xsm_mem_sharing (struct domain *d) return xsm_ops->mem_sharing(d); } +static inline int xsm_mem_sharing_op (struct domain *d, struct domain *cd, int op) +{ + return xsm_ops->mem_sharing_op(d, cd, op); +} + static inline int xsm_apic (struct domain *d, int cmd) { return xsm_ops->apic(d, cmd); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index c76212d..c82c464 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -135,8 +135,11 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, hvm_set_isa_irq_level); set_to_dummy_if_null(ops, hvm_set_pci_link_route); set_to_dummy_if_null(ops, hvm_inject_msi); - set_to_dummy_if_null(ops, mem_event); + set_to_dummy_if_null(ops, mem_event_setup); + set_to_dummy_if_null(ops, mem_event_control); + set_to_dummy_if_null(ops, mem_event_op); set_to_dummy_if_null(ops, mem_sharing); + set_to_dummy_if_null(ops, mem_sharing_op); set_to_dummy_if_null(ops, apic); set_to_dummy_if_null(ops, xen_settime); set_to_dummy_if_null(ops, memtype); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 421087f..f993696 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1275,7 +1275,17 @@ static int flask_hvm_inject_msi(struct domain *d) return current_has_perm(d, SECCLASS_HVM, HVM__SEND_IRQ); } -static int flask_mem_event(struct domain *d) +static int flask_mem_event_setup(struct domain *d) +{ + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT); +} + +static int flask_mem_event_control(struct domain *d, int mode, int op) +{ + return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT); +} + +static int flask_mem_event_op(struct domain *d, int op) { return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT); } @@ -1285,6 +1295,14 @@ static int flask_mem_sharing(struct domain *d) return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING); } +static int flask_mem_sharing_op(struct domain *d, struct domain *cd, int op) +{ + int rc = current_has_perm(cd, SECCLASS_HVM, HVM__MEM_SHARING); + if ( rc ) + return rc; + return domain_has_perm(d, cd, SECCLASS_HVM, HVM__SHARE_MEM); +} + static int flask_apic(struct domain *d, int cmd) { u32 perm; @@ -1734,8 +1752,11 @@ static struct xsm_operations flask_ops = { .hvm_set_isa_irq_level = flask_hvm_set_isa_irq_level, .hvm_set_pci_link_route = flask_hvm_set_pci_link_route, .hvm_inject_msi = flask_hvm_inject_msi, - .mem_event = flask_mem_event, + .mem_event_setup = flask_mem_event_setup, + .mem_event_control = flask_mem_event_control, + .mem_event_op = flask_mem_event_op, .mem_sharing = flask_mem_sharing, + .mem_sharing_op = flask_mem_sharing_op, .apic = flask_apic, .xen_settime = flask_xen_settime, .memtype = flask_memtype, diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 894910c..186f1fa 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -84,6 +84,7 @@ S_(SECCLASS_HVM, HVM__MEM_SHARING, "mem_sharing") S_(SECCLASS_HVM, HVM__AUDIT_P2M, "audit_p2m") S_(SECCLASS_HVM, HVM__SEND_IRQ, "send_irq") + S_(SECCLASS_HVM, HVM__SHARE_MEM, "share_mem") S_(SECCLASS_EVENT, EVENT__BIND, "bind") S_(SECCLASS_EVENT, EVENT__SEND, "send") S_(SECCLASS_EVENT, EVENT__STATUS, "status") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index 1bdb515..b3831f6 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -87,6 +87,7 @@ #define HVM__MEM_SHARING 0x00001000UL #define HVM__AUDIT_P2M 0x00002000UL #define HVM__SEND_IRQ 0x00004000UL +#define HVM__SHARE_MEM 0x00008000UL #define EVENT__BIND 0x00000001UL #define EVENT__SEND 0x00000002UL -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 19/22] arch/x86: check remote MMIO remap permissions
When a domain is mapping pages from a different pg_owner domain, the iomem_access checks are currently only applied to the pg_owner domain, potentially allowing the current domain to bypass its more restrictive iomem_access policy using another domain that it has access to. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> Cc: Tim Deegan <tim@xen.org> --- xen/arch/x86/mm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 5c6ea2d..c0c2bf3 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -754,6 +754,18 @@ get_page_from_l1e( return -EINVAL; } + if ( pg_owner != curr->domain && + !iomem_access_permitted(curr->domain, mfn, mfn) ) + { + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ + { + MEM_LOG("Domain %u attempted to map I/O space %08lx in domain %u", + curr->domain->domain_id, mfn, pg_owner->domain_id); + return -EPERM; + } + return -EINVAL; + } + if ( !(l1f & _PAGE_RW) || !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) return 0; -- 1.7.11.4
Daniel De Graaf
2012-Sep-12 15:59 UTC
[PATCH 20/22] arch/x86: use XSM hooks for get_pg_owner access checks
There are three callers of get_pg_owner: * do_mmuext_op, which does not have XSM hooks on all subfunctions * do_mmu_update, which has hooks that are inefficient * do_update_va_mapping_otherdomain, which has a simple XSM hook In order to preserve return values for the do_mmuext_op hypercall, an additional XSM hook is required to check the operation even for those subfunctions that do not use the pg_owner field. This also covers the MMUEXT_UNPIN_TABLE operation which did previously have an XSM hook. The XSM hooks in do_mmu_update were capable of replacing the checks in get_pg_owner; however, the hooks are buried in the inner loop of the function - not very good for performance when XSM is enabled and these turn in to indirect function calls. This patch removes the PTE from the hooks and replaces it with a bitfield describing what accesses are being requested. The XSM hook can then be called only when additional bits are set instead of once per iteration of the loop. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> Cc: Tim Deegan <tim@xen.org> --- tools/flask/policy/policy/flask/access_vectors | 1 + tools/flask/policy/policy/modules/xen/xen.if | 4 +- xen/arch/x86/mm.c | 53 +++++++++++-------- xen/include/xsm/dummy.h | 15 ++++-- xen/include/xsm/xsm.h | 25 +++++---- xen/xsm/dummy.c | 4 +- xen/xsm/flask/hooks.c | 71 +++++++++----------------- xen/xsm/flask/include/av_perm_to_string.h | 1 + xen/xsm/flask/include/av_permissions.h | 1 + 9 files changed, 88 insertions(+), 87 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 45ac437..8324725 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -141,6 +141,7 @@ class mmu mfnlist memorymap remote_remap + mmuext_op } class shadow diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index d630f47..725d7a1 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -7,7 +7,7 @@ ################################################################################ define(`declare_domain_common'', ` allow $1 $2:grant { query setup }; - allow $1 $2:mmu { adjust physmap map_read map_write stat pinpage updatemp }; + allow $1 $2:mmu { adjust physmap map_read map_write stat pinpage updatemp mmuext_op }; allow $1 $2:hvm { getparam setparam }; '') @@ -51,7 +51,7 @@ define(`create_domain_common'', ` allow $1 $2:domain2 { set_cpuid settsc }; allow $1 $2:security check_context; allow $1 $2:shadow enable; - allow $1 $2:mmu {map_read map_write adjust memorymap physmap pinpage}; + allow $1 $2:mmu { map_read map_write adjust memorymap physmap pinpage mmuext_op }; allow $1 $2:grant setup; allow $1 $2:hvm { cacheattr getparam hvmctl irqlevel pciroute sethvmc setparam pcilevel trackdirtyvram }; '') diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index c0c2bf3..04a056f 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2619,11 +2619,6 @@ static struct domain *get_pg_owner(domid_t domid) pg_owner = rcu_lock_domain(dom_io); break; case DOMID_XEN: - if ( !IS_PRIV(curr) ) - { - MEM_LOG("Cannot set foreign dom"); - break; - } pg_owner = rcu_lock_domain(dom_xen); break; default: @@ -2632,12 +2627,6 @@ static struct domain *get_pg_owner(domid_t domid) MEM_LOG("Unknown domain ''%u''", domid); break; } - if ( !IS_PRIV_FOR(curr, pg_owner) ) - { - MEM_LOG("Cannot set foreign dom"); - rcu_unlock_domain(pg_owner); - pg_owner = NULL; - } break; } @@ -2725,6 +2714,13 @@ long do_mmuext_op( goto out; } + rc = xsm_mmuext_op(d, pg_owner); + if ( rc ) + { + rcu_unlock_domain(pg_owner); + goto out; + } + for ( i = 0; i < count; i++ ) { if ( hypercall_preempt_check() ) @@ -3164,6 +3160,8 @@ long do_mmu_update( struct vcpu *v = current; struct domain *d = v->domain, *pt_owner = d, *pg_owner; struct domain_mmap_cache mapcache; + uint32_t xsm_needed = 0; + uint32_t xsm_checked = 0; if ( unlikely(count & MMU_UPDATE_PREEMPTED) ) { @@ -3195,11 +3193,6 @@ long do_mmu_update( rc = -EINVAL; goto out; } - if ( !IS_PRIV_FOR(d, pt_owner) ) - { - rc = -ESRCH; - goto out; - } } if ( (pg_owner = get_pg_owner((uint16_t)foreigndom)) == NULL ) @@ -3239,9 +3232,20 @@ long do_mmu_update( { p2m_type_t p2mt; - rc = xsm_mmu_normal_update(d, pt_owner, pg_owner, req.val); - if ( rc ) - break; + xsm_needed |= XSM_MMU_NORMAL_UPDATE; + if ( get_pte_flags(req.val) & _PAGE_PRESENT ) + { + xsm_needed |= XSM_MMU_UPDATE_READ; + if ( get_pte_flags(req.val) & _PAGE_RW ) + xsm_needed |= XSM_MMU_UPDATE_WRITE; + } + if ( xsm_needed != xsm_checked ) + { + rc = xsm_mmu_update(d, pt_owner, pg_owner, xsm_needed); + if ( rc ) + break; + xsm_checked = xsm_needed; + } rc = -EINVAL; req.ptr -= cmd; @@ -3353,9 +3357,14 @@ long do_mmu_update( mfn = req.ptr >> PAGE_SHIFT; gpfn = req.val; - rc = xsm_mmu_machphys_update(d, pg_owner, mfn); - if ( rc ) - break; + xsm_needed |= XSM_MMU_MACHPHYS_UPDATE; + if ( xsm_needed != xsm_checked ) + { + rc = xsm_mmu_update(d, pt_owner, pg_owner, xsm_needed); + if ( rc ) + break; + xsm_checked = xsm_needed; + } if ( unlikely(!get_page_from_pagenr(mfn, pg_owner)) ) { diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 1760cd9..9c13d5c037 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -662,21 +662,28 @@ static XSM_DEFAULT(int, domain_memory_map) (struct domain *d) return 0; } -static XSM_DEFAULT(int, mmu_normal_update) (struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte) +static XSM_DEFAULT(int, mmu_update) (struct domain *d, struct domain *t, + struct domain *f, uint32_t flags) { + if ( d != t && !IS_PRIV_FOR(d, t) ) + return -EPERM; + if ( d != f && !IS_PRIV_FOR(d, f) ) + return -EPERM; return 0; } -static XSM_DEFAULT(int, mmu_machphys_update) (struct domain *d, struct domain *f, - unsigned long mfn) +static XSM_DEFAULT(int, mmuext_op) (struct domain *d, struct domain *f) { + if ( d != f && !IS_PRIV_FOR(d, f) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, update_va_mapping) (struct domain *d, struct domain *f, l1_pgentry_t pte) { + if ( d != f && !IS_PRIV_FOR(d, f) ) + return -EPERM; return 0; } diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index c2c1efa..6d970b1 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -27,8 +27,6 @@ typedef u32 xsm_magic_t; #define XSM_MAGIC 0x00000000 #endif -#ifdef XSM_ENABLE - extern char *policy_buffer; extern u32 policy_size; @@ -170,9 +168,13 @@ struct xsm_operations { int (*getidletime) (void); int (*machine_memory_map) (void); int (*domain_memory_map) (struct domain *d); - int (*mmu_normal_update) (struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte); - int (*mmu_machphys_update) (struct domain *d1, struct domain *d2, unsigned long mfn); +#define XSM_MMU_UPDATE_READ 1 +#define XSM_MMU_UPDATE_WRITE 2 +#define XSM_MMU_NORMAL_UPDATE 4 +#define XSM_MMU_MACHPHYS_UPDATE 8 + int (*mmu_update) (struct domain *d, struct domain *t, + struct domain *f, uint32_t flags); + int (*mmuext_op) (struct domain *d, struct domain *f); int (*update_va_mapping) (struct domain *d, struct domain *f, l1_pgentry_t pte); int (*add_to_physmap) (struct domain *d1, struct domain *d2); int (*sendtrigger) (struct domain *d); @@ -186,6 +188,8 @@ struct xsm_operations { #endif }; +#ifdef XSM_ENABLE + extern struct xsm_operations *xsm_ops; static inline void xsm_security_domaininfo (struct domain *d, @@ -761,16 +765,15 @@ static inline int xsm_domain_memory_map(struct domain *d) return xsm_ops->domain_memory_map(d); } -static inline int xsm_mmu_normal_update (struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte) +static inline int xsm_mmu_update (struct domain *d, struct domain *t, + struct domain *f, uint32_t flags) { - return xsm_ops->mmu_normal_update(d, t, f, fpte); + return xsm_ops->mmu_update(d, t, f, flags); } -static inline int xsm_mmu_machphys_update (struct domain *d1, struct domain *d2, - unsigned long mfn) +static inline int xsm_mmuext_op (struct domain *d, struct domain *f) { - return xsm_ops->mmu_machphys_update(d1, d2, mfn); + return xsm_ops->mmuext_op(d, f); } static inline int xsm_update_va_mapping(struct domain *d, struct domain *f, diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index c82c464..9476be6 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -154,8 +154,8 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, getidletime); set_to_dummy_if_null(ops, machine_memory_map); set_to_dummy_if_null(ops, domain_memory_map); - set_to_dummy_if_null(ops, mmu_normal_update); - set_to_dummy_if_null(ops, mmu_machphys_update); + set_to_dummy_if_null(ops, mmu_update); + set_to_dummy_if_null(ops, mmuext_op); set_to_dummy_if_null(ops, update_va_mapping); set_to_dummy_if_null(ops, add_to_physmap); set_to_dummy_if_null(ops, remove_from_physmap); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index f993696..bd2d792 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1432,65 +1432,44 @@ static int flask_domain_memory_map(struct domain *d) return current_has_perm(d, SECCLASS_MMU, MMU__MEMORYMAP); } -static int domain_memory_perm(struct domain *d, struct domain *f, l1_pgentry_t pte) +static int flask_mmu_update(struct domain *d, struct domain *t, + struct domain *f, uint32_t flags) { int rc = 0; - u32 map_perms = MMU__MAP_READ; - unsigned long fgfn, fmfn; - p2m_type_t p2mt; - - if ( !(l1e_get_flags(pte) & _PAGE_PRESENT) ) - return 0; - - if ( l1e_get_flags(pte) & _PAGE_RW ) - map_perms |= MMU__MAP_WRITE; - - fgfn = l1e_get_pfn(pte); - fmfn = mfn_x(get_gfn_query(f, fgfn, &p2mt)); - put_gfn(f, fgfn); + u32 map_perms = 0; - if ( f->domain_id == DOMID_IO || !mfn_valid(fmfn) ) - { - struct avc_audit_data ad; - u32 dsid, fsid; - rc = security_iomem_sid(fmfn, &fsid); - if ( rc ) - return rc; - AVC_AUDIT_DATA_INIT(&ad, MEMORY); - ad.sdom = d; - ad.tdom = f; - ad.memory.pte = pte.l1; - ad.memory.mfn = fmfn; - dsid = domain_sid(d); - return avc_has_perm(dsid, fsid, SECCLASS_MMU, map_perms, &ad); - } - - return domain_has_perm(d, f, SECCLASS_MMU, map_perms); -} - -static int flask_mmu_normal_update(struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte) -{ - int rc = 0; - - if (d != t) + if ( (flags & XSM_MMU_NORMAL_UPDATE) && d != t ) rc = domain_has_perm(d, t, SECCLASS_MMU, MMU__REMOTE_REMAP); if ( rc ) return rc; - return domain_memory_perm(d, f, l1e_from_intpte(fpte)); + if ( flags & XSM_MMU_UPDATE_READ ) + map_perms |= MMU__MAP_READ; + if ( flags & XSM_MMU_UPDATE_WRITE ) + map_perms |= MMU__MAP_WRITE; + if ( flags & XSM_MMU_MACHPHYS_UPDATE ) + map_perms |= MMU__UPDATEMP; + + if ( map_perms ) + rc = domain_has_perm(d, f, SECCLASS_MMU, map_perms); + return rc; } -static int flask_mmu_machphys_update(struct domain *d1, struct domain *d2, - unsigned long mfn) +static int flask_mmuext_op(struct domain *d, struct domain *f) { - return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__UPDATEMP); + return domain_has_perm(d, f, SECCLASS_MMU, MMU__MMUEXT_OP); } static int flask_update_va_mapping(struct domain *d, struct domain *f, l1_pgentry_t pte) { - return domain_memory_perm(d, f, pte); + u32 map_perms = MMU__MAP_READ; + if ( !(l1e_get_flags(pte) & _PAGE_PRESENT) ) + return 0; + if ( l1e_get_flags(pte) & _PAGE_RW ) + map_perms |= MMU__MAP_WRITE; + + return domain_has_perm(d, f, SECCLASS_MMU, map_perms); } static int flask_add_to_physmap(struct domain *d1, struct domain *d2) @@ -1771,8 +1750,8 @@ static struct xsm_operations flask_ops = { .getidletime = flask_getidletime, .machine_memory_map = flask_machine_memory_map, .domain_memory_map = flask_domain_memory_map, - .mmu_normal_update = flask_mmu_normal_update, - .mmu_machphys_update = flask_mmu_machphys_update, + .mmu_update = flask_mmu_update, + .mmuext_op = flask_mmuext_op, .update_va_mapping = flask_update_va_mapping, .add_to_physmap = flask_add_to_physmap, .remove_from_physmap = flask_remove_from_physmap, diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 186f1fa..8f65b96 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -111,6 +111,7 @@ S_(SECCLASS_MMU, MMU__MFNLIST, "mfnlist") S_(SECCLASS_MMU, MMU__MEMORYMAP, "memorymap") S_(SECCLASS_MMU, MMU__REMOTE_REMAP, "remote_remap") + S_(SECCLASS_MMU, MMU__MMUEXT_OP, "mmuext_op") S_(SECCLASS_SHADOW, SHADOW__DISABLE, "disable") S_(SECCLASS_SHADOW, SHADOW__ENABLE, "enable") S_(SECCLASS_SHADOW, SHADOW__LOGDIRTY, "logdirty") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index b3831f6..18454fd 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -117,6 +117,7 @@ #define MMU__MFNLIST 0x00000400UL #define MMU__MEMORYMAP 0x00000800UL #define MMU__REMOTE_REMAP 0x00001000UL +#define MMU__MMUEXT_OP 0x00002000UL #define SHADOW__DISABLE 0x00000001UL #define SHADOW__ENABLE 0x00000002UL -- 1.7.11.4
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> --- tools/flask/policy/policy/flask/access_vectors | 1 + tools/flask/policy/policy/modules/xen/xen.if | 2 ++ xen/common/memory.c | 12 +++++++++++- xen/include/xsm/dummy.h | 7 +++++++ xen/include/xsm/xsm.h | 6 ++++++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 6 ++++++ xen/xsm/flask/include/av_perm_to_string.h | 1 + xen/xsm/flask/include/av_permissions.h | 1 + 9 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 8324725..caf65d2 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -142,6 +142,7 @@ class mmu memorymap remote_remap mmuext_op + exchange } class shadow diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index 725d7a1..67f5daf 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -30,6 +30,7 @@ define(`declare_domain'', ` # containing at most one domain. This is not enforced by policy. define(`declare_singleton_domain'', ` type $1, domain_type`''ifelse(`$#'', `1'', `'', `,shift($@)''); + define(`$1_self'', `$1'') type $1_channel, event_type; type_transition $1 domain_type:event $1_channel; declare_domain_common($1, $1) @@ -161,6 +162,7 @@ define(`make_device_model'', ` # use_device(domain, device) # Allow a device to be used by a domain define(`use_device'', ` + allow $1 $1_self:mmu exchange; allow $1 $2:resource use; allow $1 $2:mmu { map_read map_write }; '') diff --git a/xen/common/memory.c b/xen/common/memory.c index cfdd63f..a5b548b 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -329,9 +329,19 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) out_chunk_order = exch.in.extent_order - exch.out.extent_order; } - rc = rcu_lock_target_domain_by_id(exch.in.domid, &d); + d = rcu_lock_domain_by_any_id(exch.in.domid); + if ( d == NULL ) + { + rc = -ESRCH; + goto fail_early; + } + + rc = xsm_memory_exchange(d); if ( rc ) + { + rcu_unlock_domain(d); goto fail_early; + } memflags |= MEMF_bits(domain_clamp_alloc_bitsize( d, diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 9c13d5c037..e5e8020 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -235,6 +235,13 @@ static XSM_DEFAULT(int, grant_query_size) (struct domain *d1, struct domain *d2) return 0; } +static XSM_DEFAULT(int, memory_exchange) (struct domain *d) +{ + if ( d != current->domain && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, memory_adjust_reservation) (struct domain *d1, struct domain *d2) { diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 6d970b1..46d5cd6 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -96,6 +96,7 @@ struct xsm_operations { int (*get_pod_target) (struct domain *d); int (*set_pod_target) (struct domain *d); + int (*memory_exchange) (struct domain *d); int (*memory_adjust_reservation) (struct domain *d1, struct domain *d2); int (*memory_stat_reservation) (struct domain *d1, struct domain *d2); int (*memory_pin_page) (struct domain *d1, struct domain *d2, struct page_info *page); @@ -451,6 +452,11 @@ static inline int xsm_set_pod_target (struct domain *d) return xsm_ops->set_pod_target(d); } +static inline int xsm_memory_exchange (struct domain *d) +{ + return xsm_ops->memory_exchange(d); +} + static inline int xsm_memory_adjust_reservation (struct domain *d1, struct domain *d2) { diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 9476be6..ddaf40b 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -83,6 +83,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, get_pod_target); set_to_dummy_if_null(ops, set_pod_target); + set_to_dummy_if_null(ops, memory_exchange); set_to_dummy_if_null(ops, memory_adjust_reservation); set_to_dummy_if_null(ops, memory_stat_reservation); set_to_dummy_if_null(ops, memory_pin_page); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index bd2d792..2f33a9f 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -396,6 +396,11 @@ static int flask_set_pod_target(struct domain *d) return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETPODTARGET); } +static int flask_memory_exchange(struct domain *d) +{ + return current_has_perm(d, SECCLASS_MMU, MMU__EXCHANGE); +} + static int flask_memory_adjust_reservation(struct domain *d1, struct domain *d2) { return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__ADJUST); @@ -1683,6 +1688,7 @@ static struct xsm_operations flask_ops = { .get_pod_target = flask_get_pod_target, .set_pod_target = flask_set_pod_target, + .memory_exchange = flask_memory_exchange, .memory_adjust_reservation = flask_memory_adjust_reservation, .memory_stat_reservation = flask_memory_stat_reservation, .memory_pin_page = flask_memory_pin_page, diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 8f65b96..79d5939 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -112,6 +112,7 @@ S_(SECCLASS_MMU, MMU__MEMORYMAP, "memorymap") S_(SECCLASS_MMU, MMU__REMOTE_REMAP, "remote_remap") S_(SECCLASS_MMU, MMU__MMUEXT_OP, "mmuext_op") + S_(SECCLASS_MMU, MMU__EXCHANGE, "exchange") S_(SECCLASS_SHADOW, SHADOW__DISABLE, "disable") S_(SECCLASS_SHADOW, SHADOW__ENABLE, "enable") S_(SECCLASS_SHADOW, SHADOW__LOGDIRTY, "logdirty") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index 18454fd..d982328 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -118,6 +118,7 @@ #define MMU__MEMORYMAP 0x00000800UL #define MMU__REMOTE_REMAP 0x00001000UL #define MMU__MMUEXT_OP 0x00002000UL +#define MMU__EXCHANGE 0x00004000UL #define SHADOW__DISABLE 0x00000001UL #define SHADOW__ENABLE 0x00000002UL -- 1.7.11.4
This adds a pair of XSM hooks for tmem operations: xsm_tmem_op which controls any use of tmem, and xsm_tmem_control which allows use of the TMEM_CONTROL operations. By default, all domains can use tmem while only IS_PRIV domains can use control operations. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Dan Magenheimer <dan.magenheimer@oracle.com> --- tools/flask/policy/policy/flask/access_vectors | 2 ++ xen/common/tmem.c | 3 +++ xen/include/xen/tmem_xen.h | 8 +++++++- xen/include/xsm/dummy.h | 12 ++++++++++++ xen/include/xsm/xsm.h | 12 ++++++++++++ xen/xsm/dummy.c | 2 ++ xen/xsm/flask/hooks.c | 12 ++++++++++++ xen/xsm/flask/include/av_perm_to_string.h | 2 ++ xen/xsm/flask/include/av_permissions.h | 2 ++ 9 files changed, 54 insertions(+), 1 deletion(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index caf65d2..7a7e253 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -35,6 +35,8 @@ class xen lockprof cpupool_op sched_op + tmem_op + tmem_control } class domain diff --git a/xen/common/tmem.c b/xen/common/tmem.c index f4812b9..6d95296 100644 --- a/xen/common/tmem.c +++ b/xen/common/tmem.c @@ -2636,6 +2636,9 @@ EXPORT long do_tmem_op(tmem_cli_op_t uops) if ( !tmem_initialized ) return -ENODEV; + if ( !tmh_current_permitted() ) + return -EPERM; + total_tmem_ops++; if ( tmh_lock_all ) diff --git a/xen/include/xen/tmem_xen.h b/xen/include/xen/tmem_xen.h index 9492810..ae550af 100644 --- a/xen/include/xen/tmem_xen.h +++ b/xen/include/xen/tmem_xen.h @@ -16,6 +16,7 @@ #include <xen/guest_access.h> /* copy_from_guest */ #include <xen/hash.h> /* hash_long */ #include <xen/domain_page.h> /* __map_domain_page */ +#include <xsm/xsm.h> /* xsm_tmem_control */ #include <public/tmem.h> #ifdef CONFIG_COMPAT #include <compat/tmem.h> @@ -326,9 +327,14 @@ static inline bool_t tmh_set_client_from_id( return rc; } +static inline bool_t tmh_current_permitted(void) +{ + return !xsm_tmem_op(); +} + static inline bool_t tmh_current_is_privileged(void) { - return IS_PRIV(current->domain); + return !xsm_tmem_control(); } static inline uint8_t tmh_get_first_byte(pfp_t *pfp) diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index e5e8020..4ed010a 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -443,6 +443,18 @@ static XSM_DEFAULT(int, sched_op) (void) return 0; } +static XSM_DEFAULT(int, tmem_op) (void) +{ + return 0; +} + +static XSM_DEFAULT(int, tmem_control) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(long, __do_xsm_op)(XEN_GUEST_HANDLE(xsm_op_t) op) { return -ENOSYS; diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 46d5cd6..d7ab92b 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -134,6 +134,8 @@ struct xsm_operations { int (*lockprof)(void); int (*cpupool_op)(void); int (*sched_op)(void); + int (*tmem_op)(void); + int (*tmem_control)(void); long (*__do_xsm_op) (XEN_GUEST_HANDLE(xsm_op_t) op); @@ -610,6 +612,16 @@ static inline int xsm_sched_op(void) return xsm_ops->sched_op(); } +static inline int xsm_tmem_op(void) +{ + return xsm_ops->tmem_op(); +} + +static inline int xsm_tmem_control(void) +{ + return xsm_ops->tmem_control(); +} + static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { return xsm_ops->__do_xsm_op(op); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index ddaf40b..e4fdfd7 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -120,6 +120,8 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, lockprof); set_to_dummy_if_null(ops, cpupool_op); set_to_dummy_if_null(ops, sched_op); + set_to_dummy_if_null(ops, tmem_op); + set_to_dummy_if_null(ops, tmem_control); set_to_dummy_if_null(ops, __do_xsm_op); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 2f33a9f..4553289 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1077,6 +1077,16 @@ static inline int flask_sched_op(void) return domain_has_xen(current->domain, XEN__SCHED_OP); } +static inline int flask_tmem_op(void) +{ + return domain_has_xen(current->domain, XEN__TMEM_OP); +} + +static inline int flask_tmem_control(void) +{ + return domain_has_xen(current->domain, XEN__TMEM_CONTROL); +} + static int flask_perfcontrol(void) { return domain_has_xen(current->domain, XEN__PERFCONTROL); @@ -1721,6 +1731,8 @@ static struct xsm_operations flask_ops = { .lockprof = flask_lockprof, .cpupool_op = flask_cpupool_op, .sched_op = flask_sched_op, + .tmem_op = flask_tmem_op, + .tmem_control = flask_tmem_control, .__do_xsm_op = do_flask_op, diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 79d5939..c3f2370 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -29,6 +29,8 @@ S_(SECCLASS_XEN, XEN__LOCKPROF, "lockprof") S_(SECCLASS_XEN, XEN__CPUPOOL_OP, "cpupool_op") S_(SECCLASS_XEN, XEN__SCHED_OP, "sched_op") + S_(SECCLASS_XEN, XEN__TMEM_OP, "tmem_op") + S_(SECCLASS_XEN, XEN__TMEM_CONTROL, "tmem_control") S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUCONTEXT, "setvcpucontext") S_(SECCLASS_DOMAIN, DOMAIN__PAUSE, "pause") S_(SECCLASS_DOMAIN, DOMAIN__UNPAUSE, "unpause") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index d982328..65302e8 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -29,6 +29,8 @@ #define XEN__LOCKPROF 0x08000000UL #define XEN__CPUPOOL_OP 0x10000000UL #define XEN__SCHED_OP 0x20000000UL +#define XEN__TMEM_OP 0x40000000UL +#define XEN__TMEM_CONTROL 0x80000000UL #define DOMAIN__SETVCPUCONTEXT 0x00000001UL #define DOMAIN__PAUSE 0x00000002UL -- 1.7.11.4
Jan Beulich
2012-Sep-13 07:46 UTC
Re: [PATCH 09/22] xsm: Use the dummy XSM module if XSM is disabled
>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > This patch moves the implementation of the dummy XSM module to a header > file that provides inline functions when XSM_ENABLE is not defined. This > reduces duplication between the dummy module and callers when the > implementation of the dummy return is not just "return 0", and also > provides better compile-time checking for completeness of the XSM > implementations in the dummy module.This looks good to me, with one minor comment:> --- a/xen/xsm/xsm_core.c > +++ b/xen/xsm/xsm_core.c > @@ -113,7 +113,7 @@ int unregister_xsm(struct xsm_operations *ops) > > long do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) > { > - return __do_xsm_op(op); > + return xsm___do_xsm_op(op);The three immediately successive underscores look really odd now - any reason a single one doesn''t do? Jan
Jan Beulich
2012-Sep-13 08:00 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > When a domain is mapping pages from a different pg_owner domain, the > iomem_access checks are currently only applied to the pg_owner domain, > potentially allowing the current domain to bypass its more restrictive > iomem_access policy using another domain that it has access to.Are you sure about this? I ask because ...> --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -754,6 +754,18 @@ get_page_from_l1e( > return -EINVAL; > } > > + if ( pg_owner != curr->domain && > + !iomem_access_permitted(curr->domain, mfn, mfn) ) > + { > + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ > + { > + MEM_LOG("Domain %u attempted to map I/O space %08lx in domain %u", > + curr->domain->domain_id, mfn, pg_owner->domain_id); > + return -EPERM; > + } > + return -EINVAL; > + } > +... the place you insert this is after non-RAM pages got filtered out already, so you''re applying an IOMEM permission check to a RAM page. Jan> if ( !(l1f & _PAGE_RW) || > !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) > return 0;
Jan Beulich
2012-Sep-13 08:13 UTC
Re: [PATCH 20/22] arch/x86: use XSM hooks for get_pg_owner access checks
>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > @@ -3353,9 +3357,14 @@ long do_mmu_update( > mfn = req.ptr >> PAGE_SHIFT; > gpfn = req.val; > > - rc = xsm_mmu_machphys_update(d, pg_owner, mfn); > - if ( rc ) > - break; > + xsm_needed |= XSM_MMU_MACHPHYS_UPDATE; > + if ( xsm_needed != xsm_checked ) > + { > + rc = xsm_mmu_update(d, pt_owner, pg_owner, xsm_needed);If you''re already updating it this way, it would seem appropriate to remove the over-checking here: pt_owner is meaningless for this operation (there are no page tables involved), and hence you could/should pass d instead. Jan> + if ( rc ) > + break; > + xsm_checked = xsm_needed; > + } > > if ( unlikely(!get_page_from_pagenr(mfn, pg_owner)) ) > {
Daniel De Graaf
2012-Sep-13 13:40 UTC
Re: [PATCH 09/22] xsm: Use the dummy XSM module if XSM is disabled
On 09/13/2012 03:46 AM, Jan Beulich wrote:>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> This patch moves the implementation of the dummy XSM module to a header >> file that provides inline functions when XSM_ENABLE is not defined. This >> reduces duplication between the dummy module and callers when the >> implementation of the dummy return is not just "return 0", and also >> provides better compile-time checking for completeness of the XSM >> implementations in the dummy module. > > This looks good to me, with one minor comment: > >> --- a/xen/xsm/xsm_core.c >> +++ b/xen/xsm/xsm_core.c >> @@ -113,7 +113,7 @@ int unregister_xsm(struct xsm_operations *ops) >> >> long do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) >> { >> - return __do_xsm_op(op); >> + return xsm___do_xsm_op(op); > > The three immediately successive underscores look really odd > now - any reason a single one doesn''t do? > > JanNo reason other than not renaming the __do_xsm_op field that this calls. That also doesn''t have a good reason to need underscores, so I''ll rename it instead. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-13 13:46 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
On 09/13/2012 04:00 AM, Jan Beulich wrote:>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> When a domain is mapping pages from a different pg_owner domain, the >> iomem_access checks are currently only applied to the pg_owner domain, >> potentially allowing the current domain to bypass its more restrictive >> iomem_access policy using another domain that it has access to. > > Are you sure about this? I ask because ... > >> --- a/xen/arch/x86/mm.c >> +++ b/xen/arch/x86/mm.c >> @@ -754,6 +754,18 @@ get_page_from_l1e( >> return -EINVAL; >> } >> >> + if ( pg_owner != curr->domain && >> + !iomem_access_permitted(curr->domain, mfn, mfn) ) >> + { >> + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ >> + { >> + MEM_LOG("Domain %u attempted to map I/O space %08lx in domain %u", >> + curr->domain->domain_id, mfn, pg_owner->domain_id); >> + return -EPERM; >> + } >> + return -EINVAL; >> + } >> + > > ... the place you insert this is after non-RAM pages got filtered > out already, so you''re applying an IOMEM permission check to a > RAM page. > > Jan > >> if ( !(l1f & _PAGE_RW) || >> !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) >> return 0;If that''s true, then the check a few lines above is also applying IOMEM checks to RAM pages. I can see non-privileged attempts being filtered above, but successful mappings will continue to the check I added. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-13 13:55 UTC
Re: [PATCH 20/22] arch/x86: use XSM hooks for get_pg_owner access checks
On 09/13/2012 04:13 AM, Jan Beulich wrote:>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> @@ -3353,9 +3357,14 @@ long do_mmu_update( >> mfn = req.ptr >> PAGE_SHIFT; >> gpfn = req.val; >> >> - rc = xsm_mmu_machphys_update(d, pg_owner, mfn); >> - if ( rc ) >> - break; >> + xsm_needed |= XSM_MMU_MACHPHYS_UPDATE; >> + if ( xsm_needed != xsm_checked ) >> + { >> + rc = xsm_mmu_update(d, pt_owner, pg_owner, xsm_needed); > > If you''re already updating it this way, it would seem appropriate > to remove the over-checking here: pt_owner is meaningless for > this operation (there are no page tables involved), and hence > you could/should pass d instead. > > Jan >While this is safe, it makes thinking about the arguments to the XSM hook harder: the second argument would be defined as "pt_owner if called with XSM_MMU_NORMAL_UPDATE set and either XSM_MMU_MACHPHYS_UPDATE unset or XSM_MMU_MACHPHYS_UPDATE set in the previous call; otherwise, d." I would prefer the simpler method of passing pt_owner every time, and only checking it if XSM_MMU_NORMAL_UPDATE is set (which I now notice that the default XSM hook does not do, although the FLASK hook does; I''ll fix that). -- Daniel De Graaf National Security Agency
Jan Beulich
2012-Sep-13 14:13 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
>>> On 13.09.12 at 15:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/13/2012 04:00 AM, Jan Beulich wrote: >>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> When a domain is mapping pages from a different pg_owner domain, the >>> iomem_access checks are currently only applied to the pg_owner domain, >>> potentially allowing the current domain to bypass its more restrictive >>> iomem_access policy using another domain that it has access to. >> >> Are you sure about this? I ask because ... >> >>> --- a/xen/arch/x86/mm.c >>> +++ b/xen/arch/x86/mm.c >>> @@ -754,6 +754,18 @@ get_page_from_l1e( >>> return -EINVAL; >>> } >>> >>> + if ( pg_owner != curr->domain && >>> + !iomem_access_permitted(curr->domain, mfn, mfn) ) >>> + { >>> + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ >>> + { >>> + MEM_LOG("Domain %u attempted to map I/O space %08lx in > domain %u", >>> + curr->domain->domain_id, mfn, pg_owner->domain_id); >>> + return -EPERM; >>> + } >>> + return -EINVAL; >>> + } >>> + >> >> ... the place you insert this is after non-RAM pages got filtered >> out already, so you''re applying an IOMEM permission check to a >> RAM page. >> >> Jan >> >>> if ( !(l1f & _PAGE_RW) || >>> !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) >>> return 0; > > If that''s true, then the check a few lines above is also applying IOMEM > checks to RAM pages. I can see non-privileged attempts being filtered > above,I can''t see how that would happen given this primary conditional if ( !mfn_valid(mfn) || (real_pg_owner = page_get_owner_and_reference(page)) == dom_io ) Please clarify what you''re observing.> but successful mappings will continue to the check I added.Of course. I would think that if anything, you would want to add a second call to iomem_access_permitted() with "curr->domain" right at the place where the current one is (in particular inside the above quoted conditional). Jan
Jan Beulich
2012-Sep-13 14:15 UTC
Re: [PATCH 20/22] arch/x86: use XSM hooks for get_pg_owner access checks
>>> On 13.09.12 at 15:55, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/13/2012 04:13 AM, Jan Beulich wrote: >>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> @@ -3353,9 +3357,14 @@ long do_mmu_update( >>> mfn = req.ptr >> PAGE_SHIFT; >>> gpfn = req.val; >>> >>> - rc = xsm_mmu_machphys_update(d, pg_owner, mfn); >>> - if ( rc ) >>> - break; >>> + xsm_needed |= XSM_MMU_MACHPHYS_UPDATE; >>> + if ( xsm_needed != xsm_checked ) >>> + { >>> + rc = xsm_mmu_update(d, pt_owner, pg_owner, xsm_needed); >> >> If you''re already updating it this way, it would seem appropriate >> to remove the over-checking here: pt_owner is meaningless for >> this operation (there are no page tables involved), and hence >> you could/should pass d instead. > > While this is safe, it makes thinking about the arguments to the XSM hook > harder: the second argument would be defined as "pt_owner if called with > XSM_MMU_NORMAL_UPDATE set and either XSM_MMU_MACHPHYS_UPDATE unset or > XSM_MMU_MACHPHYS_UPDATE set in the previous call; otherwise, d." I would > prefer the simpler method of passing pt_owner every time, and only checking > it if XSM_MMU_NORMAL_UPDATE is set (which I now notice that the default > XSM hook does not do, although the FLASK hook does; I''ll fix that).If that''s a concern, then rather pass NULL here (and deal with it in the XSM code), indicating that there are no page tables being updated. Jan
Daniel De Graaf
2012-Sep-13 14:25 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
On 09/13/2012 10:13 AM, Jan Beulich wrote:>>>> On 13.09.12 at 15:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> On 09/13/2012 04:00 AM, Jan Beulich wrote: >>>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>> When a domain is mapping pages from a different pg_owner domain, the >>>> iomem_access checks are currently only applied to the pg_owner domain, >>>> potentially allowing the current domain to bypass its more restrictive >>>> iomem_access policy using another domain that it has access to. >>> >>> Are you sure about this? I ask because ... >>> >>>> --- a/xen/arch/x86/mm.c >>>> +++ b/xen/arch/x86/mm.c >>>> @@ -754,6 +754,18 @@ get_page_from_l1e( >>>> return -EINVAL; >>>> } >>>> >>>> + if ( pg_owner != curr->domain && >>>> + !iomem_access_permitted(curr->domain, mfn, mfn) ) >>>> + { >>>> + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ >>>> + { >>>> + MEM_LOG("Domain %u attempted to map I/O space %08lx in >> domain %u", >>>> + curr->domain->domain_id, mfn, pg_owner->domain_id); >>>> + return -EPERM; >>>> + } >>>> + return -EINVAL; >>>> + } >>>> + >>> >>> ... the place you insert this is after non-RAM pages got filtered >>> out already, so you''re applying an IOMEM permission check to a >>> RAM page. >>> >>> Jan >>> >>>> if ( !(l1f & _PAGE_RW) || >>>> !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) >>>> return 0; >> >> If that''s true, then the check a few lines above is also applying IOMEM >> checks to RAM pages. I can see non-privileged attempts being filtered >> above,"above" refers to "if ( !iomem_access_permitted(pg_owner, mfn, mfn) )"> I can''t see how that would happen given this primary conditional > > if ( !mfn_valid(mfn) || > (real_pg_owner = page_get_owner_and_reference(page)) == dom_io ) > > Please clarify what you''re observing.As I understand it, the contents of this block will be executed if the MFN is invalid (interpreted as MMIO space) or if the page''s owner is DOMID_IO, which is how MMIO space is marked.>> but successful mappings will continue to the check I added. > > Of course. I would think that if anything, you would want to add > a second call to iomem_access_permitted() with "curr->domain" > right at the place where the current one is (in particular inside > the above quoted conditional). > > JanI was emulating the existing iomem_access_permitted check being run on pg_owner; moving the curr->domain check up into this first conditional would end up treating the MMIO mapping as a regular RAM mapping if the iomem_access_permitted fails. Unless you''re talking about a different quoted conditional? -- Daniel De Graaf National Security Agency
Daniel De Graaf writes ("[Xen-devel] [PATCH v3] Merge IS_PRIV checks into XSM hooks"):> The ARM architecture is not touched at all in these patches; however, > none of the changes should affect ARM. XSM hooks will need to be added > for the arch-specific controls in order for FLASK to be useful on ARM, > but those changes are outside the scope of this series.By "not useful" I guess you mean that it wouldn''t have the desired security property. Is there already something that will prevent attempts to use xsm on arm ? The code which enforces this should ideally have a comment listing everything that was done to x86 but not to arm, so that we have a useful todo list and don''t miss anything before enabling xsm on arm. Ian.
Jan Beulich
2012-Sep-13 15:04 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
>>> On 13.09.12 at 16:25, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/13/2012 10:13 AM, Jan Beulich wrote: >>>>> On 13.09.12 at 15:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> On 09/13/2012 04:00 AM, Jan Beulich wrote: >>>>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>>> When a domain is mapping pages from a different pg_owner domain, the >>>>> iomem_access checks are currently only applied to the pg_owner domain, >>>>> potentially allowing the current domain to bypass its more restrictive >>>>> iomem_access policy using another domain that it has access to. >>>> >>>> Are you sure about this? I ask because ... >>>> >>>>> --- a/xen/arch/x86/mm.c >>>>> +++ b/xen/arch/x86/mm.c >>>>> @@ -754,6 +754,18 @@ get_page_from_l1e( >>>>> return -EINVAL; >>>>> } >>>>> >>>>> + if ( pg_owner != curr->domain && >>>>> + !iomem_access_permitted(curr->domain, mfn, mfn) ) >>>>> + { >>>>> + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ >>>>> + { >>>>> + MEM_LOG("Domain %u attempted to map I/O space %08lx in >>> domain %u", >>>>> + curr->domain->domain_id, mfn, pg_owner->domain_id); >>>>> + return -EPERM; >>>>> + } >>>>> + return -EINVAL; >>>>> + } >>>>> + >>>> >>>> ... the place you insert this is after non-RAM pages got filtered >>>> out already, so you''re applying an IOMEM permission check to a >>>> RAM page. >>>> >>>> Jan >>>> >>>>> if ( !(l1f & _PAGE_RW) || >>>>> !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) >>>>> return 0; >>> >>> If that''s true, then the check a few lines above is also applying IOMEM >>> checks to RAM pages. I can see non-privileged attempts being filtered >>> above, > > "above" refers to "if ( !iomem_access_permitted(pg_owner, mfn, mfn) )" > >> I can''t see how that would happen given this primary conditional >> >> if ( !mfn_valid(mfn) || >> (real_pg_owner = page_get_owner_and_reference(page)) == dom_io ) >> >> Please clarify what you''re observing. > > As I understand it, the contents of this block will be executed if the MFN > is > invalid (interpreted as MMIO space) or if the page''s owner is DOMID_IO, > which > is how MMIO space is marked. > >>> but successful mappings will continue to the check I added. >> >> Of course. I would think that if anything, you would want to add >> a second call to iomem_access_permitted() with "curr->domain" >> right at the place where the current one is (in particular inside >> the above quoted conditional). >> >> Jan > > I was emulating the existing iomem_access_permitted check being run on > pg_owner; > moving the curr->domain check up into this first conditional would end up > treating the MMIO mapping as a regular RAM mapping if the > iomem_access_permitted > fails. Unless you''re talking about a different quoted conditional?I''m sorry, each of your replies get me more confused. Can you, with the current code (i.e. without your patches or any emulation you might be doing) explain (perhaps with an example) what specific case you see needing more checking than there is currently? That would probably allow us to start talking about the same thing. Jan
On 09/13/2012 10:37 AM, Ian Jackson wrote:> Daniel De Graaf writes ("[Xen-devel] [PATCH v3] Merge IS_PRIV checks into XSM hooks"): >> The ARM architecture is not touched at all in these patches; however, >> none of the changes should affect ARM. XSM hooks will need to be added >> for the arch-specific controls in order for FLASK to be useful on ARM, >> but those changes are outside the scope of this series. > > By "not useful" I guess you mean that it wouldn''t have the desired > security property. Is there already something that will prevent > attempts to use xsm on arm ? The code which enforces this should > ideally have a comment listing everything that was done to x86 but not > to arm, so that we have a useful todo list and don''t miss anything > before enabling xsm on arm. > > Ian. >Correct, XSM itself should work (i.e. boot and not crash) on ARM, assuming there is support for loading a policy and the xsm_op hypercall is wired up. The reason I noted that FLASK is not currently useful is the lack of XSM hooks in various arch-specific functions (do_hvm_op and arch_memory_op are the ones I have looked at). Adding these hooks requires moving some of the definitions out of the #ifdef CONFIG_X86 blocks in the XSM code. The ARM support in xen-unstable.h doesn''t currently have any domctls or sysctls defined; when it does, they will need to be added to the list of hooks in flask_domctl/flask_sysctl with either an access check or a pass-through due to the use of another hook. If not, they will trigger a printk and be denied, so it''s fairly easy to catch this. Beyond the places where IS_PRIV is checked, FLASK hooks to control access to hardware need to be added where there are ARM-specific functions. For x86, this involved I/O ports, IRQ<->PIRQ mapping, and PCI device access; some of these will apply to ARM if device passthrough is supported there. -- Daniel De Graaf National Security Agency
Daniel De Graaf writes ("Re: [Xen-devel] [PATCH v3] Merge IS_PRIV checks into XSM hooks"):> On 09/13/2012 10:37 AM, Ian Jackson wrote: > The ARM support in xen-unstable.h doesn''t currently have any domctls or > sysctls defined; when it does, they will need to be added to the list of > hooks in flask_domctl/flask_sysctl with either an access check or a > pass-through due to the use of another hook. If not, they will trigger a > printk and be denied, so it''s fairly easy to catch this.That last sentence is very reassuring to me. I was just wanting to check that users weren''t liable to try to use xsm and not notice that it wasn''t complete - and that when we did try to complete xsm on arm we would avoid accidentally missing anything. Thanks, Ian.
Daniel De Graaf
2012-Sep-13 16:46 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
On 09/13/2012 11:04 AM, Jan Beulich wrote:>>>> On 13.09.12 at 16:25, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> On 09/13/2012 10:13 AM, Jan Beulich wrote: >>>>>> On 13.09.12 at 15:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>> On 09/13/2012 04:00 AM, Jan Beulich wrote: >>>>>>>> On 12.09.12 at 17:59, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>>>> When a domain is mapping pages from a different pg_owner domain, the >>>>>> iomem_access checks are currently only applied to the pg_owner domain, >>>>>> potentially allowing the current domain to bypass its more restrictive >>>>>> iomem_access policy using another domain that it has access to. >>>>> >>>>> Are you sure about this? I ask because ... >>>>> >>>>>> --- a/xen/arch/x86/mm.c >>>>>> +++ b/xen/arch/x86/mm.c >>>>>> @@ -754,6 +754,18 @@ get_page_from_l1e( >>>>>> return -EINVAL; >>>>>> } >>>>>> >>>>>> + if ( pg_owner != curr->domain && >>>>>> + !iomem_access_permitted(curr->domain, mfn, mfn) ) >>>>>> + { >>>>>> + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ >>>>>> + { >>>>>> + MEM_LOG("Domain %u attempted to map I/O space %08lx in >>>> domain %u", >>>>>> + curr->domain->domain_id, mfn, pg_owner->domain_id); >>>>>> + return -EPERM; >>>>>> + } >>>>>> + return -EINVAL; >>>>>> + } >>>>>> + >>>>> >>>>> ... the place you insert this is after non-RAM pages got filtered >>>>> out already, so you''re applying an IOMEM permission check to a >>>>> RAM page. >>>>> >>>>> Jan >>>>> >>>>>> if ( !(l1f & _PAGE_RW) || >>>>>> !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) >>>>>> return 0; >>>> >>>> If that''s true, then the check a few lines above is also applying IOMEM >>>> checks to RAM pages. I can see non-privileged attempts being filtered >>>> above, >> >> "above" refers to "if ( !iomem_access_permitted(pg_owner, mfn, mfn) )" >> >>> I can''t see how that would happen given this primary conditional >>> >>> if ( !mfn_valid(mfn) || >>> (real_pg_owner = page_get_owner_and_reference(page)) == dom_io ) >>> >>> Please clarify what you''re observing. >> >> As I understand it, the contents of this block will be executed if the MFN >> is >> invalid (interpreted as MMIO space) or if the page''s owner is DOMID_IO, >> which >> is how MMIO space is marked. >> >>>> but successful mappings will continue to the check I added. >>> >>> Of course. I would think that if anything, you would want to add >>> a second call to iomem_access_permitted() with "curr->domain" >>> right at the place where the current one is (in particular inside >>> the above quoted conditional). >>> >>> Jan >> >> I was emulating the existing iomem_access_permitted check being run on >> pg_owner; >> moving the curr->domain check up into this first conditional would end up >> treating the MMIO mapping as a regular RAM mapping if the >> iomem_access_permitted >> fails. Unless you''re talking about a different quoted conditional? > > I''m sorry, each of your replies get me more confused. Can you, > with the current code (i.e. without your patches or any emulation > you might be doing) explain (perhaps with an example) what > specific case you see needing more checking than there is > currently? That would probably allow us to start talking about the > same thing. > > Jan >For this example, assume domain A has access to map domain B''s memory read-only. Domain B has access to a device with MMIO where reads to the device''s memory cause state changes - an example of such as device is a TPM, where replies are read by repeated reads to a single 4-byte address. Domain A does not have access to this device, and would like to maliciously interfere with the device. If domain A maps the MMIO page from domain B using pg_owner == domB, the iomem_access_permitted check will be done from domain B''s perspective. While this is needed when domain A is mapping pages on behalf of domB, it is not sufficient when attempting to constrain domain A''s access. These checks only apply to MMIO, so the condition on line 735 will evaluate to true (!mfn_valid || real_pg_owner == dom_io). The (existing) check on domain B''s MMIO access is: if ( !iomem_access_permitted(pg_owner, mfn, mfn) ) This patch adds a check on domain A: if ( !iomem_access_permitted(curr->domain, mfn, mfn) ) This extra checking has not been required without XSM because only FLASK implements the ability to grant one domain read-only access to another domain. With read-write access, this extra access check is simple to get around: domain A can modify some part of the executable code in domain B to act as a proxy for its accesses. Additionally, domain A is usually dom0 or the device model, which have equal or greater MMIO access. -- Daniel De Graaf National Security Agency
Jan Beulich
2012-Sep-14 08:54 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
>>> On 13.09.12 at 18:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > For this example, assume domain A has access to map domain B''s memory > read-only. Domain B has access to a device with MMIO where reads to the > device''s memory cause state changes - an example of such as device is a > TPM, where replies are read by repeated reads to a single 4-byte > address. Domain A does not have access to this device, and would like to > maliciously interfere with the device. > > If domain A maps the MMIO page from domain B using pg_owner == domB, the > iomem_access_permitted check will be done from domain B''s perspective. > While this is needed when domain A is mapping pages on behalf of domB, > it is not sufficient when attempting to constrain domain A''s access. > > These checks only apply to MMIO, so the condition on line 735 will > evaluate to true (!mfn_valid || real_pg_owner == dom_io). > > The (existing) check on domain B''s MMIO access is: > if ( !iomem_access_permitted(pg_owner, mfn, mfn) ) > > This patch adds a check on domain A: > if ( !iomem_access_permitted(curr->domain, mfn, mfn) )So then I think I was right suggesting that the second check should be done at the same place where the first one is, not outside/after the MMIO conditional.> This extra checking has not been required without XSM because only FLASK > implements the ability to grant one domain read-only access to another > domain. With read-write access, this extra access check is simple to get > around: domain A can modify some part of the executable code in domain B > to act as a proxy for its accesses. Additionally, domain A is usually > dom0 or the device model, which have equal or greater MMIO access.Understood. Jan
Daniel De Graaf
2012-Sep-14 13:37 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
On 09/14/2012 04:54 AM, Jan Beulich wrote:>>>> On 13.09.12 at 18:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> For this example, assume domain A has access to map domain B''s memory >> read-only. Domain B has access to a device with MMIO where reads to the >> device''s memory cause state changes - an example of such as device is a >> TPM, where replies are read by repeated reads to a single 4-byte >> address. Domain A does not have access to this device, and would like to >> maliciously interfere with the device. >> >> If domain A maps the MMIO page from domain B using pg_owner == domB, the >> iomem_access_permitted check will be done from domain B''s perspective. >> While this is needed when domain A is mapping pages on behalf of domB, >> it is not sufficient when attempting to constrain domain A''s access. >> >> These checks only apply to MMIO, so the condition on line 735 will >> evaluate to true (!mfn_valid || real_pg_owner == dom_io). >> >> The (existing) check on domain B''s MMIO access is: >> if ( !iomem_access_permitted(pg_owner, mfn, mfn) ) >> >> This patch adds a check on domain A: >> if ( !iomem_access_permitted(curr->domain, mfn, mfn) ) > > So then I think I was right suggesting that the second check > should be done at the same place where the first one is, not > outside/after the MMIO conditional.That is where I am doing the second check; it is not outside the MMIO conditional (which ends 8 lines after the inserted check).>> This extra checking has not been required without XSM because only FLASK >> implements the ability to grant one domain read-only access to another >> domain. With read-write access, this extra access check is simple to get >> around: domain A can modify some part of the executable code in domain B >> to act as a proxy for its accesses. Additionally, domain A is usually >> dom0 or the device model, which have equal or greater MMIO access. > > Understood. > > Jan
Jan Beulich
2012-Sep-14 14:21 UTC
Re: [PATCH 19/22] arch/x86: check remote MMIO remap permissions
>>> On 14.09.12 at 15:37, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/14/2012 04:54 AM, Jan Beulich wrote: >>>>> On 13.09.12 at 18:46, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> For this example, assume domain A has access to map domain B''s memory >>> read-only. Domain B has access to a device with MMIO where reads to the >>> device''s memory cause state changes - an example of such as device is a >>> TPM, where replies are read by repeated reads to a single 4-byte >>> address. Domain A does not have access to this device, and would like to >>> maliciously interfere with the device. >>> >>> If domain A maps the MMIO page from domain B using pg_owner == domB, the >>> iomem_access_permitted check will be done from domain B''s perspective. >>> While this is needed when domain A is mapping pages on behalf of domB, >>> it is not sufficient when attempting to constrain domain A''s access. >>> >>> These checks only apply to MMIO, so the condition on line 735 will >>> evaluate to true (!mfn_valid || real_pg_owner == dom_io). >>> >>> The (existing) check on domain B''s MMIO access is: >>> if ( !iomem_access_permitted(pg_owner, mfn, mfn) ) >>> >>> This patch adds a check on domain A: >>> if ( !iomem_access_permitted(curr->domain, mfn, mfn) ) >> >> So then I think I was right suggesting that the second check >> should be done at the same place where the first one is, not >> outside/after the MMIO conditional. > > That is where I am doing the second check; it is not outside the MMIO > conditional (which ends 8 lines after the inserted check).Then I must have got the context wrong when looking for the insertion place. Checking... Indeed, I didn''t pay close enough attention. Sorry for all the complaints then. Jan