Changes from v3: * Moved x86-specific sysctls into #ifdef CONFIG_X86 in flask/hooks.c * Removed pt_domain parameter from mmu_update hook when unused * Renamed xsm___do_xsm_op to xsm_do_xsm_op * Added struct domain* argument to arch_do_domctl * Cleaned up mem_event code duplication 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 Miscellaneous updates to FLASK: [PATCH 01/23] xsm/flask: remove inherited class attributes [PATCH 02/23] xsm/flask: remove unneeded create_sid field [PATCH 04/23] xsm/flask: add domain relabel support [PATCH 05/23] libxl: introduce XSM relabel on build [PATCH 06/23] flask/policy: Add domain relabel example [PATCH 08/23] xsm/flask: Add checks on the domain performing the Preparatory new functions/hooks: [PATCH 03/23] xen: Add versions of rcu_lock_*_domain without IS_PRIV [PATCH 07/23] arch/x86: add distinct XSM hooks for map/unmap [PATCH 13/23] xen: lock target domain in do_domctl common code IS_PRIV Refactoring: [PATCH 09/23] xsm: Use the dummy XSM module if XSM is disabled [PATCH 10/23] xen: use XSM instead of IS_PRIV where duplicated [PATCH 11/23] xen: avoid calling rcu_lock_*target_domain when an XSM [PATCH 12/23] arch/x86: convert platform_hypercall to use XSM [PATCH 14/23] xen: convert do_domctl to use XSM [PATCH 15/23] xen: convert do_sysctl to use XSM Additional new/updated hooks: [PATCH 16/23] xsm/flask: add missing hooks [PATCH 17/23] xsm/flask: add distinct SIDs for self/target access [PATCH 18/23] arch/x86: Add missing mem_sharing XSM hooks [PATCH 19/23] arch/x86: check remote MMIO remap permissions [PATCH 20/23] arch/x86: use XSM hooks for get_pg_owner access checks [PATCH 21/23] xen: Add XSM hook for XENMEM_exchange [PATCH 22/23] tmem: add XSM hooks [PATCH 23/23] xen/arch/*: add struct domain parameter to arch_do_domctl
Daniel De Graaf
2012-Sep-17 15:23 UTC
[PATCH 01/23] 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-17 15:23 UTC
[PATCH 02/23] 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-17 15:23 UTC
[PATCH 03/23] 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 7eb5743..60391c6 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -2158,6 +2158,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 1627cac..ecea26a 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -596,16 +596,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-17 15:23 UTC
[PATCH 06/23] 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-17 15:23 UTC
[PATCH 07/23] 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 f4e5705..da70e35 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -803,6 +803,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); @@ -840,7 +844,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; @@ -902,7 +906,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-17 15:23 UTC
[PATCH 08/23] 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-17 15:23 UTC
[PATCH 09/23] 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 | 294 +++++++++++------------ xen/xsm/dummy.c | 619 +---------------------------------------------- xen/xsm/flask/hooks.c | 2 +- xen/xsm/xsm_core.c | 2 +- 6 files changed, 776 insertions(+), 771 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..0456bc8 --- /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..1a63c27 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 @@ -141,7 +135,7 @@ struct xsm_operations { int (*cpupool_op)(void); int (*sched_op)(void); - long (*__do_xsm_op) (XEN_GUEST_HANDLE(xsm_op_t) op); + long (*do_xsm_op) (XEN_GUEST_HANDLE(xsm_op_t) op); #ifdef CONFIG_X86 int (*shadow_control) (struct domain *d, uint32_t op); @@ -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()); -} - -static inline long __do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) -{ -#ifdef XSM_ENABLE - return xsm_ops->__do_xsm_op(op); -#else - return -ENOSYS; -#endif + return xsm_ops->sched_op(); } -#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 *)) +static inline long xsm_do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { - return 0; + return xsm_ops->do_xsm_op(op); } -#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..47192d7 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; @@ -732,7 +119,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, cpupool_op); set_to_dummy_if_null(ops, sched_op); - set_to_dummy_if_null(ops, __do_xsm_op); + set_to_dummy_if_null(ops, do_xsm_op); #ifdef CONFIG_X86 set_to_dummy_if_null(ops, shadow_control); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6d4b4f0..7cc06a8 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1555,7 +1555,7 @@ static struct xsm_operations flask_ops = { .cpupool_op = flask_cpupool_op, .sched_op = flask_sched_op, - .__do_xsm_op = do_flask_op, + .do_xsm_op = do_flask_op, #ifdef CONFIG_X86 .shadow_control = flask_shadow_control, diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c index 96c8669..9bf6ab9 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-17 15:23 UTC
[PATCH 10/23] 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 f60d14f..9578194 100644 --- a/xen/arch/x86/cpu/mcheck/mce.c +++ b/xen/arch/x86/cpu/mcheck/mce.c @@ -1372,9 +1372,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 0456bc8..7cb229d 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 7cc06a8..90b0388 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-17 15:23 UTC
[PATCH 11/23] 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 dfabe20..a21c9d2 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3329,7 +3329,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; @@ -3494,7 +3494,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; @@ -3538,7 +3538,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; @@ -3568,7 +3568,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; @@ -3665,9 +3665,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) ) @@ -3911,7 +3911,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; @@ -3950,7 +3950,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; @@ -4000,9 +4000,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 ) @@ -4047,7 +4047,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; @@ -4126,7 +4126,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; @@ -4161,7 +4161,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; @@ -4197,9 +4197,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) ) @@ -4251,7 +4251,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 5bcb035..a984d51 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 7cb229d..448b5c1 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-17 15:23 UTC
[PATCH 12/23] 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 448b5c1..c7ee659 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 1a63c27..028661b 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 47192d7..10f9c47 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 90b0388..2a44a76 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-17 15:23 UTC
[PATCH 13/23] 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 | 268 ++++++++++++---------------------------------------- 1 file changed, 59 insertions(+), 209 deletions(-) diff --git a/xen/common/domctl.c b/xen/common/domctl.c index d99ba67..ef2700d 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,29 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) switch ( op->cmd ) { + case XEN_DOMCTL_createdomain: + case XEN_DOMCTL_getdomaininfo: + case XEN_DOMCTL_test_assign_device: + 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 +287,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 +352,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 +443,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 +455,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 +551,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 +594,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 +638,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 +695,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 +726,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 +749,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 +794,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 +807,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 +889,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 da70e35..24e2d93 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1478,7 +1478,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 ef2700d..76f0f90 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -264,27 +264,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() ) { @@ -858,17 +840,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 c7ee659..9d70587 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 2a44a76..7caab52 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 | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 51 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 9d70587..626a332 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 028661b..96e4b13 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 10f9c47..43e8617 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 7caab52..635f91c 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -675,6 +675,38 @@ 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_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_pm_op: + case XEN_SYSCTL_page_offline_op: + case XEN_SYSCTL_lockprof_op: + case XEN_SYSCTL_cpupool_op: + case XEN_SYSCTL_scheduler_op: +#ifdef CONFIG_X86 + case XEN_SYSCTL_physinfo: + case XEN_SYSCTL_cpu_hotplug: + case XEN_SYSCTL_topologyinfo: + case XEN_SYSCTL_numainfo: +#endif + 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 +1633,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 635f91c..089faf8 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; @@ -921,6 +928,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; @@ -1128,7 +1140,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; @@ -1151,6 +1162,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); @@ -1209,6 +1225,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; @@ -1246,6 +1281,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); @@ -1689,6 +1729,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, @@ -1713,10 +1754,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, @@ -1749,6 +1792,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-17 15:23 UTC
[PATCH 17/23] 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 089faf8..a242d65 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); @@ -716,7 +738,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) @@ -741,20 +763,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) @@ -816,14 +835,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; @@ -839,14 +856,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; } @@ -854,16 +870,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; @@ -873,19 +885,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; }; @@ -899,12 +911,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) @@ -912,7 +924,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; @@ -922,8 +934,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); } @@ -935,10 +947,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); @@ -951,33 +962,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) @@ -985,7 +987,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 ) @@ -993,8 +994,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) @@ -1002,7 +1002,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 ) @@ -1010,8 +1009,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) @@ -1019,7 +1017,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 ) @@ -1027,8 +1024,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) @@ -1036,22 +1032,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) @@ -1114,11 +1105,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; }; @@ -1132,12 +1124,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) @@ -1145,7 +1137,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 ) @@ -1156,8 +1148,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); } @@ -1169,18 +1161,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) @@ -1203,7 +1194,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) @@ -1222,7 +1213,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) @@ -1263,37 +1254,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) @@ -1355,11 +1346,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) @@ -1421,16 +1408,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) @@ -1453,17 +1436,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); @@ -1506,43 +1489,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; @@ -1552,22 +1532,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; @@ -1575,18 +1553,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; @@ -1596,23 +1573,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) @@ -1631,7 +1607,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) @@ -1650,7 +1626,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-17 15:23 UTC
[PATCH 18/23] 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 changes the utility function get_mem_event_op_target to rcu_lock_live_remote_domain_by_id because there is no mm-specific logic in there. 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 | 41 ++++++++------------------ xen/arch/x86/mm/mem_sharing.c | 25 +++++++++++++--- xen/common/domain.c | 15 ++++++++++ xen/include/asm-x86/mem_event.h | 1 - xen/include/xen/sched.h | 6 ++++ 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 + 13 files changed, 130 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 24e2d93..7062f02 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1447,10 +1447,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); } @@ -1506,7 +1504,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..950209b 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,35 +440,19 @@ 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); - if ( !d ) + ret = rcu_lock_live_remote_domain_by_id(domain, &d); + if ( ret ) return ret; + ret = xsm_mem_event_op(d, op); + if ( ret ) + goto out; + switch (op) { case XENMEM_paging_op: @@ -483,6 +468,7 @@ int do_mem_event_op(int op, uint32_t domain, void *arg) ret = -ENOSYS; } + out: rcu_unlock_domain(d); return ret; } @@ -516,6 +502,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 +527,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..9229b83 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,10 +1346,18 @@ 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); - if ( !cd ) + rc = rcu_lock_live_remote_domain_by_id(mec->u.share.client_domain, + &cd); + if ( rc ) return rc; + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); + return rc; + } + if ( !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); @@ -1401,10 +1410,18 @@ 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); - if ( !cd ) + rc = rcu_lock_live_remote_domain_by_id(mec->u.share.client_domain, + &cd); + if ( rc ) return rc; + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); + return rc; + } + if ( !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); diff --git a/xen/common/domain.c b/xen/common/domain.c index 52489b3..a205557 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -475,6 +475,21 @@ int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d) return 0; } +int rcu_lock_live_remote_domain_by_id(domid_t dom, struct domain **d) +{ + int rv; + rv = rcu_lock_remote_domain_by_id(dom, d); + if ( rv ) + return rv; + if ( (*d)->is_dying ) + { + rcu_unlock_domain(*d); + return -EINVAL; + } + + return 0; +} + int domain_kill(struct domain *d) { int rc = 0; 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/xen/sched.h b/xen/include/xen/sched.h index b0def4a..b29ed13 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -471,6 +471,12 @@ int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d); */ int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d); +/* + * As rcu_lock_remote_domain_by_id() but will fail EINVAL if the domain is + * dying. + */ +int rcu_lock_live_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) { diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 626a332..5fb0afe 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 96e4b13..c08a664 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 43e8617..3926b2b 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 a242d65..65db2b7 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1277,7 +1277,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); } @@ -1287,6 +1297,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; @@ -1736,8 +1754,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-17 15:23 UTC
[PATCH 19/23] 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-17 15:23 UTC
[PATCH 20/23] 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..6e99b56 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, NULL, 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 5fb0afe..dafecea 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 ( t && 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 c08a664..6c78240 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 3926b2b..588f367 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 65db2b7..cfa3683 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1434,65 +1434,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 ( t && 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) @@ -1773,8 +1752,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 a984d51..edfaf3c 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 dafecea..331c423 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 6c78240..db4902d 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 588f367..26e04d5 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 cfa3683..a0f34b9 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); @@ -1685,6 +1690,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 331c423..277470b 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 db4902d..8eb3775 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 26e04d5..6e113fb 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 a0f34b9..b59e4bb 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1079,6 +1079,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); @@ -1723,6 +1733,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
Daniel De Graaf
2012-Sep-17 15:23 UTC
[PATCH 23/23] xen/arch/*: add struct domain parameter to arch_do_domctl
Since the arch-independent do_domctl function now RCU locks the domain specified by op->domain, pass the struct domain to the arch-specific domctl function and remove the duplicate per-subfunction locking. This also removes two get_domain/put_domain call pairs (in XEN_DOMCTL_assign_device and XEN_DOMCTL_deassign_device), replacing them with RCU locking. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Stefano Stabellini <stefano.stabellini@citrix.com> Cc: Tim Deegan <tim@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/arch/arm/domctl.c | 2 +- xen/arch/x86/domctl.c | 434 +++++++--------------------------------- xen/common/domctl.c | 2 +- xen/drivers/passthrough/iommu.c | 31 +-- xen/include/xen/hypercall.h | 2 +- xen/include/xen/iommu.h | 3 +- 6 files changed, 76 insertions(+), 398 deletions(-) diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index 1a5f79f..12531d1 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -10,7 +10,7 @@ #include <xen/errno.h> #include <public/domctl.h> -long arch_do_domctl(struct xen_domctl *domctl, +long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) { return -ENOSYS; diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 7062f02..734b2f2 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -47,7 +47,7 @@ static int gdbsx_guest_mem_io( } long arch_do_domctl( - struct xen_domctl *domctl, + struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) { long ret = 0; @@ -57,23 +57,15 @@ long arch_do_domctl( case XEN_DOMCTL_shadow_op: { - struct domain *d; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d != NULL ) - { - ret = paging_domctl(d, - &domctl->u.shadow_op, - guest_handle_cast(u_domctl, void)); - rcu_unlock_domain(d); - copy_to_guest(u_domctl, domctl, 1); - } + ret = paging_domctl(d, + &domctl->u.shadow_op, + guest_handle_cast(u_domctl, void)); + copy_to_guest(u_domctl, domctl, 1); } break; case XEN_DOMCTL_ioport_permission: { - struct domain *d; unsigned int fp = domctl->u.ioport_permission.first_port; unsigned int np = domctl->u.ioport_permission.nr_ports; int allow = domctl->u.ioport_permission.allow_access; @@ -82,10 +74,6 @@ long arch_do_domctl( if ( (fp + np) > 65536 ) break; - ret = -ESRCH; - if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) - break; - if ( np == 0 ) ret = 0; else if ( xsm_ioport_permission(d, fp, fp + np - 1, allow) ) @@ -94,8 +82,6 @@ long arch_do_domctl( ret = ioports_permit_access(d, fp, fp + np - 1); else ret = ioports_deny_access(d, fp, fp + np - 1); - - rcu_unlock_domain(d); } break; @@ -103,23 +89,16 @@ long arch_do_domctl( { struct page_info *page; unsigned long mfn = domctl->u.getpageframeinfo.gmfn; - domid_t dom = domctl->domain; - struct domain *d; ret = -EINVAL; - - if ( unlikely(!mfn_valid(mfn)) || - unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) + if ( unlikely(!mfn_valid(mfn)) ) break; page = mfn_to_page(mfn); ret = xsm_getpageframeinfo(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } if ( likely(get_page(page, d)) ) { @@ -149,8 +128,6 @@ long arch_do_domctl( put_page(page); } - rcu_unlock_domain(d); - copy_to_guest(u_domctl, domctl, 1); } break; @@ -160,27 +137,17 @@ long arch_do_domctl( { unsigned int n, j; unsigned int num = domctl->u.getpageframeinfo3.num; - domid_t dom = domctl->domain; - struct domain *d; struct page_info *page; xen_pfn_t *arr; - ret = -ESRCH; - if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) - break; - ret = xsm_getpageframeinfo(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } if ( unlikely(num > 1024) || unlikely(num != domctl->u.getpageframeinfo3.num) ) { ret = -E2BIG; - rcu_unlock_domain(d); break; } @@ -188,7 +155,6 @@ long arch_do_domctl( if ( !page ) { ret = -ENOMEM; - rcu_unlock_domain(d); break; } arr = page_to_virt(page); @@ -254,7 +220,6 @@ long arch_do_domctl( free_domheap_page(virt_to_page(arr)); - rcu_unlock_domain(d); break; } /* fall thru */ @@ -262,25 +227,15 @@ long arch_do_domctl( { int n,j; int num = domctl->u.getpageframeinfo2.num; - domid_t dom = domctl->domain; - struct domain *d; uint32_t *arr32; - ret = -ESRCH; - - if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) - break; ret = xsm_getpageframeinfo(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } if ( unlikely(num > 1024) ) { ret = -E2BIG; - rcu_unlock_domain(d); break; } @@ -288,7 +243,6 @@ long arch_do_domctl( if ( !arr32 ) { ret = -ENOMEM; - rcu_unlock_domain(d); break; } @@ -360,78 +314,58 @@ long arch_do_domctl( } free_xenheap_page(arr32); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_getmemlist: { int i; - struct domain *d = rcu_lock_domain_by_id(domctl->domain); unsigned long max_pfns = domctl->u.getmemlist.max_pfns; uint64_t mfn; struct page_info *page; - ret = -EINVAL; - if ( d != NULL ) - { - ret = xsm_getmemlist(d); - if ( ret ) - { - rcu_unlock_domain(d); - break; - } + ret = xsm_getmemlist(d); + if ( ret ) + break; - spin_lock(&d->page_alloc_lock); + if ( unlikely(d->is_dying) ) { + ret = -EINVAL; + break; + } - if ( unlikely(d->is_dying) ) { - spin_unlock(&d->page_alloc_lock); - goto getmemlist_out; - } + spin_lock(&d->page_alloc_lock); - ret = i = 0; - page_list_for_each(page, &d->page_list) + ret = i = 0; + page_list_for_each(page, &d->page_list) + { + if ( i >= max_pfns ) + break; + mfn = page_to_mfn(page); + if ( copy_to_guest_offset(domctl->u.getmemlist.buffer, + i, &mfn, 1) ) { - if ( i >= max_pfns ) - break; - mfn = page_to_mfn(page); - if ( copy_to_guest_offset(domctl->u.getmemlist.buffer, - i, &mfn, 1) ) - { - ret = -EFAULT; - break; - } - ++i; + ret = -EFAULT; + break; } - - spin_unlock(&d->page_alloc_lock); - - domctl->u.getmemlist.num_pfns = i; - copy_to_guest(u_domctl, domctl, 1); - getmemlist_out: - rcu_unlock_domain(d); + ++i; } + + spin_unlock(&d->page_alloc_lock); + + domctl->u.getmemlist.num_pfns = i; + copy_to_guest(u_domctl, domctl, 1); } break; case XEN_DOMCTL_hypercall_init: { - struct domain *d = rcu_lock_domain_by_id(domctl->domain); unsigned long gmfn = domctl->u.hypercall_init.gmfn; struct page_info *page; void *hypercall_page; - ret = -ESRCH; - if ( unlikely(d == NULL) ) - break; - ret = xsm_hypercall_init(d); if ( ret ) - { - rcu_unlock_domain(d); break; - } page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); @@ -440,7 +374,6 @@ long arch_do_domctl( { if ( page ) put_page(page); - rcu_unlock_domain(d); break; } @@ -451,19 +384,12 @@ long arch_do_domctl( unmap_domain_page(hypercall_page); put_page_and_type(page); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_sethvmcontext: { struct hvm_domain_context c = { .size = domctl->u.hvmcontext.size }; - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; ret = xsm_hvmcontext(d, domctl->cmd); if ( ret ) @@ -488,19 +414,12 @@ long arch_do_domctl( sethvmcontext_out: if ( c.data != NULL ) xfree(c.data); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gethvmcontext: { struct hvm_domain_context c = { 0 }; - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; ret = xsm_hvmcontext(d, domctl->cmd); if ( ret ) @@ -544,53 +463,33 @@ long arch_do_domctl( if ( c.data != NULL ) xfree(c.data); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gethvmcontext_partial: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_hvmcontext(d, domctl->cmd); if ( ret ) - goto gethvmcontext_partial_out; + break; ret = -EINVAL; if ( !is_hvm_domain(d) ) - goto gethvmcontext_partial_out; + break; domain_pause(d); ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type, domctl->u.hvmcontext_partial.instance, domctl->u.hvmcontext_partial.buffer); domain_unpause(d); - - gethvmcontext_partial_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_set_address_size: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_address_size(d, domctl->cmd); if ( ret ) - { - rcu_unlock_domain(d); break; - } switch ( domctl->u.address_size.size ) { @@ -604,31 +503,19 @@ long arch_do_domctl( ret = (domctl->u.address_size.size == BITS_PER_LONG) ? 0 : -EINVAL; break; } - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_get_address_size: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_address_size(d, domctl->cmd); if ( ret ) - { - rcu_unlock_domain(d); break; - } domctl->u.address_size.size is_pv_32on64_domain(d) ? 32 : BITS_PER_LONG; ret = 0; - rcu_unlock_domain(d); if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; @@ -637,76 +524,51 @@ long arch_do_domctl( case XEN_DOMCTL_set_machine_address_size: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_machine_address_size(d, domctl->cmd); if ( ret ) - goto set_machine_address_size_out; + break; ret = -EBUSY; if ( d->tot_pages > 0 ) - goto set_machine_address_size_out; + break; d->arch.physaddr_bitsize = domctl->u.address_size.size; ret = 0; - set_machine_address_size_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_get_machine_address_size: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_machine_address_size(d, domctl->cmd); if ( ret ) - { - rcu_unlock_domain(d); break; - } domctl->u.address_size.size = d->arch.physaddr_bitsize; ret = 0; - rcu_unlock_domain(d); if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; - - } break; case XEN_DOMCTL_sendtrigger: { - struct domain *d; struct vcpu *v; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = xsm_sendtrigger(d); if ( ret ) - goto sendtrigger_out; + break; ret = -EINVAL; if ( domctl->u.sendtrigger.vcpu >= MAX_VIRT_CPUS ) - goto sendtrigger_out; + break; ret = -ESRCH; if ( domctl->u.sendtrigger.vcpu >= d->max_vcpus || (v = d->vcpu[domctl->u.sendtrigger.vcpu]) == NULL ) - goto sendtrigger_out; + break; switch ( domctl->u.sendtrigger.trigger ) { @@ -743,34 +605,27 @@ long arch_do_domctl( default: ret = -ENOSYS; } - - sendtrigger_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_bind_pt_irq: { - struct domain * d; xen_domctl_bind_pt_irq_t * bind; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; bind = &(domctl->u.bind_pt_irq); ret = -EINVAL; if ( !is_hvm_domain(d) ) - goto bind_out; + break; ret = xsm_bind_pt_irq(d, bind); if ( ret ) - goto bind_out; + break; ret = -EPERM; if ( !IS_PRIV(current->domain) && !irq_access_permitted(current->domain, bind->machine_irq) ) - goto bind_out; + break; ret = -ESRCH; if ( iommu_enabled ) @@ -782,30 +637,23 @@ long arch_do_domctl( if ( ret < 0 ) printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n", ret, d->domain_id); - - bind_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_unbind_pt_irq: { - struct domain * d; xen_domctl_bind_pt_irq_t * bind; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; bind = &(domctl->u.bind_pt_irq); ret = -EPERM; if ( !IS_PRIV(current->domain) && !irq_access_permitted(current->domain, bind->machine_irq) ) - goto unbind_out; + break; ret = xsm_unbind_pt_irq(d, bind); if ( ret ) - goto unbind_out; + break; if ( iommu_enabled ) { @@ -816,15 +664,11 @@ long arch_do_domctl( if ( ret < 0 ) printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n", ret, d->domain_id); - - unbind_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_memory_mapping: { - struct domain *d; unsigned long gfn = domctl->u.memory_mapping.first_gfn; unsigned long mfn = domctl->u.memory_mapping.first_mfn; unsigned long nr_mfns = domctl->u.memory_mapping.nr_mfns; @@ -840,15 +684,9 @@ long arch_do_domctl( !iomem_access_permitted(current->domain, mfn, mfn + nr_mfns - 1) ) break; - ret = -ESRCH; - if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) - break; - ret = xsm_iomem_mapping(d, mfn, mfn + nr_mfns - 1, add); - if ( ret ) { - rcu_unlock_domain(d); + if ( ret ) break; - } if ( add ) { @@ -870,15 +708,12 @@ long arch_do_domctl( clear_mmio_p2m_entry(d, gfn+i); ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1); } - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_ioport_mapping: { #define MAX_IOPORTS 0x10000 - struct domain *d; struct hvm_iommu *hd; unsigned int fgp = domctl->u.ioport_mapping.first_gport; unsigned int fmp = domctl->u.ioport_mapping.first_mport; @@ -902,15 +737,9 @@ long arch_do_domctl( !ioports_access_permitted(current->domain, fmp, fmp + np - 1) ) break; - ret = -ESRCH; - if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) - break; - ret = xsm_ioport_mapping(d, fmp, fmp + np - 1, add); - if ( ret ) { - rcu_unlock_domain(d); + if ( ret ) break; - } hd = domain_hvm_iommu(d); if ( add ) @@ -951,30 +780,19 @@ long arch_do_domctl( } ret = ioports_deny_access(d, fmp, fmp + np - 1); } - rcu_unlock_domain(d); } break; case XEN_DOMCTL_pin_mem_cacheattr: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - ret = xsm_pin_mem_cacheattr(d); if ( ret ) - goto pin_out; + break; ret = hvm_set_mem_pinned_cacheattr( d, domctl->u.pin_mem_cacheattr.start, domctl->u.pin_mem_cacheattr.end, domctl->u.pin_mem_cacheattr.type); - - pin_out: - rcu_unlock_domain(d); } break; @@ -982,19 +800,13 @@ long arch_do_domctl( case XEN_DOMCTL_get_ext_vcpucontext: { struct xen_domctl_ext_vcpucontext *evc; - struct domain *d; struct vcpu *v; evc = &domctl->u.ext_vcpucontext; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - ret = xsm_ext_vcpucontext(d, domctl->cmd); if ( ret ) - goto ext_vcpucontext_out; + break; ret = -ESRCH; if ( (evc->vcpu >= d->max_vcpus) || @@ -1071,7 +883,6 @@ long arch_do_domctl( ret = 0; ext_vcpucontext_out: - rcu_unlock_domain(d); if ( (domctl->cmd == XEN_DOMCTL_get_ext_vcpucontext) && copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; @@ -1080,16 +891,10 @@ long arch_do_domctl( case XEN_DOMCTL_set_cpuid: { - struct domain *d; xen_domctl_cpuid_t *ctl = &domctl->u.cpuid; cpuid_input_t *cpuid = NULL; int i; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - for ( i = 0; i < MAX_CPUID_INPUT; i++ ) { cpuid = &d->arch.cpuids[i]; @@ -1112,21 +917,13 @@ long arch_do_domctl( memcpy(cpuid, ctl, sizeof(cpuid_input_t)); ret = 0; } - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gettscinfo: { - struct domain *d; xen_guest_tsc_info_t info; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - domain_pause(d); tsc_get_info(d, &info.tsc_mode, &info.elapsed_nsec, @@ -1137,20 +934,11 @@ long arch_do_domctl( else ret = 0; domain_unpause(d); - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_settscinfo: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - domain_pause(d); tsc_set_info(d, domctl->u.tsc_info.info.tsc_mode, domctl->u.tsc_info.info.elapsed_nsec, @@ -1158,138 +946,83 @@ long arch_do_domctl( domctl->u.tsc_info.info.incarnation); domain_unpause(d); - rcu_unlock_domain(d); ret = 0; } break; case XEN_DOMCTL_suppress_spurious_page_faults: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d != NULL ) - { - d->arch.suppress_spurious_page_faults = 1; - rcu_unlock_domain(d); - ret = 0; - } + d->arch.suppress_spurious_page_faults = 1; + ret = 0; } break; case XEN_DOMCTL_debug_op: { - struct domain *d; struct vcpu *v; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - ret = -EINVAL; if ( (domctl->u.debug_op.vcpu >= d->max_vcpus) || ((v = d->vcpu[domctl->u.debug_op.vcpu]) == NULL) ) - goto debug_op_out; + break; ret = -EINVAL; if ( !is_hvm_domain(d)) - goto debug_op_out; + break; ret = hvm_debug_op(v, domctl->u.debug_op.op); - - debug_op_out: - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gdbsx_guestmemio: { - struct domain *d; - - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - domctl->u.gdbsx_guest_memio.remain domctl->u.gdbsx_guest_memio.len; ret = gdbsx_guest_mem_io(domctl->domain, &domctl->u.gdbsx_guest_memio); if ( !ret && copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; - - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gdbsx_pausevcpu: { - struct domain *d; struct vcpu *v; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = -EBUSY; if ( !d->is_paused_by_controller ) - { - rcu_unlock_domain(d); break; - } ret = -EINVAL; if ( domctl->u.gdbsx_pauseunp_vcpu.vcpu >= MAX_VIRT_CPUS || (v = d->vcpu[domctl->u.gdbsx_pauseunp_vcpu.vcpu]) == NULL ) - { - rcu_unlock_domain(d); break; - } vcpu_pause(v); ret = 0; - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gdbsx_unpausevcpu: { - struct domain *d; struct vcpu *v; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - ret = -EBUSY; if ( !d->is_paused_by_controller ) - { - rcu_unlock_domain(d); break; - } ret = -EINVAL; if ( domctl->u.gdbsx_pauseunp_vcpu.vcpu >= MAX_VIRT_CPUS || (v = d->vcpu[domctl->u.gdbsx_pauseunp_vcpu.vcpu]) == NULL ) - { - rcu_unlock_domain(d); break; - } if ( !atomic_read(&v->pause_count) ) printk("WARN: Unpausing vcpu:%d which is not paused\n", v->vcpu_id); vcpu_unpause(v); ret = 0; - rcu_unlock_domain(d); } break; case XEN_DOMCTL_gdbsx_domstatus: { - struct domain *d; struct vcpu *v; - ret = -ESRCH; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - domctl->u.gdbsx_domstatus.vcpu_id = -1; domctl->u.gdbsx_domstatus.paused = d->is_paused_by_controller; if ( domctl->u.gdbsx_domstatus.paused ) @@ -1309,7 +1042,6 @@ long arch_do_domctl( ret = 0; if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; - rcu_unlock_domain(d); } break; @@ -1317,7 +1049,6 @@ long arch_do_domctl( case XEN_DOMCTL_getvcpuextstate: { struct xen_domctl_vcpuextstate *evc; - struct domain *d; struct vcpu *v; uint32_t offset = 0; uint64_t _xfeature_mask = 0; @@ -1328,12 +1059,6 @@ long arch_do_domctl( evc = &domctl->u.vcpuextstate; - ret = -ESRCH; - - d = rcu_lock_domain_by_id(domctl->domain); - if ( d == NULL ) - break; - ret = xsm_vcpuextstate(d, domctl->cmd); if ( ret ) goto vcpuextstate_out; @@ -1432,7 +1157,6 @@ long arch_do_domctl( ret = 0; vcpuextstate_out: - rcu_unlock_domain(d); if ( (domctl->cmd == XEN_DOMCTL_getvcpuextstate) && copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; @@ -1441,50 +1165,33 @@ long arch_do_domctl( case XEN_DOMCTL_mem_event_op: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d != NULL ) - { - 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); - } + ret = mem_event_domctl(d, &domctl->u.mem_event_op, + guest_handle_cast(u_domctl, void)); + copy_to_guest(u_domctl, domctl, 1); } break; case XEN_DOMCTL_mem_sharing_op: { - struct domain *d; - - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d != NULL ) - { - ret = xsm_mem_sharing(d); - if ( !ret ) - ret = mem_sharing_domctl(d, &domctl->u.mem_sharing_op); - rcu_unlock_domain(d); - } + ret = xsm_mem_sharing(d); + if ( !ret ) + ret = mem_sharing_domctl(d, &domctl->u.mem_sharing_op); } break; #if P2M_AUDIT case XEN_DOMCTL_audit_p2m: { - struct domain *d; - - ret = rcu_lock_remote_domain_by_id(domctl->domain, &d); - if ( ret != 0 ) + if ( d == current->domain ) + { + ret = -EPERM; break; + } audit_p2m(d, &domctl->u.audit_p2m.orphans, &domctl->u.audit_p2m.m2p_bad, &domctl->u.audit_p2m.p2m_bad); - rcu_unlock_domain(d); if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; } @@ -1493,29 +1200,22 @@ long arch_do_domctl( case XEN_DOMCTL_set_access_required: { - struct domain *d; struct p2m_domain* p2m; ret = -EPERM; - if ( current->domain->domain_id == domctl->domain ) + if ( current->domain == d ) break; - ret = -ESRCH; - d = rcu_lock_domain_by_id(domctl->domain); - if ( d != NULL ) - { - ret = xsm_mem_event_setup(d); - if ( !ret ) { - p2m = p2m_get_hostp2m(d); - p2m->access_required = domctl->u.access_required.access_required; - } - rcu_unlock_domain(d); - } + ret = xsm_mem_event_setup(d); + if ( !ret ) { + p2m = p2m_get_hostp2m(d); + p2m->access_required = domctl->u.access_required.access_required; + } } break; default: - ret = iommu_do_domctl(domctl, u_domctl); + ret = iommu_do_domctl(domctl, d, u_domctl); break; } diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 76f0f90..07c95a3 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -861,7 +861,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) break; default: - ret = arch_do_domctl(op, u_domctl); + ret = arch_do_domctl(op, d, u_domctl); break; } diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index b4cf16c..b3c66f8 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -526,10 +526,9 @@ void iommu_crash_shutdown(void) } int iommu_do_domctl( - struct xen_domctl *domctl, + struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) { - struct domain *d; u16 seg; u8 bus, devfn; int ret = 0; @@ -548,10 +547,6 @@ int iommu_do_domctl( if ( ret ) break; - ret = -EINVAL; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - seg = domctl->u.get_device_group.machine_sbdf >> 16; bus = (domctl->u.get_device_group.machine_sbdf >> 8) & 0xff; devfn = domctl->u.get_device_group.machine_sbdf & 0xff; @@ -572,7 +567,6 @@ int iommu_do_domctl( } if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; - rcu_unlock_domain(d); } break; @@ -595,20 +589,15 @@ int iommu_do_domctl( break; case XEN_DOMCTL_assign_device: - if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) || - unlikely(d->is_dying) ) + if ( unlikely(d->is_dying) ) { - printk(XENLOG_G_ERR - "XEN_DOMCTL_assign_device: get_domain_by_id() failed\n"); ret = -EINVAL; - if ( d ) - goto assign_device_out; break; } ret = xsm_assign_device(d, domctl->u.assign_device.machine_sbdf); if ( ret ) - goto assign_device_out; + break; seg = domctl->u.get_device_group.machine_sbdf >> 16; bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff; @@ -622,22 +611,12 @@ int iommu_do_domctl( seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), d->domain_id, ret); - assign_device_out: - put_domain(d); break; case XEN_DOMCTL_deassign_device: - if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) - { - printk(XENLOG_G_ERR - "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); - ret = -EINVAL; - break; - } - ret = xsm_deassign_device(d, domctl->u.assign_device.machine_sbdf); if ( ret ) - goto deassign_device_out; + break; seg = domctl->u.get_device_group.machine_sbdf >> 16; bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff; @@ -652,8 +631,6 @@ int iommu_do_domctl( seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), d->domain_id, ret); - deassign_device_out: - put_domain(d); break; default: diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index 1b71071..36796d2 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -37,7 +37,7 @@ do_domctl( extern long arch_do_domctl( - struct xen_domctl *domctl, + struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl); extern long diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h index 605c7b3..c2951a5 100644 --- a/xen/include/xen/iommu.h +++ b/xen/include/xen/iommu.h @@ -156,7 +156,8 @@ void iommu_crash_shutdown(void); void iommu_set_dom0_mapping(struct domain *d); void iommu_share_p2m_table(struct domain *d); -int iommu_do_domctl(struct xen_domctl *, XEN_GUEST_HANDLE(xen_domctl_t)); +int iommu_do_domctl(struct xen_domctl *, struct domain *d, + XEN_GUEST_HANDLE(xen_domctl_t)); void iommu_iotlb_flush(struct domain *d, unsigned long gfn, unsigned int page_count); void iommu_iotlb_flush_all(struct domain *d); -- 1.7.11.4
> From: Daniel De Graaf [mailto:dgdegra@tycho.nsa.gov] > Sent: Monday, September 17, 2012 9:24 AM > To: xen-devel@lists.xen.org > Cc: dgdegra@tycho.nsa.gov; keir@xen.org; Dan Magenheimer > Subject: [PATCH 22/23] tmem: add XSM hooks > > 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>Bearing in mind that I am not very familiar with the XSM code, this patch looks sane to me. Acked-by: Dan Magenheimer <dan.magenheimer@oracle.com>
Jan Beulich
2012-Sep-18 07:21 UTC
Re: [PATCH 19/23] arch/x86: check remote MMIO remap permissions
>>> On 17.09.12 at 17:23, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- 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) )On a second (or third?) look, I don''t think this is right - the current domain doesn''t matter here at all. What does matter is who''s page tables the mapping is to be put in (i.e. l1e_owner), which of course in certain cases ends up being the current domain. Jan> + { > + 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-18 14:09 UTC
Re: [PATCH 19/23] arch/x86: check remote MMIO remap permissions
On 09/18/2012 03:21 AM, Jan Beulich wrote:>>>> On 17.09.12 at 17:23, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> --- 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) ) > > On a second (or third?) look, I don''t think this is right - the current > domain doesn''t matter here at all. What does matter is who''s page > tables the mapping is to be put in (i.e. l1e_owner), which of course > in certain cases ends up being the current domain. > > JanIgnoring current->domain allows a malicious domain with access to remotely manipulate page tables to create a device mapping where the target domain doesn''t expect one. Except, now that I''ve said that ... any domain with the ability to change another domain''s page tables almost certainly can control execution in that target domain, so that attack doesn''t get you anywhere you couldn''t already go. Checking the page table owner for iomem access is useful here, I''ll change the patch to do that.>> + { >> + 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-19 17:23 UTC
[PATCH 19/23 v2] 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 a domain with a more restrictive iomem_access policy to have the pages mapped into its page tables. To catch this, also check the owner of the page tables. The current domain does not need to be checked because the ability to manipulate a domain''s page tables implies full access to the target domain, so checking that domain''s permission is sufficient. 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 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 5c6ea2d..ede92bd 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -754,6 +754,19 @@ get_page_from_l1e( return -EINVAL; } + if ( pg_owner != l1e_owner && + !iomem_access_permitted(l1e_owner, mfn, mfn) ) + { + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ + { + MEM_LOG("Domain %u attempted to map I/O space %08lx in domain %u to domain %u", + curr->domain->domain_id, mfn, pg_owner->domain_id, + l1e_owner->domain_id); + return -EPERM; + } + return -EINVAL; + } + if ( !(l1f & _PAGE_RW) || !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) return 0; -- 1.7.11.4
Jan Beulich
2012-Sep-20 06:52 UTC
Re: [PATCH 19/23 v2] arch/x86: check remote MMIO remap permissions
>>> On 19.09.12 at 19:23, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote:This looks good now to me, apart from minor (cosmetic) issues:> --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -754,6 +754,19 @@ get_page_from_l1e( > return -EINVAL; > } > > + if ( pg_owner != l1e_owner && > + !iomem_access_permitted(l1e_owner, mfn, mfn) ) > + { > + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ > + { > + MEM_LOG("Domain %u attempted to map I/O space %08lx in domain %u to domain %u",I''d prefer each of the "[Dd]omain %u" references to be "[Dd]om%d" instead - no need for excessively long log messages.> + curr->domain->domain_id, mfn, pg_owner->domain_id, > + l1e_owner->domain_id);Indentation wants to be fixed here. Ack with those changes (but aiui the patch isn''t really tied to be applied in order - if that''s right, i.e. I don''t overlook some subtlety, I could as well commit it right away; I would even consider this a backporting candidate). Jan> + 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-24 14:14 UTC
[PATCH v3] arch/x86: check remote MMIO remap permissions
Patch was 19/23 in the XSM IS_PRIV series, but as Jan pointed out, it can be applied separately from the other patches. ---->8--------------------------------------------------------------- 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 a domain with a more restrictive iomem_access policy to have the pages mapped into its page tables. To catch this, also check the owner of the page tables. The current domain does not need to be checked because the ability to manipulate a domain''s page tables implies full access to the target domain, so checking that domain''s permission is sufficient. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Acked-by: Jan Beulich <jbeulich@suse.com> Cc: Keir Fraser <keir@xen.org> Cc: Tim Deegan <tim@xen.org> --- xen/arch/x86/mm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index a962369..ff64413 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -754,6 +754,19 @@ get_page_from_l1e( return -EINVAL; } + if ( pg_owner != l1e_owner && + !iomem_access_permitted(l1e_owner, mfn, mfn) ) + { + if ( mfn != (PADDR_MASK >> PAGE_SHIFT) ) /* INVALID_MFN? */ + { + MEM_LOG("Dom%u attempted to map I/O space %08lx in dom%u to dom%u", + curr->domain->domain_id, mfn, pg_owner->domain_id, + l1e_owner->domain_id); + return -EPERM; + } + return -EINVAL; + } + if ( !(l1f & _PAGE_RW) || !rangeset_contains_singleton(mmio_ro_ranges, mfn) ) return 0; -- 1.7.11.4
Tim Deegan
2012-Sep-27 13:09 UTC
Re: [PATCH 18/23] arch/x86: Add missing mem_sharing XSM hooks
Cc''ing Joe, the author of the original check I''m talking about below. At 11:23 -0400 on 17 Sep (1347881020), Daniel De Graaf wrote:> diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c > index 24e2d93..7062f02 100644 > --- a/xen/arch/x86/domctl.c > +++ b/xen/arch/x86/domctl.c > @@ -1447,10 +1447,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); > } > @@ -1506,7 +1504,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/include/xsm/dummy.h b/xen/include/xsm/dummy.h > index 626a332..5fb0afe 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; > }I think this ought to be at least IS_PRIV_FOR. I can see the original code allowed all callers to use it, but surely it ought to be only for the tools. Since only the tools can actually set the mem-access rights (and so this is pretty much a noop) I don''t think this causes any substantial problem but we might as well adjust it anyway. Tim.> +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 96e4b13..c08a664 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 43e8617..3926b2b 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 a242d65..65db2b7 100644 > --- a/xen/xsm/flask/hooks.c > +++ b/xen/xsm/flask/hooks.c > @@ -1277,7 +1277,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); > } > @@ -1287,6 +1297,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; > @@ -1736,8 +1754,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 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Daniel De Graaf
2012-Sep-27 16:11 UTC
Re: [PATCH 18/23] arch/x86: Add missing mem_sharing XSM hooks
On 09/27/2012 09:09 AM, Tim Deegan wrote:> Cc''ing Joe, the author of the original check I''m talking about below. > > At 11:23 -0400 on 17 Sep (1347881020), Daniel De Graaf wrote: >> diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c >> index 24e2d93..7062f02 100644 >> --- a/xen/arch/x86/domctl.c >> +++ b/xen/arch/x86/domctl.c >> @@ -1447,10 +1447,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); >> } >> @@ -1506,7 +1504,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/include/xsm/dummy.h b/xen/include/xsm/dummy.h >> index 626a332..5fb0afe 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; >> } > > I think this ought to be at least IS_PRIV_FOR. I can see the original > code allowed all callers to use it, but surely it ought to be only for > the tools. Since only the tools can actually set the mem-access rights > (and so this is pretty much a noop) I don''t think this causes any > substantial problem but we might as well adjust it anyway. > > Tim.Because this is a domctl, it already requires IS_PRIV as checked by xsm_domctl (and was already checked before this series). -- Daniel De Graaf National Security Agency
Tim Deegan
2012-Sep-27 16:27 UTC
Re: [PATCH 18/23] arch/x86: Add missing mem_sharing XSM hooks
At 12:11 -0400 on 27 Sep (1348747909), Daniel De Graaf wrote:> > I think this ought to be at least IS_PRIV_FOR. I can see the original > > code allowed all callers to use it, but surely it ought to be only for > > the tools. Since only the tools can actually set the mem-access rights > > (and so this is pretty much a noop) I don''t think this causes any > > substantial problem but we might as well adjust it anyway. > > > > Tim. > > Because this is a domctl, it already requires IS_PRIV as checked by > xsm_domctl (and was already checked before this series).OK; in that case you have my ack on this. Tim.