Mailing List Archive

[PATCH v7] libxl: introduce XSM relabel on build
In response to a suggestion from Jan, I am splitting out independent
patches from the larger XSM series that I have been posting. This is
the only patch from that series that touches the toolstack; it is
independent of the rest of the series as the hypervisor component has
already been committed.

---------------------8<-------------------------------------------------

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.

Example domain configuration snippet:
seclabel='customer_1:vm_r:nomigrate_t'
init_seclabel='customer_1:vm_r:nomigrate_t_building'

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. However, if
dom0 correctly unmaps the domain upon building, a the domU is protected
against dom0 becoming malicious in the future.

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>
---
docs/man/xl.cfg.pod.5 | 9 +++++
docs/misc/xsm-flask.txt | 2 +
tools/flask/policy/policy/modules/xen/xen.if | 56 +++++++++++++++++++++-------
tools/flask/policy/policy/modules/xen/xen.te | 10 +++++
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 +++++++++-
9 files changed, 99 insertions(+), 14 deletions(-)

diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
index dc3f494..caba162 100644
--- a/docs/man/xl.cfg.pod.5
+++ b/docs/man/xl.cfg.pod.5
@@ -270,6 +270,15 @@ UUID will be generated.

Assign an XSM security label to this domain.

+=item B<init_seclabel="LABEL">
+
+Specify an XSM security label used for this domain temporarily during
+its build. The domain's XSM label will be changed to the execution
+seclabel (specified by "seclabel") once the build is complete, prior to
+unpausing the domain. With a properly constructed security policy (such
+as nomigrate_t in the example policy), this can be used to build a
+domain whose memory is not accessible to the toolstack domain.
+
=item B<nomigrate=BOOLEAN>

Disable migration of this domain. This enables certain other features
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
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 1cd13c1..32122fd 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -2169,6 +2169,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 9d20086..b183255 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1182,6 +1182,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 7eac4a8..93524f0 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -268,6 +268,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 4b75fc3..e964bf1 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -596,16 +596,34 @@ static void parse_config_data(const char *config_source,
exit(1);
}

- if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) {
+ if (!xlu_cfg_get_string (config, "init_seclabel", &buf, 0)) {
e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf),
&c_info->ssidref);
if (e) {
if (errno == ENOSYS) {
+ fprintf(stderr, "XSM Disabled: init_seclabel not supported\n");
+ } else {
+ fprintf(stderr, "Invalid init_seclabel: %s\n", buf);
+ exit(1);
+ }
+ }
+ }
+
+ if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) {
+ uint32_t ssidref;
+ e = libxl_flask_context_to_sid(ctx, (char *)buf, strlen(buf),
+ &ssidref);
+ if (e) {
+ if (errno == ENOSYS) {
fprintf(stderr, "XSM Disabled: seclabel not supported\n");
} else {
fprintf(stderr, "Invalid seclabel: %s\n", buf);
exit(1);
}
+ } else if (c_info->ssidref) {
+ b_info->exec_ssidref = ssidref;
+ } else {
+ c_info->ssidref = ssidref;
}
}

--
1.7.11.7


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
Re: [PATCH v7] libxl: introduce XSM relabel on build [ In reply to ]
On Wed, 2012-12-12 at 20:17 +0000, Daniel De Graaf wrote:
> In response to a suggestion from Jan, I am splitting out independent
> patches from the larger XSM series that I have been posting. This is
> the only patch from that series that touches the toolstack; it is
> independent of the rest of the series as the hypervisor component has
> already been committed.
>
> ---------------------8<-------------------------------------------------
>
> 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.
>
> Example domain configuration snippet:
> seclabel='customer_1:vm_r:nomigrate_t'
> init_seclabel='customer_1:vm_r:nomigrate_t_building'
>
> 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. However, if
> dom0 correctly unmaps the domain upon building, a the domU is protected
> against dom0 becoming malicious in the future.
>
> 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>

Acked + applied, thanks.

I'm in two minds about whether we should add a LIBXL_HAVE_<foo> #define.

Ian.



_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel