mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
Converts the Config.mk option of FLASK_ENABLE into a Kconfig option for the hypervisor called CONFIG_FLASK. This commit knowingly breaks the dependent relationship on XSM_ENABLE which is addressed when XSM_ENABLE is converted to Kconfig. Signed-off-by: Doug Goldstein <cardoe@cardoe.com> Acked-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
375 lines
16 KiB
Plaintext
375 lines
16 KiB
Plaintext
-----------------------
|
|
XSM/FLASK Configuration
|
|
-----------------------
|
|
|
|
Xen provides a security framework called XSM, and FLASK is an implementation of
|
|
a security model using this framework (at the time of writing, it is the only
|
|
one). FLASK defines a mandatory access control policy providing fine-grained
|
|
controls over Xen domains, allowing the policy writer to define what
|
|
interactions between domains, devices, and the hypervisor are permitted.
|
|
|
|
Some examples of what FLASK can do:
|
|
- Prevent two domains from communicating via event channels or grants
|
|
- Control which domains can use device passthrough (and which devices)
|
|
- Restrict or audit operations performed by privileged domains
|
|
- Prevent a privileged domain from arbitrarily mapping pages from other domains
|
|
|
|
Some of these examples require dom0 disaggregation to be useful, since the
|
|
domain build process requires the ability to write to the new domain's memory.
|
|
|
|
Security Status of dom0 disaggregation
|
|
--------------------------------------
|
|
|
|
Xen supports disaggregation of various support and management
|
|
functions into their own domains, via the XSM mechanisms described in
|
|
this document.
|
|
|
|
However the implementations of these support and management interfaces
|
|
were originally written to be used only by the totally-privileged
|
|
dom0, and have not been reviewed for security when exposed to
|
|
supposedly-only-semi-privileged disaggregated management domains. But
|
|
such management domains are (in such a design) to be seen as
|
|
potentially hostile, e.g. due to privilege escalation following
|
|
exploitation of a bug in the management domain.
|
|
|
|
Until the interfaces have been properly reviewed for security against
|
|
hostile callers, the Xen.org security team intends (subject of course
|
|
to the permission of anyone disclosing to us) to handle these and
|
|
future vulnerabilities in these interfaces in public, as if they were
|
|
normal non-security-related bugs.
|
|
|
|
This applies only to bugs which do no more than reduce the security of
|
|
a radically disaggregated system to the security of a
|
|
non-disaggregated one. Here a "radically disaggregated system" is one
|
|
which uses the XSM mechanism to delegate the affected interfaces to
|
|
other-than-fully-trusted domains.
|
|
|
|
This policy does not apply to bugs which affect stub device models,
|
|
driver domains, or stub xenstored - even if those bugs do no worse
|
|
than reduce the security of such a system to one whose device models,
|
|
backend drivers, or xenstore, run in dom0.
|
|
|
|
For more information see http://xenbits.xen.org/xsa/advisory-77.html.
|
|
|
|
The following interfaces are covered by this statement. Interfaces
|
|
not listed here are considered safe for disaggregation, security
|
|
issues found in interfaces not listed here will be handled according
|
|
to the normal security problem response policy
|
|
http://www.xenproject.org/security-policy.html.
|
|
|
|
__HYPERVISOR_domctl (xen/include/public/domctl.h)
|
|
|
|
The following subops are covered by this statement. subops not listed
|
|
here are considered safe for disaggregation.
|
|
|
|
* XEN_DOMCTL_createdomain
|
|
* XEN_DOMCTL_destroydomain
|
|
* XEN_DOMCTL_getmemlist
|
|
* XEN_DOMCTL_setvcpuaffinity
|
|
* XEN_DOMCTL_shadow_op
|
|
* XEN_DOMCTL_max_mem
|
|
* XEN_DOMCTL_setvcpucontext
|
|
* XEN_DOMCTL_getvcpucontext
|
|
* XEN_DOMCTL_max_vcpus
|
|
* XEN_DOMCTL_scheduler_op
|
|
* XEN_DOMCTL_iomem_permission
|
|
* XEN_DOMCTL_gethvmcontext
|
|
* XEN_DOMCTL_sethvmcontext
|
|
* XEN_DOMCTL_set_address_size
|
|
* XEN_DOMCTL_assign_device
|
|
* XEN_DOMCTL_pin_mem_cacheattr
|
|
* XEN_DOMCTL_set_ext_vcpucontext
|
|
* XEN_DOMCTL_get_ext_vcpucontext
|
|
* XEN_DOMCTL_test_assign_device
|
|
* XEN_DOMCTL_set_target
|
|
* XEN_DOMCTL_deassign_device
|
|
* XEN_DOMCTL_get_device_group
|
|
* XEN_DOMCTL_set_machine_address_size
|
|
* XEN_DOMCTL_debug_op
|
|
* XEN_DOMCTL_gethvmcontext_partial
|
|
* XEN_DOMCTL_vm_event_op
|
|
* XEN_DOMCTL_mem_sharing_op
|
|
* XEN_DOMCTL_setvcpuextstate
|
|
* XEN_DOMCTL_getvcpuextstate
|
|
* XEN_DOMCTL_set_access_required
|
|
* XEN_DOMCTL_set_virq_handler
|
|
* XEN_DOMCTL_set_broken_page_p2m
|
|
* XEN_DOMCTL_setnodeaffinity
|
|
* XEN_DOMCTL_gdbsx_guestmemio
|
|
|
|
__HYPERVISOR_sysctl (xen/include/public/sysctl.h)
|
|
|
|
The following subops are covered by this statement. subops not listed
|
|
here are considered safe for disaggregation.
|
|
|
|
* XEN_SYSCTL_readconsole
|
|
* XEN_SYSCTL_tbuf_op
|
|
* XEN_SYSCTL_physinfo
|
|
* XEN_SYSCTL_sched_id
|
|
* XEN_SYSCTL_perfc_op
|
|
* XEN_SYSCTL_getdomaininfolist
|
|
* XEN_SYSCTL_debug_keys
|
|
* XEN_SYSCTL_getcpuinfo
|
|
* XEN_SYSCTL_availheap
|
|
* XEN_SYSCTL_get_pmstat
|
|
* XEN_SYSCTL_cpu_hotplug
|
|
* XEN_SYSCTL_pm_op
|
|
* XEN_SYSCTL_page_offline_op
|
|
* XEN_SYSCTL_lockprof_op
|
|
* XEN_SYSCTL_cputopoinfo
|
|
* XEN_SYSCTL_numainfo
|
|
* XEN_SYSCTL_cpupool_op
|
|
* XEN_SYSCTL_scheduler_op
|
|
* XEN_SYSCTL_coverage_op
|
|
|
|
__HYPERVISOR_memory_op (xen/include/public/memory.h)
|
|
|
|
The following subops are covered by this statement. subops not listed
|
|
here are considered safe for disaggregation.
|
|
|
|
* XENMEM_set_pod_target
|
|
* XENMEM_get_pod_target
|
|
* XENMEM_claim_pages
|
|
|
|
__HYPERVISOR_tmem_op (xen/include/public/tmem.h)
|
|
|
|
The following tmem control ops, that is the sub-subops of
|
|
TMEM_CONTROL, are covered by this statement.
|
|
|
|
Note that TMEM is also subject to a similar policy arising from
|
|
XSA-15 http://lists.xen.org/archives/html/xen-announce/2012-09/msg00006.html.
|
|
Due to this existing policy all TMEM Ops are already subject to
|
|
reduced security support.
|
|
|
|
* TMEMC_THAW
|
|
* TMEMC_FREEZE
|
|
* TMEMC_FLUSH
|
|
* TMEMC_DESTROY
|
|
* TMEMC_LIST
|
|
* TMEMC_SET_WEIGHT
|
|
* TMEMC_SET_CAP
|
|
* TMEMC_SET_COMPRESS
|
|
* TMEMC_QUERY_FREEABLE_MB
|
|
* TMEMC_SAVE_BEGIN
|
|
* TMEMC_SAVE_GET_VERSION
|
|
* TMEMC_SAVE_GET_MAXPOOLS
|
|
* TMEMC_SAVE_GET_CLIENT_WEIGHT
|
|
* TMEMC_SAVE_GET_CLIENT_CAP
|
|
* TMEMC_SAVE_GET_CLIENT_FLAGS
|
|
* TMEMC_SAVE_GET_POOL_FLAGS
|
|
* TMEMC_SAVE_GET_POOL_NPAGES
|
|
* TMEMC_SAVE_GET_POOL_UUID
|
|
* TMEMC_SAVE_GET_NEXT_PAGE
|
|
* TMEMC_SAVE_GET_NEXT_INV
|
|
* TMEMC_SAVE_END
|
|
* TMEMC_RESTORE_BEGIN
|
|
* TMEMC_RESTORE_PUT_PAGE
|
|
* TMEMC_RESTORE_FLUSH_PAGE
|
|
|
|
|
|
|
|
Setting up FLASK
|
|
----------------
|
|
|
|
Xen must be compiled with XSM and FLASK enabled; by default, the security
|
|
framework is disabled. Edit Config.mk or the .config file to set XSM_ENABLE to
|
|
"y" and running 'make -C xen menuconfig' and enabling FLASK inside 'Common
|
|
Features'; this change requires a make clean and rebuild.
|
|
|
|
FLASK uses only one domain configuration parameter (seclabel) defining the
|
|
full security label of the newly created domain. If using the example policy,
|
|
"seclabel='system_u:system_r:domU_t'" is an example of a normal domain. The
|
|
labels are in the same format as SELinux labels; see http://selinuxproject.org
|
|
for more details on the use of the user, role, and optional MLS/MCS labels.
|
|
|
|
FLASK policy overview
|
|
---------------------
|
|
|
|
Most of FLASK policy consists of defining the interactions allowed between
|
|
different types (domU_t would be the type in this example). For simple policies,
|
|
only type enforcement is used and the user and role are set to system_u and
|
|
system_r for all domains.
|
|
|
|
The FLASK security framework is mostly configured using a security policy file.
|
|
This policy file is not normally generated during the Xen build process because
|
|
it relies on the SELinux compiler "checkpolicy"; run
|
|
|
|
make -C tools/flask/policy
|
|
|
|
to compile the example policy included with Xen. The policy is generated from
|
|
definition files under this directory. When creating or modifying security
|
|
policy, most modifications will be made to the xen type enforcement (.te) file
|
|
tools/flask/policy/policy/modules/xen/xen.te or the macro definitions in xen.if.
|
|
The XSM policy file needs to be copied to /boot and loaded as a module by grub.
|
|
The exact position of the module does not matter as long as it is after the Xen
|
|
kernel; it is normally placed either just above the dom0 kernel or at the end.
|
|
Once dom0 is running, the policy can be reloaded using "xl loadpolicy".
|
|
|
|
The example policy included with Xen demonstrates most of the features of FLASK
|
|
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 also need a type for the stub domain.
|
|
The example policy defines dm_dom_t for the device model of a domU_t domain;
|
|
there are no device model types defined for the other domU types.
|
|
|
|
One disadvantage of using type enforcement to enforce isolation is that a new
|
|
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
|
|
---------------
|
|
|
|
Users are defined in tools/flask/policy/policy/users. The example policy defines
|
|
two users (customer_1 and customer_2) in addition to the system user system_u.
|
|
Users are visible in the labels of domains and associated objects (event
|
|
channels); in the example policy, "customer_1:vm_r:domU_t" is a valid label for
|
|
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 the system_u
|
|
user where dom0 resides.
|
|
|
|
Resource Policy
|
|
---------------
|
|
|
|
The example policy also includes a resource type (nic_dev_t) for device
|
|
passthrough, configured to allow use by domU_t. To label the PCI device 3:2.0
|
|
for passthrough, run:
|
|
|
|
tools/flask/utils/flask-label-pci 0000:03:02.0 system_u:object_r:nic_dev_t
|
|
|
|
This command must be rerun on each boot or after any policy reload.
|
|
|
|
The example policy was only tested with simple domain creation and may be
|
|
missing rules allowing accesses by dom0 or domU when a number of hypervisor
|
|
features are used. When first loading or writing a policy, you should run FLASK
|
|
in permissive mode (the default) and check the Xen logs (xl dmesg) for AVC
|
|
denials before using it in enforcing mode (flask_enforcing=1 on the command
|
|
line, or xl setenforce).
|
|
|
|
|
|
MLS/MCS policy
|
|
--------------
|
|
|
|
If you want to use the MLS policy, then set TYPE=xen-mls in the policy Makefile
|
|
before building the policy. Note that the MLS constraints in policy/mls
|
|
are incomplete and are only a sample.
|
|
|
|
|
|
AVC denials
|
|
-----------
|
|
|
|
XSM:Flask will emit avc: denied messages when a permission is denied by the
|
|
policy, just like SELinux. For example, if the HVM rules are removed from the
|
|
declare_domain and create_domain interfaces:
|
|
|
|
# xl dmesg | grep avc
|
|
(XEN) avc: denied { setparam } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { getparam } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { irqlevel } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { pciroute } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { setparam } for domid=4 scontext=system_u:system_r:domU_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { cacheattr } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
(XEN) avc: denied { pcilevel } for domid=0 scontext=system_u:system_r:dom0_t tcontext=system_u:system_r:domU_t tclass=hvm
|
|
|
|
Existing SELinux tools such as audit2allow can be applied to these denials, e.g.
|
|
xl dmesg | audit2allow
|
|
|
|
The generated allow rules can then be fed back into the policy by
|
|
adding them to xen.te, although manual review is advised and will
|
|
often lead to adding parameterized rules to the interfaces in xen.if
|
|
to address the general case.
|
|
|
|
|
|
Device Labeling in Policy
|
|
-------------------------
|
|
|
|
FLASK is capable of labeling devices and enforcing policies associated with
|
|
them. There are two methods to label devices: dynamic labeling using
|
|
flask-label-pci or similar tools run in dom0, or static labeling defined in
|
|
policy. Static labeling will make security policy machine-specific and may
|
|
prevent the system from booting after any hardware changes (adding PCI cards,
|
|
memory, or even changing certain BIOS settings). Dynamic labeling requires that
|
|
the domain performing the labeling be trusted to label all the devices in the
|
|
system properly.
|
|
|
|
IRQs, PCI devices, I/O memory and x86 IO ports can all have labels defined.
|
|
There are examples commented out in tools/flask/policy/policy/device_contexts.
|
|
|
|
Device Labeling
|
|
---------------
|
|
|
|
The "lspci -vvn" command can be used to output all the devices and identifiers
|
|
associated with them. For example, to label an Intel e1000e ethernet card the
|
|
lspci output is..
|
|
|
|
00:19.0 0200: 8086:10de (rev 02)
|
|
Subsystem: 1028:0276
|
|
Interrupt: pin A routed to IRQ 33
|
|
Region 0: Memory at febe0000 (32-bit, non-prefetchable) [size=128K]
|
|
Region 1: Memory at febd9000 (32-bit, non-prefetchable) [size=4K]
|
|
Region 2: I/O ports at ecc0 [size=32]
|
|
Kernel modules: e1000e
|
|
|
|
The labeling can be done with these lines in device_contexts:
|
|
|
|
pirqcon 33 system_u:object_r:nicP_t
|
|
iomemcon 0xfebe0-0xfebff system_u:object_r:nicP_t
|
|
iomemcon 0xfebd9 system_u:object_r:nicP_t
|
|
ioportcon 0xecc0-0xecdf system_u:object_r:nicP_t
|
|
pcidevicecon 0xc800 system_u:object_r:nicP_t
|
|
|
|
The PCI device label must be computed as the 32-bit SBDF number for the PCI
|
|
device. It the PCI device is aaaa:bb:cc.d or bb:cc.d, then the SBDF can be
|
|
calculated using:
|
|
SBDF = (a << 16) | (b << 8) | (c << 3) | d
|
|
|
|
The AVC denials for IRQs, memory, ports, and PCI devices will normally contain
|
|
the ranges being denied to more easily determine what resources are required.
|
|
When running in permissive mode, only the first denial of a given
|
|
source/destination is printed to the log, so labeling devices using this method
|
|
may require multiple passes to find all required ranges.
|