Overall, this series should not change the behavior of Xen when XSM is not enabled; however, in some cases, the exact errors that are returned will be different because security checks have been moved below validity checks. Also, once applied, newly introduced domctls and sysctls will not automatically be guarded by IS_PRIV checks - they will need to add their own permission checking code. Background: The Xen hypervisor has two basic access control function calls: IS_PRIV and the xsm_* functions. Most privileged operations currently require that both checks succeed, and many times the checks are at different locations in the code. When performing dom0 disaggregation, many of the functions normally protected with IS_PRIV are handled by domains other than dom0. This requires either making all such disaggregated domains privileged, or allowing certain operations to be performed without an IS_PRIV check. Because the privileged bit also short-circuits the IS_PRIV_FOR check, and some IS_PRIV calls do not currently have an accompanying XSM call, this series implements the second option. Once applied, most IS_PRIV checks are isolated in the newly introduced xen/include/xsm/dummy.h header. The remaining checks cover a few areas that that have some reason to remain because they involve hardware access or workarounds: 1. Overriding the IRQ and IO memory access checks (arch/x86/domctl.c). These overrides should not be needed, as dom0 should have access without needing the override. 2. Allow MAP_PIRQ_TYPE_GSI to ignore domain_pirq_to_irq negative return 3. The hack for device model framebuffers in get_page_from_l1e 4. Installing maps of non-owned pages in shadow_get_page_from_l1e 5. PCI configuration space (arch/x86/traps.c). Allowing a PV Linux domU to access the PCI configuration space is a good way to crash the system as it reconfigures PCI devices during boot, so this needs to remain to get a working system when FLASK is in permissive mode. 6. Various MSR accesses (arch/x86/traps.c) The ARM architecture is not touched at all in these patches. The only obvious breakage that I can see is due to rcu_lock_target_domain_by_id being removed, but XSM hooks will be needed for domctls and sysctls. The rcu_lock_target_domain_by_id and rcu_lock_remote_target_domain_by_id functions are removed by this series because they act as wrappers around IS_PRIV_FOR; their callers have been changed to use XSM checks instead. Miscellaneous updates to FLASK: [PATCH 01/20] xsm/flask: remove inherited class attributes [PATCH 02/20] xsm/flask: remove unneeded create_sid field [PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV [PATCH 04/20] xsm/flask: add domain relabel support [PATCH 05/20] libxl: introduce XSM relabel on build [PATCH 06/20] flask/policy: Add domain relabel example Preparatory new hooks: [PATCH 07/20] arch/x86: add distinct XSM hooks for map/unmap [PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands [PATCH 09/20] xsm/flask: Add checks on the domain performing the Refactoring: [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM Remaining IS_PRIV calls: [PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks [PATCH 14/20] tmem: Add access control check [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks [PATCH 18/20] xen: Add XSM hook for XENMEM_exchange Cleanup, FLASK updates to support IS_PRIV emulation: [PATCH 15/20] xsm: remove unneeded xsm_call macro [PATCH 16/20] xsm/flask: add distinct SIDs for self/target access [PATCH 19/20] xen: remove rcu_lock_{remote_,}target_domain_by_id [PATCH 20/20] flask: add missing operations
Daniel De Graaf
2012-Sep-10 19:48 UTC
[PATCH 01/20] 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 | 27 ------- 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/services.c | 54 +------------ 8 files changed, 4 insertions(+), 195 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..1bfeef2 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 @@ -191,16 +174,6 @@ 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; 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/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-10 19:48 UTC
[PATCH 02/20] 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-10 19:48 UTC
[PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV checks
These functions will be used to avoid duplication of IS_PRIV calls that will be introduced in XSM hooks. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/common/domain.c | 21 +++++++++++++++++++++ xen/include/xen/sched.h | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/xen/common/domain.c b/xen/common/domain.c index a1aa05e..52489b3 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -420,6 +420,13 @@ struct domain *rcu_lock_domain_by_id(domid_t dom) return d; } +struct domain *rcu_lock_domain_by_any_id(domid_t dom) +{ + if ( dom == DOMID_SELF ) + return rcu_lock_current_domain(); + return rcu_lock_domain_by_id(dom); +} + int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d) { if ( dom == DOMID_SELF ) @@ -454,6 +461,20 @@ int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d) return 0; } +int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d) +{ + if ( (*d = rcu_lock_domain_by_id(dom)) == NULL ) + return -ESRCH; + + if ( *d == current->domain ) + { + rcu_unlock_domain(*d); + return -EPERM; + } + + return 0; +} + int domain_kill(struct domain *d) { int rc = 0; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 53804c8..b0def4a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -447,6 +447,11 @@ struct domain *domain_create( struct domain *rcu_lock_domain_by_id(domid_t dom); /* + * As above function, but resolves DOMID_SELF to current domain + */ +struct domain *rcu_lock_domain_by_any_id(domid_t dom); + +/* * As above function, but accounts for current domain context: * - Translates target DOMID_SELF into caller''s domain id; and * - Checks that caller has permission to act on the target domain. @@ -460,6 +465,12 @@ int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d); */ int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d); +/* + * As rcu_lock_domain_by_id(), but will fail EPERM or ESRCH rather than resolve + * to local domain. + */ +int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d); + /* Finish a RCU critical region started by rcu_lock_domain_by_id(). */ static inline void rcu_unlock_domain(struct domain *d) { -- 1.7.11.4
This adds the ability to change a domain''s XSM label after creation. The new label will be used for all future access checks; however, existing event channels and memory mappings will remain valid even if their creation would be denied by the new label. With appropriate security policy and hooks in the domain builder, this can be used to create domains that the domain builder does not have access to after building. It can also be used to allow a domain to drop privileges - for example, prior to launching a user-supplied kernel loaded by a pv-grub stubdom. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/access_vectors | 7 ++++ tools/flask/policy/policy/flask/security_classes | 1 + tools/flask/policy/policy/modules/xen/xen.te | 2 +- xen/include/public/xsm/flask_op.h | 8 ++++ xen/xsm/flask/flask_op.c | 49 ++++++++++++++++++++++++ xen/xsm/flask/include/av_perm_to_string.h | 3 ++ xen/xsm/flask/include/av_permissions.h | 4 ++ xen/xsm/flask/include/class_to_string.h | 1 + xen/xsm/flask/include/flask.h | 15 ++++---- 9 files changed, 82 insertions(+), 8 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index a884312..c7e29ab 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -73,6 +73,13 @@ class domain set_virq_handler } +class domain2 +{ + relabelfrom + relabelto + relabelself +} + class hvm { sethvmc diff --git a/tools/flask/policy/policy/flask/security_classes b/tools/flask/policy/policy/flask/security_classes index 2ca35d2..ef134a7 100644 --- a/tools/flask/policy/policy/flask/security_classes +++ b/tools/flask/policy/policy/flask/security_classes @@ -9,6 +9,7 @@ class xen class domain +class domain2 class hvm class mmu class resource diff --git a/tools/flask/policy/policy/modules/xen/xen.te b/tools/flask/policy/policy/modules/xen/xen.te index 9cc5240..9550397 100644 --- a/tools/flask/policy/policy/modules/xen/xen.te +++ b/tools/flask/policy/policy/modules/xen/xen.te @@ -169,7 +169,7 @@ delegate_devices(dom0_t, domU_t) ################################################################################ # Domains must be declared using domain_type -neverallow * ~domain_type:domain create; +neverallow * ~domain_type:domain { create transition }; # Resources must be declared using resource_type neverallow * ~resource_type:resource use; diff --git a/xen/include/public/xsm/flask_op.h b/xen/include/public/xsm/flask_op.h index 1a251c9..233de81 100644 --- a/xen/include/public/xsm/flask_op.h +++ b/xen/include/public/xsm/flask_op.h @@ -142,6 +142,12 @@ struct xen_flask_peersid { uint32_t sid; }; +struct xen_flask_relabel { + /* IN */ + uint32_t domid; + uint32_t sid; +}; + struct xen_flask_op { uint32_t cmd; #define FLASK_LOAD 1 @@ -167,6 +173,7 @@ struct xen_flask_op { #define FLASK_ADD_OCONTEXT 21 #define FLASK_DEL_OCONTEXT 22 #define FLASK_GET_PEER_SID 23 +#define FLASK_RELABEL_DOMAIN 24 uint32_t interface_version; /* XEN_FLASK_INTERFACE_VERSION */ union { struct xen_flask_load load; @@ -185,6 +192,7 @@ struct xen_flask_op { /* FLASK_ADD_OCONTEXT, FLASK_DEL_OCONTEXT */ struct xen_flask_ocontext ocontext; struct xen_flask_peersid peersid; + struct xen_flask_relabel relabel; } u; }; typedef struct xen_flask_op xen_flask_op_t; diff --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c index bd4db37..9c8dfe7 100644 --- a/xen/xsm/flask/flask_op.c +++ b/xen/xsm/flask/flask_op.c @@ -573,6 +573,51 @@ static int flask_get_peer_sid(struct xen_flask_peersid *arg) return rv; } +static int flask_relabel_domain(struct xen_flask_relabel *arg) +{ + int rc; + struct domain *d; + struct domain_security_struct *csec = current->domain->ssid; + struct domain_security_struct *dsec; + struct avc_audit_data ad; + AVC_AUDIT_DATA_INIT(&ad, NONE); + + d = rcu_lock_domain_by_any_id(arg->domid); + if ( d == NULL ) + return -ESRCH; + + ad.sdom = current->domain; + ad.tdom = d; + dsec = d->ssid; + + if ( arg->domid == DOMID_SELF ) + { + rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, &ad); + if ( rc ) + goto out; + } + else + { + rc = avc_has_perm(csec->sid, dsec->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, &ad); + if ( rc ) + goto out; + + rc = avc_has_perm(csec->sid, arg->sid, SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, &ad); + if ( rc ) + goto out; + } + + rc = avc_has_perm(dsec->sid, arg->sid, SECCLASS_DOMAIN, DOMAIN__TRANSITION, &ad); + if ( rc ) + goto out; + + dsec->sid = arg->sid; + + out: + rcu_unlock_domain(d); + return rc; +} + long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op) { xen_flask_op_t op; @@ -680,6 +725,10 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op) rv = flask_get_peer_sid(&op.u.peersid); break; + case FLASK_RELABEL_DOMAIN: + rv = flask_relabel_domain(&op.u.relabel); + break; + default: rv = -ENOSYS; } diff --git a/xen/xsm/flask/include/av_perm_to_string.h b/xen/xsm/flask/include/av_perm_to_string.h index 17a1c36..e7e2058 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -61,6 +61,9 @@ S_(SECCLASS_DOMAIN, DOMAIN__SETPODTARGET, "setpodtarget") S_(SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO, "set_misc_info") S_(SECCLASS_DOMAIN, DOMAIN__SET_VIRQ_HANDLER, "set_virq_handler") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELFROM, "relabelfrom") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELTO, "relabelto") + S_(SECCLASS_DOMAIN2, DOMAIN2__RELABELSELF, "relabelself") S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc") S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc") S_(SECCLASS_HVM, HVM__SETPARAM, "setparam") diff --git a/xen/xsm/flask/include/av_permissions.h b/xen/xsm/flask/include/av_permissions.h index 42eaf81..cb1c5dc 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -63,6 +63,10 @@ #define DOMAIN__SET_MISC_INFO 0x40000000UL #define DOMAIN__SET_VIRQ_HANDLER 0x80000000UL +#define DOMAIN2__RELABELFROM 0x00000001UL +#define DOMAIN2__RELABELTO 0x00000002UL +#define DOMAIN2__RELABELSELF 0x00000004UL + #define HVM__SETHVMC 0x00000001UL #define HVM__GETHVMC 0x00000002UL #define HVM__SETPARAM 0x00000004UL diff --git a/xen/xsm/flask/include/class_to_string.h b/xen/xsm/flask/include/class_to_string.h index ab55700..7716645 100644 --- a/xen/xsm/flask/include/class_to_string.h +++ b/xen/xsm/flask/include/class_to_string.h @@ -5,6 +5,7 @@ S_("null") S_("xen") S_("domain") + S_("domain2") S_("hvm") S_("mmu") S_("resource") diff --git a/xen/xsm/flask/include/flask.h b/xen/xsm/flask/include/flask.h index 6d29c5a..3bff998 100644 --- a/xen/xsm/flask/include/flask.h +++ b/xen/xsm/flask/include/flask.h @@ -7,13 +7,14 @@ */ #define SECCLASS_XEN 1 #define SECCLASS_DOMAIN 2 -#define SECCLASS_HVM 3 -#define SECCLASS_MMU 4 -#define SECCLASS_RESOURCE 5 -#define SECCLASS_SHADOW 6 -#define SECCLASS_EVENT 7 -#define SECCLASS_GRANT 8 -#define SECCLASS_SECURITY 9 +#define SECCLASS_DOMAIN2 3 +#define SECCLASS_HVM 4 +#define SECCLASS_MMU 5 +#define SECCLASS_RESOURCE 6 +#define SECCLASS_SHADOW 7 +#define SECCLASS_EVENT 8 +#define SECCLASS_GRANT 9 +#define SECCLASS_SECURITY 10 /* * Security identifier indices for initial entities -- 1.7.11.4
Allow a domain to be built under one security label and run using a different label. This can be used to prevent the domain builder or control domain from having the ability to access a guest domain''s memory via map_foreign_range except during the build process where this is required. Note: this does not provide complete protection from a malicious dom0; mappings created during the build process may persist after the relabel, and could be used to indirectly access the guest''s memory. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> --- tools/libxc/xc_flask.c | 10 ++++++++++ tools/libxc/xenctrl.h | 1 + tools/libxl/libxl_create.c | 4 ++++ tools/libxl/libxl_types.idl | 1 + tools/libxl/xl_cmdimpl.c | 20 +++++++++++++++++++- 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tools/libxc/xc_flask.c b/tools/libxc/xc_flask.c index 80c5a2d..face1e0 100644 --- a/tools/libxc/xc_flask.c +++ b/tools/libxc/xc_flask.c @@ -422,6 +422,16 @@ int xc_flask_setavc_threshold(xc_interface *xch, int threshold) return xc_flask_op(xch, &op); } +int xc_flask_relabel_domain(xc_interface *xch, int domid, uint32_t sid) +{ + DECLARE_FLASK_OP; + op.cmd = FLASK_RELABEL_DOMAIN; + op.u.relabel.domid = domid; + op.u.relabel.sid = sid; + + return xc_flask_op(xch, &op); +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index b7741ca..0d595a0 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -2173,6 +2173,7 @@ int xc_flask_policyvers(xc_interface *xc_handle); int xc_flask_avc_hashstats(xc_interface *xc_handle, char *buf, int size); int xc_flask_getavc_threshold(xc_interface *xc_handle); int xc_flask_setavc_threshold(xc_interface *xc_handle, int threshold); +int xc_flask_relabel_domain(xc_interface *xch, int domid, uint32_t sid); struct elf_binary; void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf, diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index ef17f05..6d7bf4e 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -1126,6 +1126,10 @@ static void domcreate_complete(libxl__egc *egc, int rc) { STATE_AO_GC(dcs->ao); + libxl_domain_config *const d_config = dcs->guest_config; + + if (!rc && d_config->b_info.exec_ssidref) + rc = xc_flask_relabel_domain(CTX->xch, dcs->guest_domid, d_config->b_info.exec_ssidref); if (rc) { if (dcs->guest_domid) { diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 6d5c578..bc11591 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -262,6 +262,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("video_memkb", MemKB), ("shadow_memkb", MemKB), ("rtc_timeoffset", uint32), + ("exec_ssidref", uint32), ("localtime", libxl_defbool), ("disable_migrate", libxl_defbool), ("cpuid", libxl_cpuid_policy_list), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 2d6ab97..9b5f291 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -595,16 +595,34 @@ static void parse_config_data(const char *config_source, exit(1); } - if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) { + if (!xlu_cfg_get_string (config, "init_seclabel", &buf, 0)) { e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), &c_info->ssidref); if (e) { if (errno == ENOSYS) { + fprintf(stderr, "XSM Disabled: init_seclabel not supported\n"); + } else { + fprintf(stderr, "Invalid init_seclabel: %s\n", buf); + exit(1); + } + } + } + + if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) { + uint32_t ssidref; + e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf), + &ssidref); + if (e) { + if (errno == ENOSYS) { fprintf(stderr, "XSM Disabled: seclabel not supported\n"); } else { fprintf(stderr, "Invalid seclabel: %s\n", buf); exit(1); } + } else if (c_info->ssidref) { + b_info->exec_ssidref = ssidref; + } else { + c_info->ssidref = ssidref; } } -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:48 UTC
[PATCH 06/20] 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-10 19:49 UTC
[PATCH 07/20] 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 97a13fb..3ccf712 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -807,6 +807,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); @@ -844,7 +848,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; @@ -906,7 +910,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 ce55ee1..bf133fa 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -243,7 +243,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-10 19:49 UTC
[PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands
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 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 88880b0..c049db7 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -501,6 +501,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; @@ -618,6 +622,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) { uint32_t idle_nums; + ret = xsm_pm_op(); + if ( ret ) + break; + switch(op->u.core_parking.type) { case XEN_CORE_PARKING_SET: -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 09/20] 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-10 19:49 UTC
[PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module
This patch copies IS_PRIV checks into the dummy XSM hooks and makes the dummy hooks the default implementation instead of always returning zero. This patch should not change any functionality regardless of the state of XSM_ENABLE; these newly introduced duplicate checks will be resolved in the next patch. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Keir Fraser <keir@xen.org> Cc: Jan Beulich <jbeulich@suse.com> --- xen/include/xsm/dummy.h | 828 ++++++++++++++++++++++++++++++++++++++++++++++++ xen/include/xsm/xsm.h | 52 ++- xen/xsm/dummy.c | 617 +----------------------------------- xen/xsm/xsm_core.c | 2 +- 4 files changed, 854 insertions(+), 645 deletions(-) create mode 100644 xen/include/xsm/dummy.h diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h new file mode 100644 index 0000000..3f5d9b0 --- /dev/null +++ b/xen/include/xsm/dummy.h @@ -0,0 +1,828 @@ +/* + * 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) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, pausedomain) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, unpausedomain) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, resumedomain) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, domain_create)(struct domain *d, u32 ssidref) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, max_vcpus)(struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, destroydomain) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, vcpuaffinity) (int cmd, struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, scheduler) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + 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) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getvcpuinfo) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, domain_settime) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, set_target) (struct domain *d, struct domain *e) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, domctl)(struct domain *d, int cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, set_virq_handler)(struct domain *d, uint32_t virq) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, tbufcontrol) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, readconsole) (uint32_t clear) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, sched_id) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, setdomainmaxmem) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, setdomainhandle) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, setdebugging) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, perfcontrol) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, debug_keys) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getcpuinfo) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, get_pmstat) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, setpminfo) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, pm_op) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, do_mca) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, availheap) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + 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) +{ + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; + 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) +{ + 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 ( !IS_PRIV_FOR(d1, d2) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, console_io) (struct domain *d, int cmd) +{ +#ifndef VERBOSE + if ( !IS_PRIV(current->domain) ) + return -EPERM; +#endif + return 0; +} + +static XSM_DEFAULT(int, profile) (struct domain *d, int op) +{ + return 0; +} + +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; +} + +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) +{ + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + 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) +{ + 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; +} + +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) +{ + 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; +} + +static XSM_DEFAULT(int, get_device_group) (uint32_t machine_bdf) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, test_assign_device) (uint32_t machine_bdf) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, assign_device) (struct domain *d, uint32_t machine_bdf) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, deassign_device) (struct domain *d, uint32_t machine_bdf) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, resource_plug_core) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, resource_unplug_core) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +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; +} + +static XSM_DEFAULT(int, page_offline) (uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, lockprof) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, cpupool_op) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, sched_op) (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; +} + +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) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, unmap_domain_pirq) (struct domain *d, int irq) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, irq_permission) (struct domain *d, int pirq, uint8_t allow) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, iomem_permission) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, iomem_mapping) (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + 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) +{ + if ( !IS_PRIV(d) ) + return -EPERM; + return 0; +} + +#ifdef CONFIG_X86 +static XSM_DEFAULT(int, shadow_control) (struct domain *d, uint32_t op) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getpageframeinfo) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getmemlist) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, hypercall_init) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, hvmcontext) (struct domain *d, uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, address_size) (struct domain *d, uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, machine_address_size) (struct domain *d, uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +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; +} + +static XSM_DEFAULT(int, mem_event) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, mem_sharing) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, apic) (struct domain *d, int cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, xen_settime) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, memtype) (uint32_t access) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, microcode) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, physinfo) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, platform_quirk) (uint32_t quirk) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, firmware_info) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, efi_call) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, acpi_sleep) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, change_freq) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, getidletime) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, machine_memory_map) (void) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, domain_memory_map) (struct domain *d) +{ + if ( current->domain != d && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + 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) +{ + 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; +} + +static XSM_DEFAULT(int, sendtrigger) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, pin_mem_cacheattr) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, ext_vcpucontext) (struct domain *d, uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, vcpuextstate) (struct domain *d, uint32_t cmd) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, ioport_permission) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) +{ + if ( !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; + return 0; +} + +#endif diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index cbbe673..6095a86 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -21,11 +21,7 @@ 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 +#define xsm_call(fn) xsm_ops->fn /* policy magic number (defined by XSM_MAGIC) */ typedef u32 xsm_magic_t; @@ -187,8 +183,6 @@ struct xsm_operations { #endif }; -#endif - extern struct xsm_operations *xsm_ops; static inline void xsm_security_domaininfo (struct domain *d, @@ -598,32 +592,11 @@ 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) +static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { -#ifdef XSM_ENABLE return xsm_ops->__do_xsm_op(op); -#else - return -ENOSYS; -#endif } -#ifdef XSM_ENABLE -extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)); -extern int xsm_policy_init(unsigned long *module_map, - const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)); -extern int register_xsm(struct xsm_operations *ops); -extern int unregister_xsm(struct xsm_operations *ops); -#else -static inline int xsm_init (unsigned long *module_map, - const multiboot_info_t *mbi, - void *(*bootstrap_map)(const module_t *)) -{ - return 0; -} -#endif - #ifdef CONFIG_X86 static inline int xsm_shadow_control (struct domain *d, uint32_t op) { @@ -825,7 +798,28 @@ static inline int xsm_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, } #endif /* CONFIG_X86 */ +extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)); +extern int xsm_policy_init(unsigned long *module_map, + const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)); +extern int register_xsm(struct xsm_operations *ops); +extern int unregister_xsm(struct xsm_operations *ops); + extern struct xsm_operations dummy_xsm_ops; extern void xsm_fixup_ops(struct xsm_operations *ops); +#else /* XSM_ENABLE */ + +#define XSM_DEFAULT(type, name) inline type xsm_ ## name +#include <xsm/dummy.h> + +static inline int xsm_init (unsigned long *module_map, + const multiboot_info_t *mbi, + void *(*bootstrap_map)(const module_t *)) +{ + return 0; +} +#endif /* XSM_ENABLE */ + #endif /* __XSM_H */ diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index a5dbfe7..af532b8 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -10,621 +10,8 @@ * as published by the Free Software Foundation. */ -#include <xen/sched.h> -#include <xsm/xsm.h> - -static void dummy_security_domaininfo(struct domain *d, - struct xen_domctl_getdomaininfo *info) -{ - return; -} - -static int dummy_setvcpucontext(struct domain *d) -{ - return 0; -} - -static int dummy_pausedomain (struct domain *d) -{ - return 0; -} - -static int dummy_unpausedomain (struct domain *d) -{ - return 0; -} - -static int dummy_resumedomain (struct domain *d) -{ - return 0; -} - -static int dummy_domain_create(struct domain *d, u32 ssidref) -{ - return 0; -} - -static int dummy_max_vcpus(struct domain *d) -{ - return 0; -} - -static int dummy_destroydomain (struct domain *d) -{ - return 0; -} - -static int dummy_vcpuaffinity (int cmd, struct domain *d) -{ - return 0; -} - -static int dummy_scheduler (struct domain *d) -{ - return 0; -} - -static int dummy_getdomaininfo (struct domain *d) -{ - if ( !IS_PRIV(current->domain) ) - return -EPERM; - return 0; -} - -static int dummy_getvcpucontext (struct domain *d) -{ - return 0; -} - -static int dummy_getvcpuinfo (struct domain *d) -{ - return 0; -} - -static int dummy_domain_settime (struct domain *d) -{ - return 0; -} - -static int dummy_set_target (struct domain *d, struct domain *e) -{ - return 0; -} - -static int dummy_domctl(struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_set_virq_handler(struct domain *d, uint32_t virq) -{ - return 0; -} - -static int dummy_tbufcontrol (void) -{ - return 0; -} - -static int dummy_readconsole (uint32_t clear) -{ - return 0; -} - -static int dummy_sched_id (void) -{ - return 0; -} - -static int dummy_setdomainmaxmem (struct domain *d) -{ - return 0; -} - -static int dummy_setdomainhandle (struct domain *d) -{ - return 0; -} - -static int dummy_setdebugging (struct domain *d) -{ - return 0; -} - -static int dummy_perfcontrol (void) -{ - return 0; -} - -static int dummy_debug_keys (void) -{ - return 0; -} - -static int dummy_getcpuinfo (void) -{ - return 0; -} - -static int dummy_get_pmstat (void) -{ - return 0; -} - -static int dummy_setpminfo (void) -{ - return 0; -} - -static int dummy_pm_op (void) -{ - return 0; -} - -static int dummy_do_mca (void) -{ - return 0; -} - -static int dummy_availheap (void) -{ - return 0; -} - -static int dummy_alloc_security_domain (struct domain *d) -{ - return 0; -} - -static void dummy_free_security_domain (struct domain *d) -{ - return; -} - -static int dummy_grant_mapref (struct domain *d1, struct domain *d2, - uint32_t flags) -{ - return 0; -} - -static int dummy_grant_unmapref (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_setup (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_transfer (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_copy (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_grant_query_size (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_memory_adjust_reservation (struct domain *d1, - struct domain *d2) -{ - return 0; -} - -static int dummy_memory_stat_reservation (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_console_io (struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_profile (struct domain *d, int op) -{ - return 0; -} - -static int dummy_kexec (void) -{ - return 0; -} - -static int dummy_schedop_shutdown (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_memory_pin_page(struct domain *d1, struct domain *d2, struct page_info *page) -{ - return 0; -} - -static int dummy_evtchn_unbound (struct domain *d, struct evtchn *chn, - domid_t id2) -{ - return 0; -} - -static int dummy_evtchn_interdomain (struct domain *d1, struct evtchn - *chan1, struct domain *d2, struct evtchn *chan2) -{ - return 0; -} - -static void dummy_evtchn_close_post (struct evtchn *chn) -{ - return; -} - -static int dummy_evtchn_send (struct domain *d, struct evtchn *chn) -{ - return 0; -} - -static int dummy_evtchn_status (struct domain *d, struct evtchn *chn) -{ - return 0; -} - -static int dummy_evtchn_reset (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_alloc_security_evtchn (struct evtchn *chn) -{ - return 0; -} - -static void dummy_free_security_evtchn (struct evtchn *chn) -{ - return; -} - -static char *dummy_show_security_evtchn (struct domain *d, const struct evtchn *chn) -{ - return NULL; -} - -static int dummy_get_pod_target(struct domain *d) -{ - return 0; -} - -static int dummy_set_pod_target(struct domain *d) -{ - return 0; -} - -static int dummy_get_device_group (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_test_assign_device (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_assign_device (struct domain *d, uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_deassign_device (struct domain *d, uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_plug_core (void) -{ - return 0; -} - -static int dummy_resource_unplug_core (void) -{ - return 0; -} - -static int dummy_resource_plug_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_unplug_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_setup_pci (uint32_t machine_bdf) -{ - return 0; -} - -static int dummy_resource_setup_gsi (int gsi) -{ - return 0; -} - -static int dummy_resource_setup_misc (void) -{ - return 0; -} - -static int dummy_page_offline (uint32_t cmd) -{ - return 0; -} - -static int dummy_lockprof (void) -{ - return 0; -} - -static int dummy_cpupool_op (void) -{ - return 0; -} - -static int dummy_sched_op (void) -{ - return 0; -} - -static long dummy___do_xsm_op(XEN_GUEST_HANDLE(xsm_op_t) op) -{ - return -ENOSYS; -} - -static char *dummy_show_irq_sid (int irq) -{ - return NULL; -} - -static int dummy_map_domain_pirq (struct domain *d, int irq, void *data) -{ - return 0; -} - -static int dummy_unmap_domain_pirq (struct domain *d, int irq) -{ - return 0; -} - -static int dummy_irq_permission (struct domain *d, int pirq, uint8_t allow) -{ - return 0; -} - -static int dummy_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_pci_config_permission (struct domain *d, uint32_t machine_bdf, - uint16_t start, uint16_t end, - uint8_t access) -{ - return 0; -} - -#ifdef CONFIG_X86 -static int dummy_shadow_control (struct domain *d, uint32_t op) -{ - return 0; -} - -static int dummy_getpageframeinfo (struct domain *d) -{ - return 0; -} - -static int dummy_getmemlist (struct domain *d) -{ - return 0; -} - -static int dummy_hypercall_init (struct domain *d) -{ - return 0; -} - -static int dummy_hvmcontext (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_address_size (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_machine_address_size (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_hvm_param (struct domain *d, unsigned long op) -{ - return 0; -} - -static int dummy_hvm_set_pci_intx_level (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_set_isa_irq_level (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_set_pci_link_route (struct domain *d) -{ - return 0; -} - -static int dummy_hvm_inject_msi (struct domain *d) -{ - return 0; -} - -static int dummy_mem_event (struct domain *d) -{ - return 0; -} - -static int dummy_mem_sharing (struct domain *d) -{ - return 0; -} - -static int dummy_apic (struct domain *d, int cmd) -{ - return 0; -} - -static int dummy_xen_settime (void) -{ - return 0; -} - -static int dummy_memtype (uint32_t access) -{ - return 0; -} - -static int dummy_microcode (void) -{ - return 0; -} - -static int dummy_physinfo (void) -{ - return 0; -} - -static int dummy_platform_quirk (uint32_t quirk) -{ - return 0; -} - -static int dummy_firmware_info (void) -{ - return 0; -} - -static int dummy_efi_call(void) -{ - return 0; -} - -static int dummy_acpi_sleep (void) -{ - return 0; -} - -static int dummy_change_freq (void) -{ - return 0; -} - -static int dummy_getidletime (void) -{ - return 0; -} - -static int dummy_machine_memory_map (void) -{ - return 0; -} - -static int dummy_domain_memory_map (struct domain *d) -{ - return 0; -} - -static int dummy_mmu_normal_update (struct domain *d, struct domain *t, - struct domain *f, intpte_t fpte) -{ - return 0; -} - -static int dummy_mmu_machphys_update (struct domain *d, struct domain *f, unsigned long mfn) -{ - return 0; -} - -static int dummy_update_va_mapping (struct domain *d, struct domain *f, - l1_pgentry_t pte) -{ - return 0; -} - -static int dummy_add_to_physmap (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_remove_from_physmap (struct domain *d1, struct domain *d2) -{ - return 0; -} - -static int dummy_sendtrigger (struct domain *d) -{ - return 0; -} - -static int dummy_bind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - return 0; -} - -static int dummy_unbind_pt_irq (struct domain *d, struct xen_domctl_bind_pt_irq *bind) -{ - return 0; -} - -static int dummy_pin_mem_cacheattr (struct domain *d) -{ - return 0; -} - -static int dummy_ext_vcpucontext (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_vcpuextstate (struct domain *d, uint32_t cmd) -{ - return 0; -} - -static int dummy_ioport_permission (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) -{ - return 0; -} - -static int dummy_ioport_mapping (struct domain *d, uint32_t s, uint32_t e, uint8_t allow) -{ - return 0; -} -#endif +#define XSM_DEFAULT(type, name) type dummy_ ## name +#include <xsm/dummy.h> struct xsm_operations dummy_xsm_ops; diff --git a/xen/xsm/xsm_core.c b/xen/xsm/xsm_core.c index 96c8669..c4c85c0 100644 --- a/xen/xsm/xsm_core.c +++ b/xen/xsm/xsm_core.c @@ -113,7 +113,7 @@ int unregister_xsm(struct xsm_operations *ops) long do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) { - return __do_xsm_op(op); + return xsm___do_xsm_op(op); } -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 11/20] 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 by its only caller * map_domain_pirq has IS_PRIV_FOR checked in physdev_map_pirq * PHYSDEVOP_alloc_irq_vector is a noop, does not need IS_PRIV * Many PHYSDEVOP access checks are within the implementation functions * do_platform_op, do_domctl, and do_sysctl all have per-operation XSM hooks * 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/domctl.c | 25 ++++++++++++++---- xen/arch/x86/irq.c | 3 +-- xen/arch/x86/mm.c | 3 --- xen/arch/x86/physdev.c | 54 --------------------------------------- xen/arch/x86/platform_hypercall.c | 3 --- xen/common/domctl.c | 33 +++--------------------- xen/common/kexec.c | 3 --- xen/common/schedule.c | 6 ----- xen/common/sysctl.c | 3 --- xen/drivers/char/console.c | 6 ----- 12 files changed, 25 insertions(+), 119 deletions(-) diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c index 9e1f989..c7b37ef 100644 --- a/xen/arch/x86/acpi/power.c +++ b/xen/arch/x86/acpi/power.c @@ -238,7 +238,7 @@ static long enter_state_helper(void *data) */ int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep) { - if ( !IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt_blk.address ) + if ( !acpi_sinfo.pm1a_cnt_blk.address ) return -EPERM; /* Sanity check */ diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c index a89df6d..f399054 100644 --- a/xen/arch/x86/cpu/mcheck/mce.c +++ b/xen/arch/x86/cpu/mcheck/mce.c @@ -1379,9 +1379,6 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc) struct xen_mc_msrinject *mc_msrinject; struct xen_mc_mceinject *mc_mceinject; - if (!IS_PRIV(v->domain) ) - return x86_mcerr(NULL, -EPERM); - ret = xsm_do_mca(); if ( ret ) return x86_mcerr(NULL, ret); diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 3ccf712..9bc2452 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -54,6 +54,26 @@ long arch_do_domctl( switch ( domctl->cmd ) { + /* TODO: the following do not have XSM hooks yet */ + 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: + /* getpageframeinfo[23] needs an extra check to avoid allowing queries of some remote GFNs */ + case XEN_DOMCTL_getpageframeinfo2: + case XEN_DOMCTL_getpageframeinfo3: + if ( !IS_PRIV(current->domain) ) + return -EPERM; + } + + switch ( domctl->cmd ) + { case XEN_DOMCTL_shadow_op: { @@ -802,11 +822,6 @@ long arch_do_domctl( 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; - ret = xsm_unbind_pt_irq(d, bind); if ( ret ) goto unbind_out; 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 4af4130..4732c81 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -4790,9 +4790,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 bf133fa..d6ea4f0 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -110,12 +110,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 ) { @@ -239,10 +233,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; @@ -434,9 +424,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; @@ -451,9 +438,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; @@ -468,10 +452,6 @@ 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) ) - break; - /* Vector is only used by hypervisor, and dom0 shouldn''t touch it in its world, return irq_op.irq as the vecotr, and make this hypercall dummy, and also defer the vector @@ -518,9 +498,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; @@ -531,9 +508,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; @@ -546,10 +520,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; @@ -572,10 +542,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; @@ -596,10 +562,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; @@ -612,10 +574,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; @@ -634,10 +592,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; @@ -653,10 +607,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; @@ -671,10 +621,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/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index c049db7..f3304a2 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -65,9 +65,6 @@ 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; diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 2b1f182..ec8fa58 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -250,33 +250,6 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION ) return -EACCES; - 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) ) - { - is_priv = IS_PRIV_FOR(current->domain, d); - rcu_unlock_domain(d); - } - if ( !is_priv ) - return -EPERM; - break; - } -#ifdef XSM_ENABLE - case XEN_DOMCTL_getdomaininfo: - break; -#endif - default: - if ( !IS_PRIV(current->domain) ) - return -EPERM; - break; - } - if ( !domctl_lock_acquire() ) return hypercall_create_continuation( __HYPERVISOR_domctl, "h", u_domctl); @@ -892,10 +865,10 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) if ( d == NULL ) break; - if ( pirq >= d->nr_pirqs ) - ret = -EINVAL; - else if ( xsm_irq_permission(d, pirq, allow) ) + if ( xsm_irq_permission(d, pirq, allow) ) ret = -EPERM; + else if ( pirq >= d->nr_pirqs ) + ret = -EINVAL; else if ( allow ) ret = irq_permit_access(d, pirq); else 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/common/sysctl.c b/xen/common/sysctl.c index ea68278..2cea0c3 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -33,9 +33,6 @@ 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; diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index e10bed5..3ff36b9 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; -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 12/20] 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 ++++++------ 5 files changed, 63 insertions(+), 87 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 0576a24..e737671 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -3375,7 +3375,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; @@ -3540,7 +3540,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; @@ -3584,7 +3584,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; @@ -3614,7 +3614,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; @@ -3711,9 +3711,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) ) @@ -3957,7 +3957,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; @@ -3996,7 +3996,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; @@ -4046,9 +4046,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 ) @@ -4093,7 +4093,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; @@ -4172,7 +4172,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; @@ -4207,7 +4207,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; @@ -4243,9 +4243,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) ) @@ -4297,7 +4297,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 4732c81..f16b112 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -4673,9 +4673,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) ) { @@ -4712,9 +4712,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 ) @@ -4865,16 +4865,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 b81dcff..c29087a 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -195,30 +195,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) @@ -1304,11 +1280,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) ) @@ -1372,10 +1349,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; } @@ -2245,10 +2223,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); @@ -2298,14 +2276,15 @@ gnttab_get_version(XEN_GUEST_HANDLE(gnttab_get_version_t uop)) if ( copy_from_guest(&op, uop, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(op.dom, &d); - if ( rc < 0 ) - return rc; + d = rcu_lock_domain_by_any_id(op.dom); + if ( d == NULL ) + return -ESRCH; - if ( xsm_grant_query_size(current->domain, d) ) + rc = xsm_grant_query_size(current->domain, d); + if ( rc ) { rcu_unlock_domain(d); - return -EPERM; + return rc; } op.version = d->grant_table->gt_version; diff --git a/xen/common/memory.c b/xen/common/memory.c index 8779d6b..cfdd63f 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -570,7 +570,8 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) && (reservation.mem_flags & XENMEMF_populate_on_demand) ) args.memflags |= MEMF_populate_on_demand; - if ( unlikely(rcu_lock_target_domain_by_id(reservation.domid, &d)) ) + d = rcu_lock_domain_by_any_id(reservation.domid); + if ( d == NULL ) return start_extent; args.domain = d; @@ -619,9 +620,9 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&domid, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(domid, &d); - if ( rc ) - return rc; + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; rc = xsm_memory_stat_reservation(current->domain, d); if ( rc ) @@ -657,9 +658,9 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) if ( copy_from_guest(&xrfp, arg, 1) ) return -EFAULT; - rc = rcu_lock_target_domain_by_id(xrfp.domid, &d); - if ( rc != 0 ) - return rc; + d = rcu_lock_domain_by_any_id(xrfp.domid); + if ( d == NULL ) + return -ESRCH; if ( xsm_remove_from_physmap(current->domain, d) ) { -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks
This patch adds new XSM hooks to cover the 12 domctls that were not previously covered by an XSM hook, and splits up the mem_sharing and mem_event XSM hooks to better cover what the code is doing. 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 | 5 ++ tools/flask/policy/policy/modules/xen/xen.if | 2 + xen/arch/x86/domctl.c | 111 +++++++++++++------------ xen/arch/x86/mm/mem_event.c | 45 ++++------ xen/arch/x86/mm/mem_sharing.c | 23 ++++- xen/include/asm-x86/mem_event.h | 1 - xen/include/xsm/dummy.h | 58 ++++++++++++- xen/include/xsm/xsm.h | 56 ++++++++++++- xen/xsm/dummy.c | 10 ++- xen/xsm/flask/hooks.c | 56 ++++++++++++- xen/xsm/flask/include/av_perm_to_string.h | 5 ++ xen/xsm/flask/include/av_permissions.h | 5 ++ 12 files changed, 284 insertions(+), 93 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 11d02da..28b8ada 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 + share_mem + audit_p2m } class event diff --git a/tools/flask/policy/policy/modules/xen/xen.if b/tools/flask/policy/policy/modules/xen/xen.if index 2ad11b2..3527054 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; '') ################################################################################ diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 9bc2452..e92c323 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -54,26 +54,6 @@ long arch_do_domctl( switch ( domctl->cmd ) { - /* TODO: the following do not have XSM hooks yet */ - 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: - /* getpageframeinfo[23] needs an extra check to avoid allowing queries of some remote GFNs */ - case XEN_DOMCTL_getpageframeinfo2: - case XEN_DOMCTL_getpageframeinfo3: - if ( !IS_PRIV(current->domain) ) - return -EPERM; - } - - switch ( domctl->cmd ) - { case XEN_DOMCTL_shadow_op: { @@ -1113,6 +1093,10 @@ long arch_do_domctl( if ( d == NULL ) break; + ret = xsm_set_cpuid(d); + if ( ret ) + goto set_cpuid_out; + for ( i = 0; i < MAX_CPUID_INPUT; i++ ) { cpuid = &d->arch.cpuids[i]; @@ -1136,6 +1120,7 @@ long arch_do_domctl( ret = 0; } + set_cpuid_out: rcu_unlock_domain(d); } break; @@ -1150,6 +1135,10 @@ long arch_do_domctl( if ( d == NULL ) break; + ret = xsm_gettscinfo(d); + if ( ret ) + goto gettscinfo_out; + domain_pause(d); tsc_get_info(d, &info.tsc_mode, &info.elapsed_nsec, @@ -1161,6 +1150,7 @@ long arch_do_domctl( ret = 0; domain_unpause(d); + gettscinfo_out: rcu_unlock_domain(d); } break; @@ -1174,15 +1164,20 @@ long arch_do_domctl( if ( d == NULL ) break; + ret = xsm_settscinfo(d); + if ( ret ) + goto settscinfo_out; + domain_pause(d); tsc_set_info(d, domctl->u.tsc_info.info.tsc_mode, domctl->u.tsc_info.info.elapsed_nsec, domctl->u.tsc_info.info.gtsc_khz, domctl->u.tsc_info.info.incarnation); domain_unpause(d); + ret = 0; + settscinfo_out: rcu_unlock_domain(d); - ret = 0; } break; @@ -1194,9 +1189,10 @@ long arch_do_domctl( d = rcu_lock_domain_by_id(domctl->domain); if ( d != NULL ) { - d->arch.suppress_spurious_page_faults = 1; + ret = xsm_domctl(d, domctl->cmd); + if ( !ret ) + d->arch.suppress_spurious_page_faults = 1; rcu_unlock_domain(d); - ret = 0; } } break; @@ -1211,6 +1207,10 @@ long arch_do_domctl( if ( d == NULL ) break; + ret = xsm_debug_op(d); + if ( ret ) + goto debug_op_out; + ret = -EINVAL; if ( (domctl->u.debug_op.vcpu >= d->max_vcpus) || ((v = d->vcpu[domctl->u.debug_op.vcpu]) == NULL) ) @@ -1235,6 +1235,10 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; + ret = xsm_debug_op(d); + if ( ret ) + goto gdbsx_guestmemio_out; + domctl->u.gdbsx_guest_memio.remain domctl->u.gdbsx_guest_memio.len; @@ -1242,6 +1246,7 @@ long arch_do_domctl( if ( !ret && copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; + gdbsx_guestmemio_out: rcu_unlock_domain(d); } break; @@ -1255,21 +1260,20 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; + ret = xsm_debug_op(d); + if ( ret ) + goto gdbsx_pausevcpu_out; + ret = -EBUSY; if ( !d->is_paused_by_controller ) - { - rcu_unlock_domain(d); - break; - } + goto gdbsx_pausevcpu_out; 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; - } + goto gdbsx_pausevcpu_out; vcpu_pause(v); ret = 0; + gdbsx_pausevcpu_out: rcu_unlock_domain(d); } break; @@ -1283,23 +1287,22 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; + ret = xsm_debug_op(d); + if ( ret ) + goto gdbsx_unpausevcpu_out; + ret = -EBUSY; if ( !d->is_paused_by_controller ) - { - rcu_unlock_domain(d); - break; - } + goto gdbsx_unpausevcpu_out; 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; - } + goto gdbsx_unpausevcpu_out; if ( !atomic_read(&v->pause_count) ) printk("WARN: Unpausing vcpu:%d which is not paused\n", v->vcpu_id); vcpu_unpause(v); ret = 0; + gdbsx_unpausevcpu_out: rcu_unlock_domain(d); } break; @@ -1313,6 +1316,10 @@ long arch_do_domctl( if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; + ret = xsm_debug_op(d); + if ( ret ) + goto gdbsx_domstatus_out; + domctl->u.gdbsx_domstatus.vcpu_id = -1; domctl->u.gdbsx_domstatus.paused = d->is_paused_by_controller; if ( domctl->u.gdbsx_domstatus.paused ) @@ -1332,6 +1339,7 @@ long arch_do_domctl( ret = 0; if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; + gdbsx_domstatus_out: rcu_unlock_domain(d); } break; @@ -1471,10 +1479,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); } @@ -1503,16 +1509,19 @@ long arch_do_domctl( { struct domain *d; - ret = rcu_lock_remote_target_domain_by_id(domctl->domain, &d); - if ( ret != 0 ) + d = rcu_lock_domain_by_any_id(domctl->domain); + if ( d == NULL ) break; - audit_p2m(d, - &domctl->u.audit_p2m.orphans, - &domctl->u.audit_p2m.m2p_bad, - &domctl->u.audit_p2m.p2m_bad); + ret = xsm_audit_p2m(d); + if ( !ret ) + 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) ) + if ( !ret && copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; } break; @@ -1531,7 +1540,7 @@ long arch_do_domctl( d = rcu_lock_domain_by_id(domctl->domain); if ( d != NULL ) { - ret = xsm_mem_event(d); + ret = xsm_mem_event_setup(d); if ( !ret ) { p2m = p2m_get_hostp2m(d); p2m->access_required = domctl->u.access_required.access_required; diff --git a/xen/arch/x86/mm/mem_event.c b/xen/arch/x86/mm/mem_event.c index d728889..d574541 100644 --- a/xen/arch/x86/mm/mem_event.c +++ b/xen/arch/x86/mm/mem_event.c @@ -29,6 +29,7 @@ #include <asm/mem_paging.h> #include <asm/mem_access.h> #include <asm/mem_sharing.h> +#include <xsm/xsm.h> /* for public/io/ring.h macros */ #define xen_mb() mb() @@ -439,34 +440,22 @@ static void mem_sharing_notification(struct vcpu *v, unsigned int port) mem_sharing_sharing_resume(v->domain); } -struct domain *get_mem_event_op_target(uint32_t domain, int *rc) -{ - struct domain *d; - - /* Get the target domain */ - *rc = rcu_lock_remote_target_domain_by_id(domain, &d); - if ( *rc != 0 ) - return NULL; - - /* Not dying? */ - if ( d->is_dying ) - { - rcu_unlock_domain(d); - *rc = -EINVAL; - return NULL; - } - - return d; -} - int do_mem_event_op(int op, uint32_t domain, void *arg) { int ret; struct domain *d; - d = get_mem_event_op_target(domain, &ret); + d = rcu_lock_domain_by_any_id(domain); if ( !d ) - return ret; + return -ESRCH; + + ret = -EINVAL; + if ( d->is_dying || d == current->domain ) + goto out; + + ret = xsm_mem_event_op(d, op); + if ( ret ) + goto out; switch (op) { @@ -483,6 +472,7 @@ int do_mem_event_op(int op, uint32_t domain, void *arg) ret = -ENOSYS; } + out: rcu_unlock_domain(d); return ret; } @@ -516,6 +506,10 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, { int rc; + rc = xsm_mem_event_control(d, mec->mode, mec->op); + if ( rc ) + return rc; + if ( unlikely(d == current->domain) ) { gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n"); @@ -537,13 +531,6 @@ int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, return -EINVAL; } - /* TODO: XSM hook */ -#if 0 - rc = xsm_mem_event_control(d, mec->op); - if ( rc ) - return rc; -#endif - rc = -ENOSYS; switch ( mec->mode ) diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index 5103285..395d302 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -34,6 +34,7 @@ #include <asm/atomic.h> #include <xen/rcupdate.h> #include <asm/event.h> +#include <xsm/xsm.h> #include "mm-locks.h" @@ -1345,11 +1346,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); + cd = rcu_lock_domain_by_any_id(mec->u.share.client_domain); if ( !cd ) + return -ESRCH; + + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); return rc; + } - if ( !mem_sharing_enabled(cd) ) + if ( cd == current->domain || !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); return -EINVAL; @@ -1401,11 +1409,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); + cd = rcu_lock_domain_by_any_id(mec->u.share.client_domain); if ( !cd ) + return -ESRCH; + + rc = xsm_mem_sharing_op(d, cd, mec->op); + if ( rc ) + { + rcu_unlock_domain(cd); return rc; + } - if ( !mem_sharing_enabled(cd) ) + if ( cd == current->domain || !mem_sharing_enabled(cd) ) { rcu_unlock_domain(cd); return -EINVAL; diff --git a/xen/include/asm-x86/mem_event.h b/xen/include/asm-x86/mem_event.h index 23d71c1..448be4f 100644 --- a/xen/include/asm-x86/mem_event.h +++ b/xen/include/asm-x86/mem_event.h @@ -62,7 +62,6 @@ void mem_event_put_request(struct domain *d, struct mem_event_domain *med, int mem_event_get_response(struct domain *d, struct mem_event_domain *med, mem_event_response_t *rsp); -struct domain *get_mem_event_op_target(uint32_t domain, int *rc); int do_mem_event_op(int op, uint32_t domain, void *arg); int mem_event_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, XEN_GUEST_HANDLE(void) u_domctl); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 3f5d9b0..afbc504 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -171,6 +171,13 @@ static XSM_DEFAULT(int, setdebugging) (struct domain *d) return 0; } +static XSM_DEFAULT(int, debug_op) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, perfcontrol) (void) { if ( !IS_PRIV(current->domain) ) @@ -562,6 +569,27 @@ static XSM_DEFAULT(int, getpageframeinfo) (struct domain *d) return 0; } +static XSM_DEFAULT(int, set_cpuid) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, gettscinfo) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + +static XSM_DEFAULT(int, settscinfo) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, getmemlist) (struct domain *d) { if ( !IS_PRIV(current->domain) ) @@ -632,13 +660,27 @@ 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) { if ( !IS_PRIV(current->domain) ) return -EPERM; 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) { if ( !IS_PRIV(current->domain) ) @@ -646,6 +688,20 @@ 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, audit_p2m) (struct domain *d) +{ + if ( !IS_PRIV(current->domain) ) + return -EPERM; + return 0; +} + static XSM_DEFAULT(int, apic) (struct domain *d, int cmd) { if ( !IS_PRIV(current->domain) ) diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 6095a86..6483ec6 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -67,6 +67,7 @@ struct xsm_operations { int (*setdomainmaxmem) (struct domain *d); int (*setdomainhandle) (struct domain *d); int (*setdebugging) (struct domain *d); + int (*debug_op) (struct domain *d); int (*perfcontrol) (void); int (*debug_keys) (void); int (*getcpuinfo) (void); @@ -142,6 +143,9 @@ struct xsm_operations { #ifdef CONFIG_X86 int (*shadow_control) (struct domain *d, uint32_t op); int (*getpageframeinfo) (struct domain *d); + int (*set_cpuid) (struct domain *d); + int (*gettscinfo) (struct domain *d); + int (*settscinfo) (struct domain *d); int (*getmemlist) (struct domain *d); int (*hypercall_init) (struct domain *d); int (*hvmcontext) (struct domain *d, uint32_t op); @@ -152,8 +156,12 @@ 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 (*audit_p2m) (struct domain *d); int (*apic) (struct domain *d, int cmd); int (*xen_settime) (void); int (*memtype) (uint32_t access); @@ -301,6 +309,11 @@ static inline int xsm_setdebugging (struct domain *d) return xsm_call(setdebugging(d)); } +static inline int xsm_debug_op (struct domain *d) +{ + return xsm_call(debug_op(d)); +} + static inline int xsm_perfcontrol (void) { return xsm_call(perfcontrol()); @@ -328,7 +341,7 @@ static inline int xsm_get_pmstat(void) static inline int xsm_setpminfo(void) { - return xsm_call(setpminfo()); + return xsm_call(setpminfo()); } static inline int xsm_pm_op(void) @@ -608,6 +621,21 @@ static inline int xsm_getpageframeinfo (struct domain *d) return xsm_call(getpageframeinfo(d)); } +static inline int xsm_set_cpuid (struct domain *d) +{ + return xsm_call(set_cpuid(d)); +} + +static inline int xsm_gettscinfo (struct domain *d) +{ + return xsm_call(gettscinfo(d)); +} + +static inline int xsm_settscinfo (struct domain *d) +{ + return xsm_call(settscinfo(d)); +} + static inline int xsm_getmemlist (struct domain *d) { return xsm_call(getmemlist(d)); @@ -658,9 +686,19 @@ static inline int xsm_hvm_inject_msi (struct domain *d) return xsm_call(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_call(mem_event(d)); + return xsm_call(mem_event_setup(d)); +} + +static inline int xsm_mem_event_control (struct domain *d, int mode, int op) +{ + return xsm_call(mem_event_control(d, mode, op)); +} + +static inline int xsm_mem_event_op (struct domain *d, int op) +{ + return xsm_call(mem_event_op(d, op)); } static inline int xsm_mem_sharing (struct domain *d) @@ -668,6 +706,16 @@ static inline int xsm_mem_sharing (struct domain *d) return xsm_call(mem_sharing(d)); } +static inline int xsm_mem_sharing_op (struct domain *d, struct domain *cd, int op) +{ + return xsm_call(mem_sharing_op(d, cd, op)); +} + +static inline int xsm_audit_p2m (struct domain *d) +{ + return xsm_call(audit_p2m(d)); +} + static inline int xsm_apic (struct domain *d, int cmd) { return xsm_call(apic(d, cmd)); diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index af532b8..055071a 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -51,6 +51,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, setdomainmaxmem); set_to_dummy_if_null(ops, setdomainhandle); set_to_dummy_if_null(ops, setdebugging); + set_to_dummy_if_null(ops, debug_op); set_to_dummy_if_null(ops, perfcontrol); set_to_dummy_if_null(ops, debug_keys); set_to_dummy_if_null(ops, getcpuinfo); @@ -124,6 +125,9 @@ void xsm_fixup_ops (struct xsm_operations *ops) #ifdef CONFIG_X86 set_to_dummy_if_null(ops, shadow_control); set_to_dummy_if_null(ops, getpageframeinfo); + set_to_dummy_if_null(ops, set_cpuid); + set_to_dummy_if_null(ops, gettscinfo); + set_to_dummy_if_null(ops, settscinfo); set_to_dummy_if_null(ops, getmemlist); set_to_dummy_if_null(ops, hypercall_init); set_to_dummy_if_null(ops, hvmcontext); @@ -134,8 +138,12 @@ 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, audit_p2m); 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 6d4b4f0..fc89ebc 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -635,6 +635,12 @@ static int flask_setdebugging(struct domain *d) DOMAIN__SETDEBUGGING); } +static int flask_debug_op(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, + DOMAIN__SETDEBUGGING); +} + static int flask_debug_keys(void) { return domain_has_xen(current->domain, XEN__DEBUG); @@ -1041,6 +1047,21 @@ static int flask_getpageframeinfo(struct domain *d) return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGEINFO); } +static int flask_set_cpuid(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); +} + +static int flask_gettscinfo(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); +} + +static int flask_settscinfo(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); +} + static int flask_getmemlist(struct domain *d) { return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGELIST); @@ -1131,7 +1152,17 @@ 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_mem_event(struct domain *d) +static int flask_mem_event_setup(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_EVENT); +} + +static int flask_mem_event_control(struct domain *d, int mode, int op) +{ + return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_EVENT); +} + +static int flask_mem_event_op(struct domain *d, int op) { return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_EVENT); } @@ -1141,6 +1172,19 @@ static int flask_mem_sharing(struct domain *d) return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__MEM_SHARING); } +static int flask_mem_sharing_op(struct domain *d, struct domain *cd, int op) +{ + int rc = domain_has_perm(current->domain, cd, SECCLASS_HVM, HVM__MEM_SHARING); + if ( rc ) + return rc; + return domain_has_perm(d, cd, SECCLASS_HVM, HVM__SHARE_MEM); +} + +static int flask_audit_p2m(struct domain *d) +{ + return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__AUDIT_P2M); +} + static int flask_apic(struct domain *d, int cmd) { u32 perm; @@ -1492,6 +1536,7 @@ static struct xsm_operations flask_ops = { .setdomainmaxmem = flask_setdomainmaxmem, .setdomainhandle = flask_setdomainhandle, .setdebugging = flask_setdebugging, + .debug_op = flask_debug_op, .perfcontrol = flask_perfcontrol, .debug_keys = flask_debug_keys, .getcpuinfo = flask_getcpuinfo, @@ -1560,6 +1605,9 @@ static struct xsm_operations flask_ops = { #ifdef CONFIG_X86 .shadow_control = flask_shadow_control, .getpageframeinfo = flask_getpageframeinfo, + .set_cpuid = flask_set_cpuid, + .gettscinfo = flask_gettscinfo, + .settscinfo = flask_settscinfo, .getmemlist = flask_getmemlist, .hypercall_init = flask_hypercall_init, .hvmcontext = flask_hvmcontext, @@ -1568,8 +1616,12 @@ static struct xsm_operations flask_ops = { .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, - .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, + .audit_p2m = flask_audit_p2m, .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 10f8e80..997f098 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__SHARE_MEM, "share_mem") + S_(SECCLASS_HVM, HVM__AUDIT_P2M, "audit_p2m") 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..8596a55 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__SHARE_MEM 0x00002000UL +#define HVM__AUDIT_P2M 0x00004000UL #define EVENT__BIND 0x00000001UL #define EVENT__SEND 0x00000002UL -- 1.7.11.4
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Cc: Dan Magenheimer <dan.magenheimer@oracle.com> --- tools/flask/policy/policy/flask/access_vectors | 1 + xen/common/tmem.c | 10 +++++----- xen/include/xen/tmem_xen.h | 5 ----- 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, 28 insertions(+), 10 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 28b8ada..2986b40 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -35,6 +35,7 @@ class xen lockprof cpupool_op sched_op + tmem_op } class domain diff --git a/xen/common/tmem.c b/xen/common/tmem.c index 1a8777c..fe2db45 100644 --- a/xen/common/tmem.c +++ b/xen/common/tmem.c @@ -23,6 +23,7 @@ #include <xen/radix-tree.h> #include <xen/list.h> #include <xen/init.h> +#include <xsm/xsm.h> #define EXPORT /* indicates code other modules are dependent upon */ #define FORWARD @@ -2540,11 +2541,10 @@ static NOINLINE int do_tmem_control(struct tmem_op *op) uint32_t subop = op->u.ctrl.subop; OID *oidp = (OID *)(&op->u.ctrl.oid[0]); - if (!tmh_current_is_privileged()) - { - /* don''t fail... mystery: sometimes dom0 fails here */ - /* return -EPERM; */ - } + ret = xsm_tmem_control(subop); + if ( ret ) + return ret; + switch(subop) { case TMEMC_THAW: diff --git a/xen/include/xen/tmem_xen.h b/xen/include/xen/tmem_xen.h index 4a35760..f248128 100644 --- a/xen/include/xen/tmem_xen.h +++ b/xen/include/xen/tmem_xen.h @@ -344,11 +344,6 @@ static inline bool_t tmh_set_client_from_id( return rc; } -static inline bool_t tmh_current_is_privileged(void) -{ - return IS_PRIV(current->domain); -} - static inline uint8_t tmh_get_first_byte(pfp_t *pfp) { void *p = __map_domain_page(pfp); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index afbc504..b26de57 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -500,6 +500,13 @@ static XSM_DEFAULT(int, sched_op) (void) return 0; } +static XSM_DEFAULT(int, tmem_control) (uint32_t subcmd) +{ + 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 6483ec6..ff76cae 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -137,6 +137,7 @@ struct xsm_operations { int (*lockprof)(void); int (*cpupool_op)(void); int (*sched_op)(void); + int (*tmem_control)(uint32_t subop); long (*__do_xsm_op) (XEN_GUEST_HANDLE(xsm_op_t) op); @@ -605,6 +606,11 @@ static inline int xsm_sched_op(void) return xsm_call(sched_op()); } +static inline int xsm_tmem_control(uint32_t subop) +{ + return xsm_call(tmem_control(subop)); +} + 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 055071a..0a18d50 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -119,6 +119,7 @@ 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_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 fc89ebc..f6ec7bd 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -962,6 +962,11 @@ static inline int flask_sched_op(void) return domain_has_xen(current->domain, XEN__SCHED_OP); } +static inline int flask_tmem_control(uint32_t subcmd) +{ + return domain_has_xen(current->domain, XEN__TMEM_OP); +} + static int flask_perfcontrol(void) { return domain_has_xen(current->domain, XEN__PERFCONTROL); @@ -1599,6 +1604,7 @@ static struct xsm_operations flask_ops = { .lockprof = flask_lockprof, .cpupool_op = flask_cpupool_op, .sched_op = flask_sched_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 997f098..5d5a45a 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -29,6 +29,7 @@ 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_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 8596a55..e6d6a6d 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -29,6 +29,7 @@ #define XEN__LOCKPROF 0x08000000UL #define XEN__CPUPOOL_OP 0x10000000UL #define XEN__SCHED_OP 0x20000000UL +#define XEN__TMEM_OP 0x40000000UL #define DOMAIN__SETVCPUCONTEXT 0x00000001UL #define DOMAIN__PAUSE 0x00000002UL -- 1.7.11.4
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/include/xsm/xsm.h | 258 +++++++++++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 130 deletions(-) diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index ff76cae..8226d93 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -21,8 +21,6 @@ typedef void xsm_op_t; DEFINE_XEN_GUEST_HANDLE(xsm_op_t); -#define xsm_call(fn) xsm_ops->fn - /* policy magic number (defined by XSM_MAGIC) */ typedef u32 xsm_magic_t; #ifndef XSM_MAGIC @@ -197,418 +195,418 @@ 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_debug_op (struct domain *d) { - return xsm_call(debug_op(d)); + return xsm_ops->debug_op(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)); + xsm_ops->free_security_evtchn(chn); } static inline char *xsm_show_security_evtchn (struct domain *d, const struct evtchn *chn) { - return xsm_call(show_security_evtchn(d, chn)); + return xsm_ops->show_security_evtchn(d, chn); } static inline int xsm_get_pod_target (struct domain *d) { - return xsm_call(get_pod_target(d)); + return xsm_ops->get_pod_target(d); } static inline int xsm_set_pod_target (struct domain *d) { - return xsm_call(set_pod_target(d)); + return xsm_ops->set_pod_target(d); } static inline int xsm_memory_adjust_reservation (struct domain *d1, struct domain *d2) { - return xsm_call(memory_adjust_reservation(d1, d2)); + return xsm_ops->memory_adjust_reservation(d1, d2); } static inline int xsm_memory_stat_reservation (struct domain *d1, struct domain *d2) { - return xsm_call(memory_stat_reservation(d1, d2)); + return xsm_ops->memory_stat_reservation(d1, d2); } static inline int xsm_memory_pin_page(struct domain *d1, struct domain *d2, struct page_info *page) { - return xsm_call(memory_pin_page(d1, d2, page)); + return xsm_ops->memory_pin_page(d1, d2, page); } static inline int xsm_remove_from_physmap(struct domain *d1, struct domain *d2) { - return xsm_call(remove_from_physmap(d1, d2)); + return xsm_ops->remove_from_physmap(d1, d2); } static inline int xsm_console_io (struct domain *d, int cmd) { - return xsm_call(console_io(d, cmd)); + return xsm_ops->console_io(d, cmd); } static inline int xsm_profile (struct domain *d, int op) { - return xsm_call(profile(d, op)); + return xsm_ops->profile(d, op); } static inline int xsm_kexec (void) { - return xsm_call(kexec()); + return xsm_ops->kexec(); } static inline int xsm_schedop_shutdown (struct domain *d1, struct domain *d2) { - return xsm_call(schedop_shutdown(d1, d2)); + return xsm_ops->schedop_shutdown(d1, d2); } static inline char *xsm_show_irq_sid (int irq) { - return xsm_call(show_irq_sid(irq)); + return xsm_ops->show_irq_sid(irq); } static inline int xsm_map_domain_pirq (struct domain *d, int irq, void *data) { - return xsm_call(map_domain_pirq(d, irq, data)); + return xsm_ops->map_domain_pirq(d, irq, data); } static inline int xsm_unmap_domain_pirq (struct domain *d, int irq) { - return xsm_call(unmap_domain_pirq(d, irq)); + return xsm_ops->unmap_domain_pirq(d, irq); } static inline int xsm_irq_permission (struct domain *d, int pirq, uint8_t allow) { - return xsm_call(irq_permission(d, pirq, allow)); + return xsm_ops->irq_permission(d, pirq, allow); } static inline int xsm_iomem_permission (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { - return xsm_call(iomem_permission(d, s, e, allow)); + return xsm_ops->iomem_permission(d, s, e, allow); } static inline int xsm_iomem_mapping (struct domain *d, uint64_t s, uint64_t e, uint8_t allow) { - return xsm_call(iomem_mapping(d, s, e, allow)); + return xsm_ops->iomem_mapping(d, s, e, allow); } static inline int xsm_pci_config_permission (struct domain *d, uint32_t machine_bdf, uint16_t start, uint16_t end, uint8_t access) { - return xsm_call(pci_config_permission(d, machine_bdf, start, end, access)); + return xsm_ops->pci_config_permission(d, machine_bdf, start, end, access); } static inline int xsm_get_device_group(uint32_t machine_bdf) { - return xsm_call(get_device_group(machine_bdf)); + return xsm_ops->get_device_group(machine_bdf); } static inline int xsm_test_assign_device(uint32_t machine_bdf) { - return xsm_call(test_assign_device(machine_bdf)); + return xsm_ops->test_assign_device(machine_bdf); } static inline int xsm_assign_device(struct domain *d, uint32_t machine_bdf) { - return xsm_call(assign_device(d, machine_bdf)); + return xsm_ops->assign_device(d, machine_bdf); } static inline int xsm_deassign_device(struct domain *d, uint32_t machine_bdf) { - return xsm_call(deassign_device(d, machine_bdf)); + return xsm_ops->deassign_device(d, machine_bdf); } static inline int xsm_resource_plug_pci (uint32_t machine_bdf) { - return xsm_call(resource_plug_pci(machine_bdf)); + return xsm_ops->resource_plug_pci(machine_bdf); } static inline int xsm_resource_unplug_pci (uint32_t machine_bdf) { - return xsm_call(resource_unplug_pci(machine_bdf)); + return xsm_ops->resource_unplug_pci(machine_bdf); } static inline int xsm_resource_plug_core (void) { - return xsm_call(resource_plug_core()); + return xsm_ops->resource_plug_core(); } static inline int xsm_resource_unplug_core (void) { - return xsm_call(resource_unplug_core()); + return xsm_ops->resource_unplug_core(); } static inline int xsm_resource_setup_pci (uint32_t machine_bdf) { - return xsm_call(resource_setup_pci(machine_bdf)); + return xsm_ops->resource_setup_pci(machine_bdf); } static inline int xsm_resource_setup_gsi (int gsi) { - return xsm_call(resource_setup_gsi(gsi)); + return xsm_ops->resource_setup_gsi(gsi); } static inline int xsm_resource_setup_misc (void) { - return xsm_call(resource_setup_misc()); + return xsm_ops->resource_setup_misc(); } static inline int xsm_page_offline(uint32_t cmd) { - return xsm_call(page_offline(cmd)); + return xsm_ops->page_offline(cmd); } static inline int xsm_lockprof(void) { - return xsm_call(lockprof()); + return xsm_ops->lockprof(); } static inline int xsm_cpupool_op(void) { - return xsm_call(cpupool_op()); + return xsm_ops->cpupool_op(); } static inline int xsm_sched_op(void) { - return xsm_call(sched_op()); + return xsm_ops->sched_op(); } static inline int xsm_tmem_control(uint32_t subop) { - return xsm_call(tmem_control(subop)); + return xsm_ops->tmem_control(subop); } static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) @@ -619,236 +617,236 @@ static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) #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_set_cpuid (struct domain *d) { - return xsm_call(set_cpuid(d)); + return xsm_ops->set_cpuid(d); } static inline int xsm_gettscinfo (struct domain *d) { - return xsm_call(gettscinfo(d)); + return xsm_ops->gettscinfo(d); } static inline int xsm_settscinfo (struct domain *d) { - return xsm_call(settscinfo(d)); + return xsm_ops->settscinfo(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_setup (struct domain *d) { - return xsm_call(mem_event_setup(d)); + return xsm_ops->mem_event_setup(d); } static inline int xsm_mem_event_control (struct domain *d, int mode, int op) { - return xsm_call(mem_event_control(d, mode, op)); + return xsm_ops->mem_event_control(d, mode, op); } static inline int xsm_mem_event_op (struct domain *d, int op) { - return xsm_call(mem_event_op(d, op)); + return xsm_ops->mem_event_op(d, op); } 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_mem_sharing_op (struct domain *d, struct domain *cd, int op) { - return xsm_call(mem_sharing_op(d, cd, op)); + return xsm_ops->mem_sharing_op(d, cd, op); } static inline int xsm_audit_p2m (struct domain *d) { - return xsm_call(audit_p2m(d)); + return xsm_ops->audit_p2m(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 */ -- 1.7.11.4
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 16/20] 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 | 425 +++++++++++++-------------- xen/xsm/flask/include/objsec.h | 2 + 6 files changed, 309 insertions(+), 243 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 3527054..1847f23 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 }; + 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 }; +'') + +# 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 f6ec7bd..7da1754 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); +} + +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(dsec->sid, esec->sid, SECCLASS_EVENT, perms, NULL); + 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,53 +564,61 @@ 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 = current_has_perm(t, SECCLASS_DOMAIN2, DOMAIN2__SET_AS_TARGET); if ( rc ) return rc; - rc = domain_has_perm(current->domain, e, SECCLASS_DOMAIN2, DOMAIN2__SET_AS_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; - return domain_has_perm(d, e, SECCLASS_DOMAIN, DOMAIN__SET_TARGET); + + /* (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) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO); + return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SET_MISC_INFO); } 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) @@ -619,26 +643,22 @@ 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_op(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) @@ -700,14 +720,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; @@ -723,14 +741,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; } @@ -738,16 +755,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; @@ -757,19 +770,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; }; @@ -783,12 +796,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) @@ -796,7 +809,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; @@ -806,18 +819,17 @@ 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); } 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); @@ -830,33 +842,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) @@ -864,7 +867,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 ) @@ -872,8 +874,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) @@ -881,7 +882,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 ) @@ -889,8 +889,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) @@ -898,7 +897,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 ) @@ -906,8 +904,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) @@ -915,22 +912,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) @@ -998,11 +990,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; }; @@ -1016,12 +1009,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); } @@ -1030,7 +1023,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 ) @@ -1041,41 +1034,40 @@ 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); } 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_set_cpuid(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_CPUID); } static int flask_gettscinfo(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GETTSC); } static int flask_settscinfo(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); + return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SETTSC); } 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) @@ -1098,7 +1090,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) @@ -1117,7 +1109,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_hvm_param(struct domain *d, unsigned long op) @@ -1139,47 +1131,47 @@ 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_mem_event_setup(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_event_control(struct domain *d, int mode, int op) { - 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_event_op(struct domain *d, int op) { - 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_mem_sharing_op(struct domain *d, struct domain *cd, int op) { - int rc = domain_has_perm(current->domain, cd, SECCLASS_HVM, HVM__MEM_SHARING); + 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); @@ -1187,7 +1179,7 @@ static int flask_mem_sharing_op(struct domain *d, struct domain *cd, int op) static int flask_audit_p2m(struct domain *d) { - return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__AUDIT_P2M); + return current_has_perm(d, SECCLASS_HVM, HVM__AUDIT_P2M); } static int flask_apic(struct domain *d, int cmd) @@ -1248,11 +1240,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_firmware_info(void) @@ -1282,16 +1270,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) @@ -1314,17 +1298,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); @@ -1367,43 +1351,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; @@ -1413,22 +1394,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; @@ -1436,18 +1415,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; @@ -1457,23 +1435,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) @@ -1492,7 +1469,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) @@ -1511,7 +1488,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-10 19:49 UTC
[PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
This requires introducing a new XSM hook for do_mmuext_op to validate remote domain access 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 + tools/flask/policy/policy/modules/xen/xen.if | 4 ++-- xen/arch/x86/mm.c | 23 +++++++---------------- xen/include/xsm/dummy.h | 15 +++++++++++++++ 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, 40 insertions(+), 18 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 2986b40..5e897e2 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 1847f23..e0c2d2d 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 f16b112..692d651 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2882,11 +2882,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: @@ -2895,12 +2890,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; } @@ -3008,6 +2997,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() ) @@ -3483,11 +3479,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 ) diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index b26de57..a093734 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -803,18 +803,33 @@ static XSM_DEFAULT(int, domain_memory_map) (struct domain *d) static XSM_DEFAULT(int, mmu_normal_update) (struct domain *d, struct domain *t, struct domain *f, intpte_t fpte) { + if ( d != t && !IS_PRIV_FOR(d, t) ) + return -EPERM; + if ( d != f && !IS_PRIV_FOR(d, f) ) + return -EPERM; return 0; } static XSM_DEFAULT(int, mmu_machphys_update) (struct domain *d, struct domain *f, unsigned long mfn) { + if ( d != f && !IS_PRIV_FOR(d, f) ) + return -EPERM; + return 0; +} + +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 8226d93..cf2a7e5 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -177,6 +177,7 @@ struct xsm_operations { 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); + 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); @@ -797,6 +798,11 @@ static inline int xsm_mmu_machphys_update (struct domain *d1, struct domain *d2, return xsm_ops->mmu_machphys_update(d1, d2, mfn); } +static inline int xsm_mmuext_op (struct domain *d, struct domain *f) +{ + return xsm_ops->mmuext_op(d, f); +} + static inline int xsm_update_va_mapping(struct domain *d, struct domain *f, l1_pgentry_t pte) { diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 0a18d50..954f97c 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -160,6 +160,7 @@ void xsm_fixup_ops (struct xsm_operations *ops) 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, 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 7da1754..dc5f67e 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1333,6 +1333,11 @@ static int flask_mmu_machphys_update(struct domain *d1, struct domain *d2, return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__UPDATEMP); } +static int flask_mmuext_op(struct domain *d, struct domain *f) +{ + 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) { @@ -1620,6 +1625,7 @@ static struct xsm_operations flask_ops = { .domain_memory_map = flask_domain_memory_map, .mmu_normal_update = flask_mmu_normal_update, .mmu_machphys_update = flask_mmu_machphys_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 5d5a45a..5d4f316 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 e6d6a6d..f970b50 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> --- 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 5e897e2..2736075 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 e0c2d2d..8056f18 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -30,6 +30,7 @@ define(`declare_domain'', ` # containing at most one domain. This is not enforced by policy. define(`declare_singleton_domain'', ` type $1, domain_type`''ifelse(`$#'', `1'', `'', `,shift($@)''); + define(`$1_self'', `$1'') type $1_channel, event_type; type_transition $1 domain_type:event $1_channel; declare_domain_common($1, $1) @@ -161,6 +162,7 @@ define(`make_device_model'', ` # use_device(domain, device) # Allow a device to be used by a domain define(`use_device'', ` + allow $1 $1_self:mmu exchange; allow $1 $2:resource use; allow $1 $2:mmu { map_read map_write }; '') diff --git a/xen/common/memory.c b/xen/common/memory.c index cfdd63f..a5b548b 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -329,9 +329,19 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) out_chunk_order = exch.in.extent_order - exch.out.extent_order; } - rc = rcu_lock_target_domain_by_id(exch.in.domid, &d); + d = rcu_lock_domain_by_any_id(exch.in.domid); + if ( d == NULL ) + { + rc = -ESRCH; + goto fail_early; + } + + rc = xsm_memory_exchange(d); if ( rc ) + { + rcu_unlock_domain(d); goto fail_early; + } memflags |= MEMF_bits(domain_clamp_alloc_bitsize( d, diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index a093734..16ad33a 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -279,6 +279,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 cf2a7e5..8c11172 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -98,6 +98,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); @@ -452,6 +453,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 954f97c..8e13740 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 dc5f67e..316e8ef 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); @@ -1555,6 +1560,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 5d4f316..b2c77b2 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 f970b50..acb0b1a 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
Daniel De Graaf
2012-Sep-10 19:49 UTC
[PATCH 19/20] xen: remove rcu_lock_{remote_, }target_domain_by_id
These functions are now (mostly) unused, replaced by versions without an implicit access control check. Make the checks explicit in the remaining callers. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/arch/x86/physdev.c | 18 +++++++++++------- xen/common/domain.c | 34 ---------------------------------- xen/include/xen/sched.h | 14 -------------- 3 files changed, 11 insertions(+), 55 deletions(-) diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index d6ea4f0..4dfb5a0 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -106,9 +106,11 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p, return physdev_hvm_map_pirq(d, type, index, pirq_p); } - ret = rcu_lock_target_domain_by_id(domid, &d); - if ( ret ) - return ret; + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; + if ( d != current->domain && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; /* Verify or get irq. */ switch ( type ) @@ -217,11 +219,13 @@ int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p, int physdev_unmap_pirq(domid_t domid, int pirq) { struct domain *d; - int ret; + int ret = 0; - ret = rcu_lock_target_domain_by_id(domid, &d); - if ( ret ) - return ret; + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; + if ( d != current->domain && !IS_PRIV_FOR(current->domain, d) ) + return -EPERM; if ( is_hvm_domain(d) ) { diff --git a/xen/common/domain.c b/xen/common/domain.c index 52489b3..ecfc6d6 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -427,40 +427,6 @@ struct domain *rcu_lock_domain_by_any_id(domid_t dom) return rcu_lock_domain_by_id(dom); } -int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d) -{ - if ( dom == DOMID_SELF ) - { - *d = rcu_lock_current_domain(); - return 0; - } - - if ( (*d = rcu_lock_domain_by_id(dom)) == NULL ) - return -ESRCH; - - if ( !IS_PRIV_FOR(current->domain, *d) ) - { - rcu_unlock_domain(*d); - return -EPERM; - } - - return 0; -} - -int rcu_lock_remote_target_domain_by_id(domid_t dom, struct domain **d) -{ - if ( (*d = rcu_lock_domain_by_id(dom)) == NULL ) - return -ESRCH; - - if ( (*d == current->domain) || !IS_PRIV_FOR(current->domain, *d) ) - { - rcu_unlock_domain(*d); - return -EPERM; - } - - return 0; -} - int rcu_lock_remote_domain_by_id(domid_t dom, struct domain **d) { if ( (*d = rcu_lock_domain_by_id(dom)) == NULL ) diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index b0def4a..9019c21 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -452,20 +452,6 @@ struct domain *rcu_lock_domain_by_id(domid_t dom); 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. - */ -int rcu_lock_target_domain_by_id(domid_t dom, struct domain **d); - -/* - * As rcu_lock_target_domain_by_id(), but will fail EPERM rather than resolve - * to local domain. Successful return always resolves to a remote domain that - * the local domain is privileged to control. - */ -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. */ -- 1.7.11.4
The hvm_inject_msi, machine_address_size, iomem_mapping, and ioport_mapping security operations did not have FLASK operations defined; define them now. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- tools/flask/policy/policy/flask/access_vectors | 1 + tools/flask/policy/policy/modules/xen/xen.if | 2 +- xen/xsm/flask/hooks.c | 42 ++++++++++++++++++++++++-- xen/xsm/flask/include/av_perm_to_string.h | 1 + xen/xsm/flask/include/av_permissions.h | 1 + 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/tools/flask/policy/policy/flask/access_vectors b/tools/flask/policy/policy/flask/access_vectors index 2736075..b394fc1 100644 --- a/tools/flask/policy/policy/flask/access_vectors +++ b/tools/flask/policy/policy/flask/access_vectors @@ -103,6 +103,7 @@ class hvm mem_sharing share_mem 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 8056f18..67f5daf 100644 --- a/tools/flask/policy/policy/modules/xen/xen.if +++ b/tools/flask/policy/policy/modules/xen/xen.if @@ -143,7 +143,7 @@ define(`device_model'', ` 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 }; + allow $1 $2_target:hvm { getparam setparam trackdirtyvram hvmctl irqlevel pciroute cacheattr send_irq }; '') # make_device_model(priv, dm_dom, hvm_dom) diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 316e8ef..12638c4 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -814,8 +814,7 @@ static int flask_iomem_permission(struct domain *d, uint64_t start, uint64_t end struct iomem_has_perm_data data; int rc; - rc = current_has_perm(d, SECCLASS_RESOURCE, - resource_to_perm(access)); + rc = current_has_perm(d, SECCLASS_RESOURCE, resource_to_perm(access)); if ( rc ) return rc; @@ -830,6 +829,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 dsid, rsid; @@ -1022,7 +1026,6 @@ static int _ioport_has_perm(void *v, u32 sid, unsigned long start, unsigned long 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) { int rc; @@ -1045,6 +1048,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 current_has_perm(d, SECCLASS_MMU, MMU__PAGEINFO); @@ -1117,6 +1125,25 @@ static int flask_address_size(struct domain *d, uint32_t cmd) return current_has_perm(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 current_has_perm(d, SECCLASS_DOMAIN, perm); +} + static int flask_hvm_param(struct domain *d, unsigned long op) { u32 perm; @@ -1154,6 +1181,11 @@ static int flask_hvm_set_pci_link_route(struct domain *d) return current_has_perm(d, SECCLASS_HVM, HVM__PCIROUTE); } +static int flask_hvm_inject_msi(struct domain *d) +{ + return current_has_perm(d, SECCLASS_HVM, HVM__SEND_IRQ); +} + static int flask_mem_event_setup(struct domain *d) { return current_has_perm(d, SECCLASS_HVM, HVM__MEM_EVENT); @@ -1578,6 +1610,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, @@ -1606,10 +1639,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_setup = flask_mem_event_setup, .mem_event_control = flask_mem_event_control, .mem_event_op = flask_mem_event_op, @@ -1646,6 +1681,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 b2c77b2..1b958fd 100644 --- a/xen/xsm/flask/include/av_perm_to_string.h +++ b/xen/xsm/flask/include/av_perm_to_string.h @@ -85,6 +85,7 @@ S_(SECCLASS_HVM, HVM__MEM_SHARING, "mem_sharing") S_(SECCLASS_HVM, HVM__SHARE_MEM, "share_mem") 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 acb0b1a..15a7eee 100644 --- a/xen/xsm/flask/include/av_permissions.h +++ b/xen/xsm/flask/include/av_permissions.h @@ -88,6 +88,7 @@ #define HVM__MEM_SHARING 0x00001000UL #define HVM__SHARE_MEM 0x00002000UL #define HVM__AUDIT_P2M 0x00004000UL +#define HVM__SEND_IRQ 0x00008000UL #define EVENT__BIND 0x00000001UL #define EVENT__SEND 0x00000002UL -- 1.7.11.4
On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote:> Overall, this series should not change the behavior of Xen when XSM is > not enabled; however, in some cases, the exact errors that are returned > will be different because security checks have been moved below validity > checks. Also, once applied, newly introduced domctls and sysctls will > not automatically be guarded by IS_PRIV checks - they will need to add > their own permission checking code.How do we guard against accidentally forgetting to do this?> The ARM architecture is not touched at all in these patches. The only > obvious breakage that I can see is due to rcu_lock_target_domain_by_id > being removed, but XSM hooks will be needed for domctls and sysctls.So ARM build is broken? And/or ARM is made insecure because of unchecked sysctls/domctls? -- Keir> The rcu_lock_target_domain_by_id and rcu_lock_remote_target_domain_by_id > functions are removed by this series because they act as wrappers around > IS_PRIV_FOR; their callers have been changed to use XSM checks instead. > > Miscellaneous updates to FLASK: > [PATCH 01/20] xsm/flask: remove inherited class attributes > [PATCH 02/20] xsm/flask: remove unneeded create_sid field > [PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV > [PATCH 04/20] xsm/flask: add domain relabel support > [PATCH 05/20] libxl: introduce XSM relabel on build > [PATCH 06/20] flask/policy: Add domain relabel example > > Preparatory new hooks: > [PATCH 07/20] arch/x86: add distinct XSM hooks for map/unmap > [PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands > [PATCH 09/20] xsm/flask: Add checks on the domain performing the > > Refactoring: > [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module > [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated > [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM > > Remaining IS_PRIV calls: > [PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks > [PATCH 14/20] tmem: Add access control check > [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks > [PATCH 18/20] xen: Add XSM hook for XENMEM_exchange > > Cleanup, FLASK updates to support IS_PRIV emulation: > [PATCH 15/20] xsm: remove unneeded xsm_call macro > [PATCH 16/20] xsm/flask: add distinct SIDs for self/target access > [PATCH 19/20] xen: remove rcu_lock_{remote_,}target_domain_by_id > [PATCH 20/20] flask: add missing operations > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On 09/10/2012 04:51 PM, Keir Fraser wrote:> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: > >> Overall, this series should not change the behavior of Xen when XSM is >> not enabled; however, in some cases, the exact errors that are returned >> will be different because security checks have been moved below validity >> checks. Also, once applied, newly introduced domctls and sysctls will >> not automatically be guarded by IS_PRIV checks - they will need to add >> their own permission checking code. > > How do we guard against accidentally forgetting to do this?The same way you guard against it when adding a new hypercall: when adding new functionality that needs access checks, also add the access checks.>> The ARM architecture is not touched at all in these patches. The only >> obvious breakage that I can see is due to rcu_lock_target_domain_by_id >> being removed, but XSM hooks will be needed for domctls and sysctls. > > So ARM build is broken? And/or ARM is made insecure because of unchecked > sysctls/domctls? > > -- KeirThe ARM build is broken by patch #19 in this series; fixing it is fairly simple (I''ll send a non-compile-tested version as 21/20), or you could postpone that patch as it''s just cleanup. Since ARM doesn''t have any arch-specific domctls or sysctls yet, they are not insecure. You could also add an IS_PRIV check at the top of ARM''s arch_do_{dom,sys}ctl functions if you don''t want to add XSM hooks for each operation as in x86.> >> The rcu_lock_target_domain_by_id and rcu_lock_remote_target_domain_by_id >> functions are removed by this series because they act as wrappers around >> IS_PRIV_FOR; their callers have been changed to use XSM checks instead. >> >> Miscellaneous updates to FLASK: >> [PATCH 01/20] xsm/flask: remove inherited class attributes >> [PATCH 02/20] xsm/flask: remove unneeded create_sid field >> [PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV >> [PATCH 04/20] xsm/flask: add domain relabel support >> [PATCH 05/20] libxl: introduce XSM relabel on build >> [PATCH 06/20] flask/policy: Add domain relabel example >> >> Preparatory new hooks: >> [PATCH 07/20] arch/x86: add distinct XSM hooks for map/unmap >> [PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands >> [PATCH 09/20] xsm/flask: Add checks on the domain performing the >> >> Refactoring: >> [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module >> [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated >> [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM >> >> Remaining IS_PRIV calls: >> [PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks >> [PATCH 14/20] tmem: Add access control check >> [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks >> [PATCH 18/20] xen: Add XSM hook for XENMEM_exchange >> >> Cleanup, FLASK updates to support IS_PRIV emulation: >> [PATCH 15/20] xsm: remove unneeded xsm_call macro >> [PATCH 16/20] xsm/flask: add distinct SIDs for self/target access >> [PATCH 19/20] xen: remove rcu_lock_{remote_,}target_domain_by_id >> [PATCH 20/20] flask: add missing operations >>
Daniel De Graaf
2012-Sep-10 21:13 UTC
[PATCH 21/20] arch/arm: replace rcu_lock_target_domain_by_id with XSM
Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/arch/arm/hvm.c | 12 +++++++++--- xen/arch/arm/mm.c | 11 +++++++++-- xen/include/xsm/dummy.h | 29 +++++++++++++++-------------- xen/include/xsm/xsm.h | 25 +++++++++++++------------ 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/xen/arch/arm/hvm.c b/xen/arch/arm/hvm.c index c11378d..3cb8eec 100644 --- a/xen/arch/arm/hvm.c +++ b/xen/arch/arm/hvm.c @@ -4,6 +4,7 @@ #include <xen/errno.h> #include <xen/guest_access.h> #include <xen/sched.h> +#include <xsm/xsm.h> #include <public/xen.h> #include <public/hvm/params.h> @@ -30,9 +31,13 @@ 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 = xsm_hvm_param(d, op); + if ( rc ) + goto param_fail; if ( op == HVMOP_set_param ) { @@ -44,6 +49,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; } + param_fail: rcu_unlock_domain(d); break; } diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c index 40ac176..ffef978 100644 --- a/xen/arch/arm/mm.c +++ b/xen/arch/arm/mm.c @@ -31,6 +31,7 @@ #include <asm/current.h> #include <public/memory.h> #include <xen/sched.h> +#include <xsm/xsm.h> struct domain *dom_xen, *dom_io; @@ -508,9 +509,15 @@ 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 ) + d = rcu_lock_domain_by_any_id(xatp.domid); + if ( d == NULL ) + return -ESRCH; + rc = xsm_add_to_physmap(current->domain, d); + if ( rc ) + { + rcu_unlock_domain(d); return rc; + } rc = xenmem_add_to_physmap(d, &xatp); diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index 16ad33a..d2a8879 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -568,6 +568,21 @@ static XSM_DEFAULT(int, pci_config_permission) (struct domain *d, uint32_t machi return 0; } +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, add_to_physmap) (struct domain *d1, struct domain *d2) +{ + if ( d1 != d2 && !IS_PRIV_FOR(d1, d2) ) + return -EPERM; + return 0; +} + + #ifdef CONFIG_X86 static XSM_DEFAULT(int, shadow_control) (struct domain *d, uint32_t op) { @@ -639,13 +654,6 @@ 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) -{ - 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) ) @@ -840,13 +848,6 @@ static XSM_DEFAULT(int, update_va_mapping) (struct domain *d, struct domain *f, return 0; } -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) ) diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 8c11172..d0538b4 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -140,6 +140,9 @@ struct xsm_operations { long (*__do_xsm_op) (XEN_GUEST_HANDLE(xsm_op_t) op); + int (*hvm_param) (struct domain *d, unsigned long op); + int (*add_to_physmap) (struct domain *d1, struct domain *d2); + #ifdef CONFIG_X86 int (*shadow_control) (struct domain *d, uint32_t op); int (*getpageframeinfo) (struct domain *d); @@ -151,7 +154,6 @@ struct xsm_operations { int (*hvmcontext) (struct domain *d, uint32_t op); int (*address_size) (struct domain *d, uint32_t op); int (*machine_address_size) (struct domain *d, uint32_t op); - int (*hvm_param) (struct domain *d, unsigned long op); int (*hvm_set_pci_intx_level) (struct domain *d); int (*hvm_set_isa_irq_level) (struct domain *d); int (*hvm_set_pci_link_route) (struct domain *d); @@ -180,7 +182,6 @@ struct xsm_operations { int (*mmu_machphys_update) (struct domain *d1, struct domain *d2, unsigned long mfn); 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); int (*bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); int (*unbind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind); @@ -621,6 +622,16 @@ static inline long xsm___do_xsm_op (XEN_GUEST_HANDLE(xsm_op_t) op) return xsm_ops->__do_xsm_op(op); } +static inline int xsm_hvm_param (struct domain *d, unsigned long op) +{ + return xsm_ops->hvm_param(d, op); +} + +static inline int xsm_add_to_physmap(struct domain *d1, struct domain *d2) +{ + return xsm_ops->add_to_physmap(d1, d2); +} + #ifdef CONFIG_X86 static inline int xsm_shadow_control (struct domain *d, uint32_t op) { @@ -672,11 +683,6 @@ static inline int xsm_machine_address_size (struct domain *d, uint32_t cmd) return xsm_ops->machine_address_size(d, cmd); } -static inline int xsm_hvm_param (struct domain *d, unsigned long op) -{ - return xsm_ops->hvm_param(d, op); -} - static inline int xsm_hvm_set_pci_intx_level (struct domain *d) { return xsm_ops->hvm_set_pci_intx_level(d); @@ -815,11 +821,6 @@ static inline int xsm_update_va_mapping(struct domain *d, struct domain *f, return xsm_ops->update_va_mapping(d, f, pte); } -static inline int xsm_add_to_physmap(struct domain *d1, struct domain *d2) -{ - return xsm_ops->add_to_physmap(d1, d2); -} - static inline int xsm_sendtrigger(struct domain *d) { return xsm_ops->sendtrigger(d); -- 1.7.11.4
On 10/09/2012 22:10, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote:> On 09/10/2012 04:51 PM, Keir Fraser wrote: >> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >> >>> Overall, this series should not change the behavior of Xen when XSM is >>> not enabled; however, in some cases, the exact errors that are returned >>> will be different because security checks have been moved below validity >>> checks. Also, once applied, newly introduced domctls and sysctls will >>> not automatically be guarded by IS_PRIV checks - they will need to add >>> their own permission checking code. >> >> How do we guard against accidentally forgetting to do this? > > The same way you guard against it when adding a new hypercall: when adding > new functionality that needs access checks, also add the access checks.So... We just shouldn''t accidentally forget. That will work well. ;) Historically XSM has not been top of many committers'' checklists. -- Keir>>> The ARM architecture is not touched at all in these patches. The only >>> obvious breakage that I can see is due to rcu_lock_target_domain_by_id >>> being removed, but XSM hooks will be needed for domctls and sysctls. >> >> So ARM build is broken? And/or ARM is made insecure because of unchecked >> sysctls/domctls? >> >> -- Keir > > The ARM build is broken by patch #19 in this series; fixing it is fairly > simple (I''ll send a non-compile-tested version as 21/20), or you could > postpone that patch as it''s just cleanup. > > Since ARM doesn''t have any arch-specific domctls or sysctls yet, they are > not insecure. You could also add an IS_PRIV check at the top of ARM''s > arch_do_{dom,sys}ctl functions if you don''t want to add XSM hooks for each > operation as in x86. > >> >>> The rcu_lock_target_domain_by_id and rcu_lock_remote_target_domain_by_id >>> functions are removed by this series because they act as wrappers around >>> IS_PRIV_FOR; their callers have been changed to use XSM checks instead. >>> >>> Miscellaneous updates to FLASK: >>> [PATCH 01/20] xsm/flask: remove inherited class attributes >>> [PATCH 02/20] xsm/flask: remove unneeded create_sid field >>> [PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV >>> [PATCH 04/20] xsm/flask: add domain relabel support >>> [PATCH 05/20] libxl: introduce XSM relabel on build >>> [PATCH 06/20] flask/policy: Add domain relabel example >>> >>> Preparatory new hooks: >>> [PATCH 07/20] arch/x86: add distinct XSM hooks for map/unmap >>> [PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands >>> [PATCH 09/20] xsm/flask: Add checks on the domain performing the >>> >>> Refactoring: >>> [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module >>> [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated >>> [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM >>> >>> Remaining IS_PRIV calls: >>> [PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks >>> [PATCH 14/20] tmem: Add access control check >>> [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks >>> [PATCH 18/20] xen: Add XSM hook for XENMEM_exchange >>> >>> Cleanup, FLASK updates to support IS_PRIV emulation: >>> [PATCH 15/20] xsm: remove unneeded xsm_call macro >>> [PATCH 16/20] xsm/flask: add distinct SIDs for self/target access >>> [PATCH 19/20] xen: remove rcu_lock_{remote_,}target_domain_by_id >>> [PATCH 20/20] flask: add missing operations >>>
Jan Beulich
2012-Sep-11 07:29 UTC
Re: [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > Some checks are removed due to non-obvious duplicates in their callers: > > * acpi_enter_sleep is checked by its only caller > * map_domain_pirq has IS_PRIV_FOR checked in physdev_map_pirq... and ioapic_guest_write(). Please have this list complete, as it is going to be necessary to fully validate this (now and retrospectively once applied) for the absence of security holes.> * PHYSDEVOP_alloc_irq_vector is a noop, does not need IS_PRIVNAK. This nevertheless is a privileged operation (i.e. must not succeed for unprivileged guests).> * Many PHYSDEVOP access checks are within the implementation functionsFor the above named reason, please fully document this.> * do_platform_op, do_domctl, and do_sysctl all have per-operation > XSM hooks > * do_console_io has changed to IS_PRIV from an explicit domid==0I see a point in actually limiting this to Dom0 - that''s the only domain that can''t possibly have a virtual console. But I''m not really opposed to changing this. Jan
Jan Beulich
2012-Sep-11 07:36 UTC
Re: [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM hook exists
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- a/xen/common/grant_table.c > +++ b/xen/common/grant_table.c > @@ -195,30 +195,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); > -} > -Removing that function again is fine as long as you retain the distinguished error codes, which ...> static inline int > __get_maptrack_handle( > struct grant_table *t) > @@ -1304,11 +1280,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;... you don''t.> --- 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;And quite similarly here and further down you''re losing -EPERM. Jan
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- a/xen/common/tmem.c > +++ b/xen/common/tmem.c > @@ -23,6 +23,7 @@ > #include <xen/radix-tree.h> > #include <xen/list.h> > #include <xen/init.h> > +#include <xsm/xsm.h> > > #define EXPORT /* indicates code other modules are dependent upon */ > #define FORWARD > @@ -2540,11 +2541,10 @@ static NOINLINE int do_tmem_control(struct tmem_op *op) > uint32_t subop = op->u.ctrl.subop; > OID *oidp = (OID *)(&op->u.ctrl.oid[0]); > > - if (!tmh_current_is_privileged()) > - { > - /* don''t fail... mystery: sometimes dom0 fails here */ > - /* return -EPERM; */ > - } > + ret = xsm_tmem_control(subop); > + if ( ret ) > + return ret; > +This shouldn''t be placed here literally, but rather be moved into the tmh_current_is_privileged() - the file here is, afaict, intended to not have Xen-specific code (except for the inclusion of tmem_xen.h, so the comment also applies to the inclusion of xsm/xsm.h above). Plus it probably ought to go on top of the pending tmem patch series. Jan
Jan Beulich
2012-Sep-11 07:44 UTC
Re: [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- a/xen/include/xsm/xsm.h > +++ b/xen/include/xsm/xsm.h > @@ -21,11 +21,7 @@ > 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 > +#define xsm_call(fn) xsm_ops->fnSo am I getting it right that with XSM disabled this now adds an indirect call in almost every hypercall? I''m not really in favor of that, particularly not if that affects hot path ones like the MMU operations. Jan
Jan Beulich
2012-Sep-11 07:55 UTC
Re: [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- a/xen/arch/x86/mm.c > +++ b/xen/arch/x86/mm.c > @@ -2882,11 +2882,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: > @@ -2895,12 +2890,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; > } > > @@ -3008,6 +2997,13 @@ long do_mmuext_op( > goto out; > } > > + rc = xsm_mmuext_op(d, pg_owner); > + if ( rc ) > + { > + rcu_unlock_domain(pg_owner); > + goto out; > + } > +While this part is fine, ...> for ( i = 0; i < count; i++ ) > { > if ( hypercall_preempt_check() ) > @@ -3483,11 +3479,6 @@ long do_mmu_update( > rc = -EINVAL; > goto out; > } > - if ( !IS_PRIV_FOR(d, pt_owner) ) > - { > - rc = -ESRCH; > - goto out; > - }... this one isn''t (at least in conjunction with them all becoming indirect calls unconditionally) - you replace a single validation per set of requests with one validation per request. Jan
Jan Beulich
2012-Sep-11 07:59 UTC
Re: [PATCH 19/20] xen: remove rcu_lock_{remote_, }target_domain_by_id
>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > --- a/xen/arch/x86/physdev.c > +++ b/xen/arch/x86/physdev.c > @@ -106,9 +106,11 @@ int physdev_map_pirq(domid_t domid, int type, int > *index, int *pirq_p, > return physdev_hvm_map_pirq(d, type, index, pirq_p); > } > > - ret = rcu_lock_target_domain_by_id(domid, &d); > - if ( ret ) > - return ret; > + d = rcu_lock_domain_by_any_id(domid); > + if ( d == NULL ) > + return -ESRCH; > + if ( d != current->domain && !IS_PRIV_FOR(current->domain, d) ) > + return -EPERM;Wasn''t one of the goal of the series the _removal_ of the explicit IS_PRIV()/IS_PRIV_FOR() checks? Jan
>>> On 10.09.12 at 23:10, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/10/2012 04:51 PM, Keir Fraser wrote: >> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >> >>> Overall, this series should not change the behavior of Xen when XSM is >>> not enabled; however, in some cases, the exact errors that are returned >>> will be different because security checks have been moved below validity >>> checks. Also, once applied, newly introduced domctls and sysctls will >>> not automatically be guarded by IS_PRIV checks - they will need to add >>> their own permission checking code. >> >> How do we guard against accidentally forgetting to do this? > > The same way you guard against it when adding a new hypercall: when adding > new functionality that needs access checks, also add the access checks.Except that previously the access check was done centrally at the top of do_domctl(), so newly added sub-functions didn''t need to worry. Jan
On Mon, 2012-09-10 at 22:35 +0100, Keir Fraser wrote:> On 10/09/2012 22:10, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: > > > On 09/10/2012 04:51 PM, Keir Fraser wrote: > >> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: > >> > >>> Overall, this series should not change the behavior of Xen when XSM is > >>> not enabled; however, in some cases, the exact errors that are returned > >>> will be different because security checks have been moved below validity > >>> checks. Also, once applied, newly introduced domctls and sysctls will > >>> not automatically be guarded by IS_PRIV checks - they will need to add > >>> their own permission checking code. > >> > >> How do we guard against accidentally forgetting to do this? > > > > The same way you guard against it when adding a new hypercall: when adding > > new functionality that needs access checks, also add the access checks. > > So... We just shouldn''t accidentally forget. That will work well. ;) > Historically XSM has not been top of many committers'' checklists.Can we play tricks like int did_priv_check; switch(op) case FOO: if (xsm_check_foo(&did_priv_check)) .... break; } ASSERT(did_priv_check) I''d expect the compiler to catch missing checks due to the use of the uninitialised var, although that relies somewhat on the switch not being too big and confusing it. The other option might be to define domctl_do_perm_check, which has a similar switch over op but an explicit default: return -EPERM. Then call that from the top of do_domctl instead of scattering the priv checks throughout the main switch statement? That way if you forget to add the perm check it simply won''t work and you''ll see that the first time you try and test it... Or an array of do_perm_check function pointers of NR_DOMCTL in size and a NULL check? The differing prototypes probably make this one a non-starter without loads of per op helper functions. Ian.> -- Keir > > >>> The ARM architecture is not touched at all in these patches. The only > >>> obvious breakage that I can see is due to rcu_lock_target_domain_by_id > >>> being removed, but XSM hooks will be needed for domctls and sysctls. > >> > >> So ARM build is broken? And/or ARM is made insecure because of unchecked > >> sysctls/domctls? > >> > >> -- Keir > > > > The ARM build is broken by patch #19 in this series; fixing it is fairly > > simple (I''ll send a non-compile-tested version as 21/20), or you could > > postpone that patch as it''s just cleanup. > > > > Since ARM doesn''t have any arch-specific domctls or sysctls yet, they are > > not insecure. You could also add an IS_PRIV check at the top of ARM''s > > arch_do_{dom,sys}ctl functions if you don''t want to add XSM hooks for each > > operation as in x86. > > > >> > >>> The rcu_lock_target_domain_by_id and rcu_lock_remote_target_domain_by_id > >>> functions are removed by this series because they act as wrappers around > >>> IS_PRIV_FOR; their callers have been changed to use XSM checks instead. > >>> > >>> Miscellaneous updates to FLASK: > >>> [PATCH 01/20] xsm/flask: remove inherited class attributes > >>> [PATCH 02/20] xsm/flask: remove unneeded create_sid field > >>> [PATCH 03/20] xen: Add versions of rcu_lock_*_domain without IS_PRIV > >>> [PATCH 04/20] xsm/flask: add domain relabel support > >>> [PATCH 05/20] libxl: introduce XSM relabel on build > >>> [PATCH 06/20] flask/policy: Add domain relabel example > >>> > >>> Preparatory new hooks: > >>> [PATCH 07/20] arch/x86: add distinct XSM hooks for map/unmap > >>> [PATCH 08/20] arch/x86: add missing XSM checks to XENPF_ commands > >>> [PATCH 09/20] xsm/flask: Add checks on the domain performing the > >>> > >>> Refactoring: > >>> [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module > >>> [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated > >>> [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM > >>> > >>> Remaining IS_PRIV calls: > >>> [PATCH 13/20] arch/x86: Add missing domctl and mem_sharing XSM hooks > >>> [PATCH 14/20] tmem: Add access control check > >>> [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks > >>> [PATCH 18/20] xen: Add XSM hook for XENMEM_exchange > >>> > >>> Cleanup, FLASK updates to support IS_PRIV emulation: > >>> [PATCH 15/20] xsm: remove unneeded xsm_call macro > >>> [PATCH 16/20] xsm/flask: add distinct SIDs for self/target access > >>> [PATCH 19/20] xen: remove rcu_lock_{remote_,}target_domain_by_id > >>> [PATCH 20/20] flask: add missing operations > >>> > > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Ian Campbell
2012-Sep-11 09:05 UTC
Re: [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated
On Tue, 2012-09-11 at 08:29 +0100, Jan Beulich wrote:> > * do_console_io has changed to IS_PRIV from an explicit domid==0 > > I see a point in actually limiting this to Dom0 - that''s the only > domain that can''t possibly have a virtual console. But I''m not > really opposed to changing this.On a debug and/or verbose build of the hypervisor any domain can log here, and pvops Linux with earlyprintk=xen and/or xen_raw_printk will do so - it''s quite useful for debugging early start of day issues in guest kernels. Although I suppose we can always comment out the check locally when doing such debugging. It occurs to me now that perhaps this should be handled more like the HVM port e9 stuff (i.e. with rate limiting etc) anyway. Ian.
On 09/11/2012 04:09 AM, Jan Beulich wrote:>>>> On 10.09.12 at 23:10, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> On 09/10/2012 04:51 PM, Keir Fraser wrote: >>> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >>> >>>> Overall, this series should not change the behavior of Xen when XSM is >>>> not enabled; however, in some cases, the exact errors that are returned >>>> will be different because security checks have been moved below validity >>>> checks. Also, once applied, newly introduced domctls and sysctls will >>>> not automatically be guarded by IS_PRIV checks - they will need to add >>>> their own permission checking code. >>> >>> How do we guard against accidentally forgetting to do this? >> >> The same way you guard against it when adding a new hypercall: when adding >> new functionality that needs access checks, also add the access checks. > > Except that previously the access check was done centrally at the > top of do_domctl(), so newly added sub-functions didn''t need to > worry. > > Jan >One addition I am considering is an extra XSM hook at the start of do_domctl and do_sysctl that takes only the command (and domain, for domctl); this could be used to restrict access to unknown domctl/sysctls, and would fix the issues of adding sub-functions without access checks. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-11 13:24 UTC
Re: [PATCH 10/20] xsm: Add IS_PRIV checks to dummy XSM module
On 09/11/2012 03:44 AM, Jan Beulich wrote:>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> --- a/xen/include/xsm/xsm.h >> +++ b/xen/include/xsm/xsm.h >> @@ -21,11 +21,7 @@ >> 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 >> +#define xsm_call(fn) xsm_ops->fn > > So am I getting it right that with XSM disabled this now adds an > indirect call in almost every hypercall? I''m not really in favor of > that, particularly not if that affects hot path ones like the MMU > operations. > > Jan >No. With XSM disabled, this part of the header file is not used; instead, xsm/dummy.h is included with XSM_DEFAULT set up to generate inline functions. So there should be no slowdown if XSM is disabled. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-11 13:26 UTC
Re: [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM hook exists
On 09/11/2012 03:36 AM, Jan Beulich wrote:>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> --- a/xen/common/grant_table.c >> +++ b/xen/common/grant_table.c >> @@ -195,30 +195,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); >> -} >> - > > Removing that function again is fine as long as you retain the > distinguished error codes, which ... > >> static inline int >> __get_maptrack_handle( >> struct grant_table *t) >> @@ -1304,11 +1280,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; > > ... you don''t.Actually, I do. The only distinguishing error code here is GNTST_permission_denied, which is now only triggered by the XSM hook.>> --- 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; > > And quite similarly here and further down you''re losing -EPERM. > > Jan >Same logic: rcu_lock_domain_by_any_id will succeed where -EPERM was returned by rcu_lock_target_domain_by_id; the check is moved to the XSM hook. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-11 13:33 UTC
Re: [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated
On 09/11/2012 05:05 AM, Ian Campbell wrote:> On Tue, 2012-09-11 at 08:29 +0100, Jan Beulich wrote: >>> * do_console_io has changed to IS_PRIV from an explicit domid==0 >> >> I see a point in actually limiting this to Dom0 - that''s the only >> domain that can''t possibly have a virtual console. But I''m not >> really opposed to changing this. > > On a debug and/or verbose build of the hypervisor any domain can log > here, and pvops Linux with earlyprintk=xen and/or xen_raw_printk will do > so - it''s quite useful for debugging early start of day issues in guest > kernels. Although I suppose we can always comment out the check locally > when doing such debugging.I did keep the #ifdef VERBOSE around that IS_PRIV check, although it''s not noted in the commit message. I also take advantage of earlyprintk=xen for debugging and for minios output.> It occurs to me now that perhaps this should be handled more like the > HVM port e9 stuff (i.e. with rate limiting etc) anyway. > > Ian. >I also have a patch for debugging that prepends "(domid) " to the console output to help sorting out the serial log output when many domains are using it (which is quite helpful during bootup). Combined with rate limiting, this should make domU serial output useful in production builds. -- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-11 13:33 UTC
[PATCH] xen/console: Add domain ID to output if VERBOSE
When compiling with VERBOSE, any domain can output to the serial console; add a domain ID prefix similar to the (XEN) prefix used by the hypervisor to make it possible to distinguish the source of each message. This is especially useful for debugging stub domains. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> --- xen/drivers/char/console.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index e10bed5..ccef303 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -324,6 +324,10 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count) { char kbuf[128], *kptr; int kcount; +#ifdef VERBOSE + static domid_t active = DOMID_IDLE; + char pbuf[10]; +#endif while ( count > 0 ) { @@ -339,6 +343,18 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count) spin_lock_irq(&console_lock); +#ifdef VERBOSE + snprintf(pbuf, sizeof(pbuf), "(%d) ", current->domain->domain_id); + if (active != current->domain->domain_id) { + sercon_puts(pbuf); + vga_puts(pbuf); + + active = current->domain->domain_id; + } + if (strchr(kbuf, ''\n'')) + active = DOMID_IDLE; +#endif + sercon_puts(kbuf); vga_puts(kbuf); -- 1.7.11.4
Daniel De Graaf
2012-Sep-11 13:40 UTC
Re: [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
On 09/11/2012 03:55 AM, Jan Beulich wrote:>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> --- a/xen/arch/x86/mm.c >> +++ b/xen/arch/x86/mm.c >> @@ -2882,11 +2882,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: >> @@ -2895,12 +2890,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; >> } >> >> @@ -3008,6 +2997,13 @@ long do_mmuext_op( >> goto out; >> } >> >> + rc = xsm_mmuext_op(d, pg_owner); >> + if ( rc ) >> + { >> + rcu_unlock_domain(pg_owner); >> + goto out; >> + } >> + > > While this part is fine, ... > >> for ( i = 0; i < count; i++ ) >> { >> if ( hypercall_preempt_check() ) >> @@ -3483,11 +3479,6 @@ long do_mmu_update( >> rc = -EINVAL; >> goto out; >> } >> - if ( !IS_PRIV_FOR(d, pt_owner) ) >> - { >> - rc = -ESRCH; >> - goto out; >> - } > > ... this one isn''t (at least in conjunction with them all becoming > indirect calls unconditionally) - you replace a single validation per > set of requests with one validation per request. > > Jan > >Is it still a problem if the check is inlined? If so, I could add an additional XSM hook where the old IS_PRIV check was done, and make the check inside the loop an inlined noop in the XSM-disabled case. -- Daniel De Graaf National Security Agency
On 09/11/2012 04:54 AM, Ian Campbell wrote:> On Mon, 2012-09-10 at 22:35 +0100, Keir Fraser wrote: >> On 10/09/2012 22:10, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >> >>> On 09/10/2012 04:51 PM, Keir Fraser wrote: >>>> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >>>> >>>>> Overall, this series should not change the behavior of Xen when XSM is >>>>> not enabled; however, in some cases, the exact errors that are returned >>>>> will be different because security checks have been moved below validity >>>>> checks. Also, once applied, newly introduced domctls and sysctls will >>>>> not automatically be guarded by IS_PRIV checks - they will need to add >>>>> their own permission checking code. >>>> >>>> How do we guard against accidentally forgetting to do this? >>> >>> The same way you guard against it when adding a new hypercall: when adding >>> new functionality that needs access checks, also add the access checks. >> >> So... We just shouldn''t accidentally forget. That will work well. ;) >> Historically XSM has not been top of many committers'' checklists. > > Can we play tricks like > > int did_priv_check; > > switch(op) > case FOO: > if (xsm_check_foo(&did_priv_check)) > .... > break; > } > ASSERT(did_priv_check) > > I''d expect the compiler to catch missing checks due to the use of the > uninitialised var, although that relies somewhat on the switch not being > too big and confusing it.This is almost certainly going to confuse the compiler, since often the XSM hook is after some minimal parameter validation which will break on failure. Using an initialized variable would work, but I like the other option better.> The other option might be to define domctl_do_perm_check, which has a > similar switch over op but an explicit default: return -EPERM. Then call > that from the top of do_domctl instead of scattering the priv checks > throughout the main switch statement? That way if you forget to add the > perm check it simply won''t work and you''ll see that the first time you > try and test it...Or even just default back to IS_PRIV, and a FLASK unknown_domctl permission that is documented as only for development (or just -EPERM in FLASK, since most developers who would turn that on would also be interested in adding the full XSM hook).> Or an array of do_perm_check function pointers of NR_DOMCTL in size and > a NULL check? The differing prototypes probably make this one a > non-starter without loads of per op helper functions. > > Ian.-- Daniel De Graaf National Security Agency
Daniel De Graaf
2012-Sep-11 14:10 UTC
Re: [PATCH 11/20] xen: use XSM instead of IS_PRIV where duplicated
On 09/11/2012 03:29 AM, Jan Beulich wrote:>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> Some checks are removed due to non-obvious duplicates in their callers: >> >> * acpi_enter_sleep is checked by its only caller >> * map_domain_pirq has IS_PRIV_FOR checked in physdev_map_pirq > > ... and ioapic_guest_write(). Please have this list complete, as it > is going to be necessary to fully validate this (now and > retrospectively once applied) for the absence of security holes.I''ll check callers again when resubmitting; I didn''t generate this list the first time I was doing the checks, so it has obviously missed a few. The ioapic_guest_write function is checked by PHYSDEVOP_apic_write, so it''s also protected.> >> * PHYSDEVOP_alloc_irq_vector is a noop, does not need IS_PRIV > > NAK. This nevertheless is a privileged operation (i.e. must not > succeed for unprivileged guests).Do we depend on this behavior? Anyway, I''ll revert this chunk or replace it with an xsm hook if there''s an appropriate one.>> * Many PHYSDEVOP access checks are within the implementation functions > > For the above named reason, please fully document this. >Will do on resubmit. [snip remainder, addressed in the thread with Ian''s reply]
>>> On 11.09.12 at 15:21, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/11/2012 04:09 AM, Jan Beulich wrote: >>>>> On 10.09.12 at 23:10, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> On 09/10/2012 04:51 PM, Keir Fraser wrote: >>>> On 10/09/2012 20:48, "Daniel De Graaf" <dgdegra@tycho.nsa.gov> wrote: >>>> >>>>> Overall, this series should not change the behavior of Xen when XSM is >>>>> not enabled; however, in some cases, the exact errors that are returned >>>>> will be different because security checks have been moved below validity >>>>> checks. Also, once applied, newly introduced domctls and sysctls will >>>>> not automatically be guarded by IS_PRIV checks - they will need to add >>>>> their own permission checking code. >>>> >>>> How do we guard against accidentally forgetting to do this? >>> >>> The same way you guard against it when adding a new hypercall: when adding >>> new functionality that needs access checks, also add the access checks. >> >> Except that previously the access check was done centrally at the >> top of do_domctl(), so newly added sub-functions didn''t need to >> worry. > > One addition I am considering is an extra XSM hook at the start of do_domctl > and do_sysctl that takes only the command (and domain, for domctl); this > could be used to restrict access to unknown domctl/sysctls, and would fix > the issues of adding sub-functions without access checks.That sounds reasonable, the more that the performance aspect of these additions doesn''t matter for these two hypercalls. Jan
Jan Beulich
2012-Sep-11 14:15 UTC
Re: [PATCH 12/20] xen: avoid calling rcu_lock_*target_domain when an XSM hook exists
>>> On 11.09.12 at 15:26, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/11/2012 03:36 AM, Jan Beulich wrote: >>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> --- a/xen/common/grant_table.c >>> +++ b/xen/common/grant_table.c >>> @@ -195,30 +195,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); >>> -} >>> - >> >> Removing that function again is fine as long as you retain the >> distinguished error codes, which ... >> >>> static inline int >>> __get_maptrack_handle( >>> struct grant_table *t) >>> @@ -1304,11 +1280,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; >> >> ... you don''t. > > Actually, I do. The only distinguishing error code here is > GNTST_permission_denied, which is now only triggered by the XSM > hook.Ah, okay, that wasn''t visible from the patch context (and the sum of the patches was too large to track all the details mentally). Sorry for the noise then. Jan
Jan Beulich
2012-Sep-11 14:16 UTC
Re: [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
>>> On 11.09.12 at 15:40, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/11/2012 03:55 AM, Jan Beulich wrote: >>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> --- a/xen/arch/x86/mm.c >>> +++ b/xen/arch/x86/mm.c >>> @@ -2882,11 +2882,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: >>> @@ -2895,12 +2890,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; >>> } >>> >>> @@ -3008,6 +2997,13 @@ long do_mmuext_op( >>> goto out; >>> } >>> >>> + rc = xsm_mmuext_op(d, pg_owner); >>> + if ( rc ) >>> + { >>> + rcu_unlock_domain(pg_owner); >>> + goto out; >>> + } >>> + >> >> While this part is fine, ... >> >>> for ( i = 0; i < count; i++ ) >>> { >>> if ( hypercall_preempt_check() ) >>> @@ -3483,11 +3479,6 @@ long do_mmu_update( >>> rc = -EINVAL; >>> goto out; >>> } >>> - if ( !IS_PRIV_FOR(d, pt_owner) ) >>> - { >>> - rc = -ESRCH; >>> - goto out; >>> - } >> >> ... this one isn''t (at least in conjunction with them all becoming >> indirect calls unconditionally) - you replace a single validation per >> set of requests with one validation per request. > > Is it still a problem if the check is inlined? If so, I could add an > additional XSM hook where the old IS_PRIV check was done, and make the > check inside the loop an inlined noop in the XSM-disabled case.It''s not a problem for the inlined case I would say, but I do think that performance here matters even if XSM is enabled. Jan
Jan Beulich
2012-Sep-11 14:23 UTC
Re: [PATCH] xen/console: Add domain ID to output if VERBOSE
>>> On 11.09.12 at 15:33, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > @@ -339,6 +343,18 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) > buffer, int count) > > spin_lock_irq(&console_lock); > > +#ifdef VERBOSE > + snprintf(pbuf, sizeof(pbuf), "(%d) ", current->domain->domain_id); > + if (active != current->domain->domain_id) { > + sercon_puts(pbuf); > + vga_puts(pbuf); > + > + active = current->domain->domain_id; > + } > + if (strchr(kbuf, ''\n'')) > + active = DOMID_IDLE; > +#endifThis is too simplistic - you ought to be dealing with embedded ''\n'', not just trailing ones. Jan> + > sercon_puts(kbuf); > vga_puts(kbuf); > > -- > 1.7.11.4
Ian Campbell
2012-Sep-11 14:26 UTC
Re: [PATCH] xen/console: Add domain ID to output if VERBOSE
On Tue, 2012-09-11 at 15:23 +0100, Jan Beulich wrote:> >>> On 11.09.12 at 15:33, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > > @@ -339,6 +343,18 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) > > buffer, int count) > > > > spin_lock_irq(&console_lock); > > > > +#ifdef VERBOSE > > + snprintf(pbuf, sizeof(pbuf), "(%d) ", current->domain->domain_id); > > + if (active != current->domain->domain_id) { > > + sercon_puts(pbuf); > > + vga_puts(pbuf); > > + > > + active = current->domain->domain_id; > > + } > > + if (strchr(kbuf, ''\n'')) > > + active = DOMID_IDLE; > > +#endif > > This is too simplistic - you ought to be dealing with embedded ''\n'', > not just trailing ones.hvm_print_line should perhaps become more generic? Ian.
Daniel De Graaf
2012-Sep-11 14:33 UTC
Re: [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
On 09/11/2012 10:16 AM, Jan Beulich wrote:>>>> On 11.09.12 at 15:40, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >> On 09/11/2012 03:55 AM, Jan Beulich wrote: >>>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>> --- a/xen/arch/x86/mm.c >>>> +++ b/xen/arch/x86/mm.c >>>> @@ -2882,11 +2882,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: >>>> @@ -2895,12 +2890,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; >>>> } >>>> >>>> @@ -3008,6 +2997,13 @@ long do_mmuext_op( >>>> goto out; >>>> } >>>> >>>> + rc = xsm_mmuext_op(d, pg_owner); >>>> + if ( rc ) >>>> + { >>>> + rcu_unlock_domain(pg_owner); >>>> + goto out; >>>> + } >>>> + >>> >>> While this part is fine, ... >>> >>>> for ( i = 0; i < count; i++ ) >>>> { >>>> if ( hypercall_preempt_check() ) >>>> @@ -3483,11 +3479,6 @@ long do_mmu_update( >>>> rc = -EINVAL; >>>> goto out; >>>> } >>>> - if ( !IS_PRIV_FOR(d, pt_owner) ) >>>> - { >>>> - rc = -ESRCH; >>>> - goto out; >>>> - } >>> >>> ... this one isn''t (at least in conjunction with them all becoming >>> indirect calls unconditionally) - you replace a single validation per >>> set of requests with one validation per request. >> >> Is it still a problem if the check is inlined? If so, I could add an >> additional XSM hook where the old IS_PRIV check was done, and make the >> check inside the loop an inlined noop in the XSM-disabled case. > > It''s not a problem for the inlined case I would say, but I do > think that performance here matters even if XSM is enabled. > > Jan >That''s a problem that should probably be addressed in a different patch, since the current XSM hook is already implemented as one per request. This is because it needs access to the page being mapped in order to check for MMIO mappings. Since those are not the normal case, I think this could be improved using a lazier hook - or by dropping the per-request XSM check, because I think it might be re-implementing the existing mmio rangeset checks, and should just rely on those. -- Daniel De Graaf National Security Agency
Jan Beulich
2012-Sep-11 14:50 UTC
Re: [PATCH 17/20] arch/x86: use XSM hooks for get_pg_owner access checks
>>> On 11.09.12 at 16:33, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: > On 09/11/2012 10:16 AM, Jan Beulich wrote: >>>>> On 11.09.12 at 15:40, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>> On 09/11/2012 03:55 AM, Jan Beulich wrote: >>>>>>> On 10.09.12 at 21:49, Daniel De Graaf <dgdegra@tycho.nsa.gov> wrote: >>>>> --- a/xen/arch/x86/mm.c >>>>> +++ b/xen/arch/x86/mm.c >>>>> @@ -2882,11 +2882,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: >>>>> @@ -2895,12 +2890,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; >>>>> } >>>>> >>>>> @@ -3008,6 +2997,13 @@ long do_mmuext_op( >>>>> goto out; >>>>> } >>>>> >>>>> + rc = xsm_mmuext_op(d, pg_owner); >>>>> + if ( rc ) >>>>> + { >>>>> + rcu_unlock_domain(pg_owner); >>>>> + goto out; >>>>> + } >>>>> + >>>> >>>> While this part is fine, ... >>>> >>>>> for ( i = 0; i < count; i++ ) >>>>> { >>>>> if ( hypercall_preempt_check() ) >>>>> @@ -3483,11 +3479,6 @@ long do_mmu_update( >>>>> rc = -EINVAL; >>>>> goto out; >>>>> } >>>>> - if ( !IS_PRIV_FOR(d, pt_owner) ) >>>>> - { >>>>> - rc = -ESRCH; >>>>> - goto out; >>>>> - } >>>> >>>> ... this one isn''t (at least in conjunction with them all becoming >>>> indirect calls unconditionally) - you replace a single validation per >>>> set of requests with one validation per request. >>> >>> Is it still a problem if the check is inlined? If so, I could add an >>> additional XSM hook where the old IS_PRIV check was done, and make the >>> check inside the loop an inlined noop in the XSM-disabled case. >> >> It''s not a problem for the inlined case I would say, but I do >> think that performance here matters even if XSM is enabled. > > That''s a problem that should probably be addressed in a different patch, > since the current XSM hook is already implemented as one per request.That''s true for the pin-page case in do_mmuext_op(), but not for any other of its sub-ops (particularly not for the TLB flushing ones, for which I can''t even see how XSM denying the operation could be useful in any way, the more that presently foreigndom/pg_owner is being ignored for many of these, i.e. they act locally even if an otherwise valid foreign domain was specified).> This is because it needs access to the page being mapped in order to check > for MMIO mappings. Since those are not the normal case, I think this could > be improved using a lazier hook - or by dropping the per-request XSM check, > because I think it might be re-implementing the existing mmio rangeset > checks, and should just rely on those.Indeed - if the per-request check makes no sense, then dropping that one would be the preferred route over the one you took here. Same for do_mmu_update(). Jan