[libvirt] [RFC] sVirt v0.10 - initial prototype

This is a request for comments on the initial prototype release of sVirt, a project to add security labeling support to Linux-based virtualization. Project page: http://www.selinuxproject.org/page/SVirt Previous libvirt discussions: High-level requirements: https://www.redhat.com/archives/libvir-list/2008-August/msg00255.html XML security labels: https://www.redhat.com/archives/libvir-list/2008-August/msg00740.html A patch for libvirt is attached; and also included in a release tarball at http://namei.org/svirt/. See 'readme.txt' there for more details on building and running the code. The purpose of this release is to establish a proof of concept of applying security labels to VMs, and for discussion of the underlying technical approach. With this release, it is possible to define a security label for a kvm/qemu domain in its XML configuration ('virsh edit'), launch the domain and have it transition to the specified security label ('virsh start'), then query the security label of the running domain ('virsh dominfo'). The following changes were made to libvirt: 1. Implementing a pluggable security label driver framework; 2. Implementing an SELinux security label driver for (1); 3. Wiring the security label framework into the Qemu driver; 4. Implementing basic libvirt API calls for initializing the driver, and getting/setting domain security labels; 5. Extending the domain XML configuration to include security labels; 6. Adding domain security label display/edit/dump support to virsh. One of the design principles I've followed with this is to reduce or eliminate configuration wherever possible. If a variety of security labeling drivers are present, libvirtd automatically detects which one to enable and enables it. e.g. if SELinux is enabled on the system, the SELinux labeling driver is enabled automatically when livbirtd starts. Another is to treat security labels as opaque unless they're actually being used for security purposes (e.g. to launch the domain). So, virsh and the domain configuration code currently do not need to semantically interpet security labels, just understand their format. This should suit the initial simple goal of isolated domains, which only requires security labels to be distinct. The domain security label configuration format is as follows: # virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain> It's possible to query the security label of a running domain via virsh: # virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing) The security label is deterimed via the new virDomainGetSecLabel() API method, which is transported over RPC to the backend driver (qemu in this case), and is entirely independent of the local security model, if any. e.g. this command could be run remotely from an entirely different platform: you just see what's happening on the remote system, as with other attributes of the domain. Feedback on the design thus far is sought before proceeding to more comprehensive integration. In particular, I'd be interested in any thoughts on the placement of the security labeling driver within libvirt, as this seems to be the most critical architectural issue (I've already refactored this aspect once). Currently, the idea is to attach the security labeling driver to the virt driver, rather than implement it independently as a top-level component as in the case of other types of drivers (e.g. storage). This is because process-based security labeling is highly dependent on the kind of virtualization in use, and may not make sense at all in some cases (e.g. when using a non-Linux hypervisor, or containers). In the case of qemu, a security labeling driver is added to qemud: @@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen; virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; }; and then initialized during qemud startup from qemudSecLabelInit(). During initialization, any available security labeling drivers are probed, and the first one which thinks it should be used is installed. Top-level libvirt API calls are then dispatched to the active security labeling driver via the backend virt driver, as necessary. Note that the security labeling framework in this release is always built-in -- it can be made a compile-time option later if desired. Requirements not yet addressed include: - Labeling of resources and generally comprehensive labeling management - Automatic labeling (e.g. for the simple isolation use-case) - Integration of labeling support into higher-level management tools such as virt-manager - Integration with the audit subsystem to help with administration and debugging - Domain of interpretation (DOI) checking/translation - Python bindings As mentioned, the goal at this stage is to get feedback on the underlying design: comments welcome! - James -- James Morris <jmorris@namei.org>

James Morris wrote:
This is a request for comments on the initial prototype release of sVirt, a project to add security labeling support to Linux-based virtualization.
Project page: http://www.selinuxproject.org/page/SVirt
Previous libvirt discussions:
High-level requirements: https://www.redhat.com/archives/libvir-list/2008-August/msg00255.html
XML security labels: https://www.redhat.com/archives/libvir-list/2008-August/msg00740.html
A patch for libvirt is attached; and also included in a release tarball at http://namei.org/svirt/. See 'readme.txt' there for more details on building and running the code.
The purpose of this release is to establish a proof of concept of applying security labels to VMs, and for discussion of the underlying technical approach.
With this release, it is possible to define a security label for a kvm/qemu domain in its XML configuration ('virsh edit'), launch the domain and have it transition to the specified security label ('virsh start'), then query the security label of the running domain ('virsh dominfo').
The following changes were made to libvirt:
1. Implementing a pluggable security label driver framework;
2. Implementing an SELinux security label driver for (1);
3. Wiring the security label framework into the Qemu driver;
4. Implementing basic libvirt API calls for initializing the driver, and getting/setting domain security labels;
5. Extending the domain XML configuration to include security labels;
6. Adding domain security label display/edit/dump support to virsh.
One of the design principles I've followed with this is to reduce or eliminate configuration wherever possible. If a variety of security labeling drivers are present, libvirtd automatically detects which one to enable and enables it. e.g. if SELinux is enabled on the system, the SELinux labeling driver is enabled automatically when livbirtd starts.
Another is to treat security labels as opaque unless they're actually being used for security purposes (e.g. to launch the domain). So, virsh and the domain configuration code currently do not need to semantically interpet security labels, just understand their format. This should suit the initial simple goal of isolated domains, which only requires security labels to be distinct.
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
It's possible to query the security label of a running domain via virsh:
# virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing)
The security label is deterimed via the new virDomainGetSecLabel() API method, which is transported over RPC to the backend driver (qemu in this case), and is entirely independent of the local security model, if any. e.g. this command could be run remotely from an entirely different platform: you just see what's happening on the remote system, as with other attributes of the domain.
Feedback on the design thus far is sought before proceeding to more comprehensive integration.
In particular, I'd be interested in any thoughts on the placement of the security labeling driver within libvirt, as this seems to be the most critical architectural issue (I've already refactored this aspect once).
Currently, the idea is to attach the security labeling driver to the virt driver, rather than implement it independently as a top-level component as in the case of other types of drivers (e.g. storage). This is because process-based security labeling is highly dependent on the kind of virtualization in use, and may not make sense at all in some cases (e.g. when using a non-Linux hypervisor, or containers).
In the case of qemu, a security labeling driver is added to qemud:
@@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen;
virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; };
and then initialized during qemud startup from qemudSecLabelInit().
During initialization, any available security labeling drivers are probed, and the first one which thinks it should be used is installed. Top-level libvirt API calls are then dispatched to the active security labeling driver via the backend virt driver, as necessary.
Note that the security labeling framework in this release is always built-in -- it can be made a compile-time option later if desired.
Requirements not yet addressed include: - Labeling of resources and generally comprehensive labeling management - Automatic labeling (e.g. for the simple isolation use-case) - Integration of labeling support into higher-level management tools such as virt-manager - Integration with the audit subsystem to help with administration and debugging - Domain of interpretation (DOI) checking/translation - Python bindings
As mentioned, the goal at this stage is to get feedback on the underlying design: comments welcome!
- James
Why do we care about the policy type? Policy type is a fairly meaningless object. If you are trying to figure out if the host machine is valid to run a virtual machine you should just check whether the type is valid on the machine, That way if I define minimum policy with virt support on one host and targeted policy with virt support on another machine, both would work. Finally I think it might be ok for the administrator to request that this virtual machine would only run on a machine with SELinux in enforcing mode. For example if you had a fairly untrusted virtual machine you would want to ensure that the machine was enforcing SELinux before it got started.

On Tue, Oct 21, 2008 at 09:57:15AM -0400, Daniel J Walsh wrote:
James Morris wrote:
[snip]
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
It's possible to query the security label of a running domain via virsh:
# virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing)
[snip]
Why do we care about the policy type? Policy type is a fairly meaningless object. If you are trying to figure out if the host machine is valid to run a virtual machine you should just check whether the type is valid on the machine, That way if I define minimum policy with virt support on one host and targeted policy with virt support on another machine, both would work. Finally I think it might be ok for the administrator to request that this virtual machine would only run on a machine with SELinux in enforcing mode. For example if you had a fairly untrusted virtual machine you would want to ensure that the machine was enforcing SELinux before it got started.
Who/what should be making such a policy decision though ? Seems like the management app using libvirt would want to do that - perhaps even making that decison before defining the existance of the VM on the target machine, let alone starting it. When migrating a VM from one host to another an application may also want to verify that the same policy is available on both the source and target hosts. A simple 'targeted' vs 'enforcing' string is likely not sufficient in this context. This also feels like host level info, rather per-VM. I think the 'policytype' bit of the label may thus better live in the host capabilities XML document, so you can query it independantly of any virtual machine eg perhaps something like # virsh capabilities <capabilities> <host> <cpu> <arch>i686</arch> </cpu> <secpolicy model='selinux'> <type>targetted</type> <state>enforcing</state> </secpolicy> </host> .... snip rest of XML... Is there any meaningful / useful policy version information that can be included here ? Or policy feature bits The VM config would thus only need <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> </seclabel> ... </domain> I should note that the domain XML format is representative of the config for a particular deployment of a virtual machine onto a host. It is not a generic interchange format for 'appliances'. If you were distributing an appliance, then the virt-image XML format would be used, and this encodes information on pre-requisites for host capabilities. When an appliance is deployed as a virtual domain, the virt-image tool, validate the virt-image XML pre-requisites, against the host capabilites XML to determine if the host is suitable. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, Oct 21, 2008 at 09:57:15AM -0400, Daniel J Walsh wrote:
James Morris wrote:
[snip]
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
It's possible to query the security label of a running domain via virsh:
# virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing)
[snip]
Why do we care about the policy type? Policy type is a fairly meaningless object. If you are trying to figure out if the host machine is valid to run a virtual machine you should just check whether the type is valid on the machine, That way if I define minimum policy with virt support on one host and targeted policy with virt support on another machine, both would work. Finally I think it might be ok for the administrator to request that this virtual machine would only run on a machine with SELinux in enforcing mode. For example if you had a fairly untrusted virtual machine you would want to ensure that the machine was enforcing SELinux before it got started.
Who/what should be making such a policy decision though ? Seems like the management app using libvirt would want to do that - perhaps even making that decison before defining the existance of the VM on the target machine, let alone starting it.
When migrating a VM from one host to another an application may also want to verify that the same policy is available on both the source and target hosts. A simple 'targeted' vs 'enforcing' string is likely not sufficient in this context. This also feels like host level info, rather per-VM.
I think the 'policytype' bit of the label may thus better live in the host capabilities XML document, so you can query it independantly of any virtual machine
eg perhaps something like
# virsh capabilities <capabilities>
<host> <cpu> <arch>i686</arch> </cpu> <secpolicy model='selinux'> <type>targetted</type> <state>enforcing</state> </secpolicy> </host>
.... snip rest of XML...
Is there any meaningful / useful policy version information that can be included here ? Or policy feature bits
The VM config would thus only need
<domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> </seclabel> ... </domain>
I should note that the domain XML format is representative of the config for a particular deployment of a virtual machine onto a host.
It is not a generic interchange format for 'appliances'. If you were distributing an appliance, then the virt-image XML format would be used, and this encodes information on pre-requisites for host capabilities.
When an appliance is deployed as a virtual domain, the virt-image tool, validate the virt-image XML pre-requisites, against the host capabilites XML to determine if the host is suitable.
Daniel Again targeted means nothing. It is just an arbitrary name given to a
Daniel P. Berrange wrote: policy package. So I don't see why it should be mentioned anywhere. I think the existance of the kernel policy which understands what a system_u:system_r:virtd_t:s0 is what is important. Again, I could have a three host machines each one with a different policy package say targeted, mls and overt policy package. If all three understand what a system_u:system_r:virtd_t:s0 type is, then all three could run the image. Having two machine with a "targeted" policy on them does nothing to assure that a processs labeled system_u:system_r:virtd_t:s0 can run. As far as enforcing mode is concerned, I thought that you could require that this virtual machine could only run on machines with SELinux in enforcing mode. so wouldn't that be associated with the virtual machine?

On Tue, Oct 21, 2008 at 01:50:20PM -0400, Daniel J Walsh wrote:
On Tue, Oct 21, 2008 at 09:57:15AM -0400, Daniel J Walsh wrote:
James Morris wrote: I think the 'policytype' bit of the label may thus better live in the host capabilities XML document, so you can query it independantly of any virtual machine
eg perhaps something like
# virsh capabilities <capabilities>
<host> <cpu> <arch>i686</arch> </cpu> <secpolicy model='selinux'> <type>targetted</type> <state>enforcing</state> </secpolicy> </host>
.... snip rest of XML...
Is there any meaningful / useful policy version information that can be included here ? Or policy feature bits
The VM config would thus only need
<domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> </seclabel> ... </domain>
I should note that the domain XML format is representative of the config for a particular deployment of a virtual machine onto a host.
It is not a generic interchange format for 'appliances'. If you were distributing an appliance, then the virt-image XML format would be used, and this encodes information on pre-requisites for host capabilities.
When an appliance is deployed as a virtual domain, the virt-image tool, validate the virt-image XML pre-requisites, against the host capabilites XML to determine if the host is suitable.
Daniel Again targeted means nothing. It is just an arbitrary name given to a
Daniel P. Berrange wrote: policy package. So I don't see why it should be mentioned anywhere.
I think the existance of the kernel policy which understands what a system_u:system_r:virtd_t:s0 is what is important.
Again, I could have a three host machines each one with a different policy package say targeted, mls and overt policy package. If all three understand what a system_u:system_r:virtd_t:s0 type is, then all three could run the image.
I guess my point was that we need a way to determine whether the policy on any machine is suitable for running a VM, before placing the VM on that host. In the context of a data center mgmt app we can have 100's or 1000's of possible virtualization enabled hosts. Not all of these hosts will be providing the same level of functionality / same versions of software, including selinux policy. So before starting a VM, the mgmt app needs to be able to make a reasonably accurate decision about what host will support the VM's requirements for SELinux policy capabilities. We can't just pick one at random, try to start if and see if the kernel complains that 'system_u:system_r:virtd_t:s0' doesn't exist in its policy.
Having two machine with a "targeted" policy on them does nothing to assure that a processs labeled system_u:system_r:virtd_t:s0 can run.
It wasn't intended to be a guarentee - its basically metadata to help the admin / mgmt app pick a suitable virtualization host from amongst their data center of 100's of machine. Maybe exposing the policytype 'targetted' is the wrong thing to be considering for this purpose. Perhaps we should instead provide an API to let you query the full list of all defined security domains, roles and users. Basically enough info to let you validate whether the label 'system_u:system_r:virtd_t:s0' is likely to be supported. NB I use the word 'likely' here - we don't need an absolute guarentee - we just need to be able to make a reasonable choice of hosts & if it fails it can be re-placed elsewhere. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

libvir-list-bounces@redhat.com wrote on 10/22/2008 05:51:46 AM:
"Daniel P. Berrange" <berrange@redhat.com> Sent by: libvir-list-bounces@redhat.com
Again, I could have a three host machines each one with a different policy package say targeted, mls and overt policy package. If all
[...] three
understand what a system_u:system_r:virtd_t:s0 type is, then all three could run the image.
I guess my point was that we need a way to determine whether the policy on any machine is suitable for running a VM, before placing the VM on that host. In the context of a data center mgmt app we can have 100's or 1000's of possible virtualization enabled hosts. Not all of these hosts will be providing the same level of functionality / same versions of software, including selinux policy.
This sounds like there would need to be an API for the retrieval of the current policy module that applies to the labeling of for example the qemu process. A management application would then certainly need to interpret this policy module to understand what labels are possible. How about enabling the update of this policy module by exposing an API that lets one set a new policy so that virtual machines with new labels can be placed? Would this be within scope of the security extensions? The actual labeling of the virtual machine image files could probably have to be left up to other management APIs that may deal with making those virtual machine images available, but nevertheless an API for labeling of VM images may be useful as well. Stefan

On Tue, 21 Oct 2008, Daniel P. Berrange wrote:
I should note that the domain XML format is representative of the config for a particular deployment of a virtual machine onto a host.
It is not a generic interchange format for 'appliances'. If you were distributing an appliance, then the virt-image XML format would be used, and this encodes information on pre-requisites for host capabilities.
When an appliance is deployed as a virtual domain, the virt-image tool, validate the virt-image XML pre-requisites, against the host capabilites XML to determine if the host is suitable.
As you mention in a later email, enforcing mode can be set on a per-process (domain) basis, so for the case of domain labeling, the current enforcing status needs to be bound to the domain. In terms of migration and provisioning, we need to consider several issues in more detail (some perhaps later), e.g.: - It should be possible to migrate an "isolated" domain between different types of security models if each supports it (e.g. from Smack to SELinux); - How do we handle different types of virtualization running on the same host, e.g. qemu domains running inside containers? - Policy for import and export of domains, including translation of labels when imported. Initially, though, perhaps just stick with the simplest case of listing which security models and DOIs are supported, and I think we should stick with 'seclabel' rather than introduce 'secpolicy'. <host> ... <seclabel model='selinux'> <doi>engineering.example.com.</doi> <!-- any other supported DOIs... --> <enforcing>yes</enforcing> </seclabel> <!-- any other active security labeling models ... --> </host> -- James Morris <jmorris@namei.org>

On Wed, Oct 22, 2008 at 08:50:19PM +1100, James Morris wrote:
On Tue, 21 Oct 2008, Daniel P. Berrange wrote:
I should note that the domain XML format is representative of the config for a particular deployment of a virtual machine onto a host.
It is not a generic interchange format for 'appliances'. If you were distributing an appliance, then the virt-image XML format would be used, and this encodes information on pre-requisites for host capabilities.
When an appliance is deployed as a virtual domain, the virt-image tool, validate the virt-image XML pre-requisites, against the host capabilites XML to determine if the host is suitable.
As you mention in a later email, enforcing mode can be set on a per-process (domain) basis, so for the case of domain labeling, the current enforcing status needs to be bound to the domain.
In terms of migration and provisioning, we need to consider several issues in more detail (some perhaps later), e.g.:
- It should be possible to migrate an "isolated" domain between different types of security models if each supports it (e.g. from Smack to SELinux);
- How do we handle different types of virtualization running on the same host, e.g. qemu domains running inside containers?
The data in the host capability XML is interpreted wrt the hypervisor connection URI you gave to virConnectPtr. So if you open two libvirt connections, one with qemu:///system and one with 'xen:///' on the same physical host, it is expected you will see alternative views of that host. As just one example, if you opened 'qemu:///system' on a Xen enabled host you'd only see a view of the world that covers the hardware available to Domain-0. This can be a subset of the hardware seen by the hypervisor itself. If you opened 'xen:///' then you'd see the full view. So, what this means for security models - if you opened 'qemu:///system' on a Xen enabled host you'd likely see a SELinux security model, whereas 'xen:///' would likely show you an XSM security model. That said in normal circumstances we don't expect that people will use multiple different virtualization technologies within the context of a single OS instance. You may however see nested virtualization, eg, a Fedora 9 KVM host, runs a RHEL-5 xen guest, which runs a Windows guest. There are even patches for KVM to let it expose SVM hardware virt to the guests. libvirt does not try to track this nesting explicitly - its viewpoint is always limited to a single hypervisor connection. The intent is that libvirt provides enough metadata, to allow an external mgmt application to build up a complete 'world view' of all its data center, correlating guests & hosts, primarily via the UUID.
- Policy for import and export of domains, including translation of labels when imported.
Initially, though, perhaps just stick with the simplest case of listing which security models and DOIs are supported, and I think we should stick with 'seclabel' rather than introduce 'secpolicy'.
<host> ... <seclabel model='selinux'> <doi>engineering.example.com.</doi> <!-- any other supported DOIs... --> <enforcing>yes</enforcing> </seclabel>
<!-- any other active security labeling models ... -->
</host>
I think to start with we probably just assume a single security labelling model per hypervisor connection. If a single host happened to have multiple models, I believe each model would likely be scoped to a specific hypervisor on the host. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, 22 Oct 2008, Daniel P. Berrange wrote:
I think to start with we probably just assume a single security labelling model per hypervisor connection. If a single host happened to have multiple models, I believe each model would likely be scoped to a specific hypervisor on the host.
I would expect that, too. -- James Morris <jmorris@namei.org>

On Tue, 21 Oct 2008, Daniel P. Berrange wrote:
eg perhaps something like
# virsh capabilities <capabilities>
<host> <cpu> <arch>i686</arch> </cpu> <secpolicy model='selinux'> <type>targetted</type> <state>enforcing</state> </secpolicy> </host>
.... snip rest of XML...
I don't think the endforcing state for the host will be useful, as this can change between API calls, and it really needs to be enforced on the host at the time of domain instantiation.
Is there any meaningful / useful policy version information that can be included here ? Or policy feature bits
Possibly, although I think we should leave the configuration of DOI to the admin, rather than trying to figure out what might be useful in advance. In some cases, the admin may wish to use an RPM package+version string, and others, a domain name could indicate that each system is managed within an boundary with consistent label semantics. - James -- James Morris <jmorris@namei.org>

On Tue, 21 Oct 2008, Daniel J Walsh wrote:
Why do we care about the policy type? Policy type is a fairly meaningless object. If you are trying to figure out if the host machine is valid to run a virtual machine you should just check whether the type is valid on the machine, That way if I define minimum policy with virt support on one host and targeted policy with virt support on another machine, both would work.
We need a way to indicate how to interpret the meaning of labels, which may vary depending on how policy has been implemented and deployed within a specific administrative boundary. Keep in mind also that this API needs to be useable with non-SELinux security schemes, although, in any case, just because a label is technically valid on a system, doesn't mean that the meaning is understood. e.g. "virt_image_t:s0" on a targeted system could mean something radically different to "virt_image_t:s0" on an MLS system, where, say, "s0" might mean "top secret" instead of "nothing". Perhaps we should call this element "doi" (Domain of Interpretation) instead of "policytype", in keeping with existing similar security labeling, and not tied in name to the SELinux polictype configuration variable. I thought the SELinux policytype in this case would be a useful starting point for the DOI, although the truth is that this needs to be entirely administratively managed. We can't predict where administrative security boundaries will be or how the user will represent them. Possibile DOI schemes include domain name, policy package+version names, existing kerberos realms etc. As this will be a long-lasting API, we need to build support for DOI in now, and annotate where the DOI should be considered. e.g. - A server should only launch a domain if the domain's label is bound to a an appropriate DOI; - When displaying security labels remotely, the DOI bound to the label should be displayed with the label (or translate the label, if appropriate). For a default value, I suggest we use the string "local", which means that the label only has significance on the local system where the domain is running. Anything beyond that needs to be explicitly configured by the admin.
Finally I think it might be ok for the administrator to request that this virtual machine would only run on a machine with SELinux in enforcing mode. For example if you had a fairly untrusted virtual machine you would want to ensure that the machine was enforcing SELinux before it got started.
Ok, so the domain configuration could have an element like: <enforce>yes</enforce> which means that label security policy must be applied. The security label for the domain would now look like: <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <doi>local</doi> <enforce>no</enforce> </seclabel> - James -- James Morris <jmorris@namei.org>

On Wednesday 22 October 2008 5:23:45 am James Morris wrote:
On Tue, 21 Oct 2008, Daniel J Walsh wrote:
Why do we care about the policy type? Policy type is a fairly meaningless object. If you are trying to figure out if the host machine is valid to run a virtual machine you should just check whether the type is valid on the machine, That way if I define minimum policy with virt support on one host and targeted policy with virt support on another machine, both would work.
We need a way to indicate how to interpret the meaning of labels, which may vary depending on how policy has been implemented and deployed within a specific administrative boundary. Keep in mind also that this API needs to be useable with non-SELinux security schemes, although, in any case, just because a label is technically valid on a system, doesn't mean that the meaning is understood. e.g. "virt_image_t:s0" on a targeted system could mean something radically different to "virt_image_t:s0" on an MLS system, where, say, "s0" might mean "top secret" instead of "nothing".
Perhaps we should call this element "doi" (Domain of Interpretation) instead of "policytype", in keeping with existing similar security labeling, and not tied in name to the SELinux polictype configuration variable.
I thought the SELinux policytype in this case would be a useful starting point for the DOI, although the truth is that this needs to be entirely administratively managed. We can't predict where administrative security boundaries will be or how the user will represent them. Possibile DOI schemes include domain name, policy package+version names, existing kerberos realms etc.
I like the concept of a DOI field instead of policy type; considering the portability of guest images this seems like a good solution based on the relative success of DOIs in other distributed applications. However, may I suggest that instead of representing the DOI as a string we use a 32bit integer? I know that may sound a bit odd, but in the networking world most DOI values are represented as integers and when security labels are involved they tend to be 32bits. I understand that using a plain integer is much more abstract than a human readable string but it should make it easier to leverage existing and future* DOI frameworks. *An informal group/list just formed to start discussing DOI management issues such as DOI formats, negotiation and translation. -- paul moore linux @ hp

On Thu, 23 Oct 2008, Paul Moore wrote:
However, may I suggest that instead of representing the DOI as a string we use a 32bit integer? I know that may sound a bit odd, but in the networking world most DOI values are represented as integers and when security labels are involved they tend to be 32bits. I understand that using a plain integer is much more abstract than a human readable string but it should make it easier to leverage existing and future* DOI frameworks.
I'd prefer to use string, which can be managed freely by the user, and be human-readable. Unlike IP layer networking, we're not constrained by e.g. having to fit in the IP options, and can simply convey the DOI as-is. This will also not prevent users from utilizing integers as the DOI if desired. In the common non-DoD case, people should be able to configure the DOI as simply as editing a configuration file to set the DOI to a domain name or arbitrary realm name.
*An informal group/list just formed to start discussing DOI management issues such as DOI formats, negotiation and translation.
URL ? - James -- James Morris <jmorris@namei.org>

On Tuesday 28 October 2008 5:42:17 pm James Morris wrote:
On Thu, 23 Oct 2008, Paul Moore wrote:
However, may I suggest that instead of representing the DOI as a string we use a 32bit integer? I know that may sound a bit odd, but in the networking world most DOI values are represented as integers and when security labels are involved they tend to be 32bits. I understand that using a plain integer is much more abstract than a human readable string but it should make it easier to leverage existing and future* DOI frameworks.
I'd prefer to use string, which can be managed freely by the user, and be human-readable. Unlike IP layer networking, we're not constrained by e.g. having to fit in the IP options, and can simply convey the DOI as-is.
True, we've got plenty of space to play with in the sVirt case as opposed to things like labeled networking and labeled NFS. However, that wasn't really my concern. It is likely that at some point in the future we will have some sort of standardized approach to dealing with DOIs and right now most of the DOIs in the labeled security space are 32 bit integers; using a 32 bit value in sVirt has the potential to make life much easier down the road. Granted, if strings are voted as the way forward and portability of labeled guests really takes off then I'm sure we'll find a way to deal with it; it would just be nice not to have to adapt things later on.
This will also not prevent users from utilizing integers as the DOI if desired.
Also true.
In the common non-DoD case, people should be able to configure the DOI as simply as editing a configuration file to set the DOI to a domain name or arbitrary realm name.
I don't think DoD/non-DoD has anything to do with it, it is more of a management issue and both groups have the same problem. Is the convenience of being able to enter "guests-r-us.com" over "5" in the DOI field really worth the disconnect from the traditional 32 bit DOI integer?
*An informal group/list just formed to start discussing DOI management issues such as DOI formats, negotiation and translation.
URL ?
Viola, http://mail.opensolaris.org/mailman/listinfo/doi-discuss, there was one thread in the beginning that got some traffic but it has been pretty quiet since then. I'm pretty sure archives are available at the link above. -- paul moore linux @ hp

On Tue, 2008-10-28 at 18:17 -0400, Paul Moore wrote:
On Tuesday 28 October 2008 5:42:17 pm James Morris wrote:
On Thu, 23 Oct 2008, Paul Moore wrote:
However, may I suggest that instead of representing the DOI as a string we use a 32bit integer? I know that may sound a bit odd, but in the networking world most DOI values are represented as integers and when security labels are involved they tend to be 32bits. I understand that using a plain integer is much more abstract than a human readable string but it should make it easier to leverage existing and future* DOI frameworks.
I'd prefer to use string, which can be managed freely by the user, and be human-readable. Unlike IP layer networking, we're not constrained by e.g. having to fit in the IP options, and can simply convey the DOI as-is.
True, we've got plenty of space to play with in the sVirt case as opposed to things like labeled networking and labeled NFS. However, that wasn't really my concern. It is likely that at some point in the future we will have some sort of standardized approach to dealing with DOIs and right now most of the DOIs in the labeled security space are 32 bit integers; using a 32 bit value in sVirt has the potential to make life much easier down the road. Granted, if strings are voted as the way forward and portability of labeled guests really takes off then I'm sure we'll find a way to deal with it; it would just be nice not to have to adapt things later on.
I really don't like the idea of using strings for this. With our u32 scheme we have a way of provisioning off private DOI spaces which is fairly simple since we can allocate ranges within the int. With strings if you want to indicate something is private you are going to have to come up with come convention of adding a prefix or suffix to indicate that. If you want to do DOI->Name translations we can make sure to require a valid name for the DOI in the IANA registration for the public ones and you will have to have something similar to setransd to handle them for private ones. Either that or build it into your scheme that when I specify a DOI I specify a name for it as well. You can have DOI be a complex element containing an int and a string.
This will also not prevent users from utilizing integers as the DOI if desired.
Also true.
However if you go with strings they are completely unusable for labeled networking and labeled NFS unless they are already a number or we come up with some sort of translation facility for it. I'd rather see the translation from int->string than string->int.
In the common non-DoD case, people should be able to configure the DOI as simply as editing a configuration file to set the DOI to a domain name or arbitrary realm name.
I don't think DoD/non-DoD has anything to do with it, it is more of a management issue and both groups have the same problem. Is the convenience of being able to enter "guests-r-us.com" over "5" in the DOI field really worth the disconnect from the traditional 32 bit DOI integer?
If in the config file the DOI is a complex element with both DOI and name you can have your cake and eat it to. I see the name element as an explicit mapping rule of DOI to a string. Also if you intend to have names like the one above it seems even less correct to use them. When guests-r-us.com and myguests.com can be running policies with the same exact semantics then it is even more important to say they both have a DOI of 5. That way you really know the policy semantics are the same instead of it being shrouded by the names. It would confuse the hell out of me as an administrator if they were identical but have two different names or if I looked at my myguests.com VMs and saw that they were running the guests-r-us.com DOI.
*An informal group/list just formed to start discussing DOI management issues such as DOI formats, negotiation and translation.
URL ?
Viola, http://mail.opensolaris.org/mailman/listinfo/doi-discuss, there was one thread in the beginning that got some traffic but it has been pretty quiet since then. I'm pretty sure archives are available at the link above.

On Tue, Oct 21, 2008 at 01:06:17PM +1100, James Morris wrote:
With this release, it is possible to define a security label for a kvm/qemu domain in its XML configuration ('virsh edit'), launch the domain and have it transition to the specified security label ('virsh start'), then query the security label of the running domain ('virsh dominfo').
The following changes were made to libvirt:
1. Implementing a pluggable security label driver framework;
2. Implementing an SELinux security label driver for (1);
3. Wiring the security label framework into the Qemu driver;
4. Implementing basic libvirt API calls for initializing the driver, and getting/setting domain security labels;
5. Extending the domain XML configuration to include security labels;
6. Adding domain security label display/edit/dump support to virsh.
One of the design principles I've followed with this is to reduce or eliminate configuration wherever possible. If a variety of security labeling drivers are present, libvirtd automatically detects which one to enable and enables it. e.g. if SELinux is enabled on the system, the SELinux labeling driver is enabled automatically when livbirtd starts.
Another is to treat security labels as opaque unless they're actually being used for security purposes (e.g. to launch the domain). So, virsh and the domain configuration code currently do not need to semantically interpet security labels, just understand their format. This should suit the initial simple goal of isolated domains, which only requires security labels to be distinct.
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
As I mentioned in my reply to Dan Walsh's comments, I thing that the policy type & its state (disabled, permissive, enforcing) is really a property of the host, rather than the VM, and so should live in the host capabilities XML document.
Currently, the idea is to attach the security labeling driver to the virt driver, rather than implement it independently as a top-level component as in the case of other types of drivers (e.g. storage). This is because process-based security labeling is highly dependent on the kind of virtualization in use, and may not make sense at all in some cases (e.g. when using a non-Linux hypervisor, or containers).
Makes sense - the choice of hypervisor driver in libvirt determines what security model has to be applied to the storage/network sub-drivers in libvirt. So, eg if we activate Xen backend, we need to have an XSM based implementation for the security model of both the Xen driver and the storage backend.
In the case of qemu, a security labeling driver is added to qemud:
@@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen;
virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; };
and then initialized during qemud startup from qemudSecLabelInit().
During initialization, any available security labeling drivers are probed, and the first one which thinks it should be used is installed. Top-level libvirt API calls are then dispatched to the active security labeling driver via the backend virt driver, as necessary.
That all makes sense to me - you'll also likely need to expose the hypervisor driver's active security driver, to the storage & network drivers. For that I reckon extending the 'virDriverPtr' struct to add a internal only method virSecLabelDriverPtr (*getSecLabelDriver)(void); would be a suitable approach. This would avoid the storage/network drivers needing to know about the internal state of the HV driver.
Note that the security labeling framework in this release is always built-in -- it can be made a compile-time option later if desired.
As long as we can turn off the specific security model backends that is sufficient - no need to be able to turn off the entire security framework within libvirt - assuming of course everything handles a 'NULL' secLabelDriver.
Requirements not yet addressed include: - Labeling of resources and generally comprehensive labeling management - Automatic labeling (e.g. for the simple isolation use-case) - Integration of labeling support into higher-level management tools such as virt-manager - Integration with the audit subsystem to help with administration and debugging - Domain of interpretation (DOI) checking/translation - Python bindings
As mentioned, the goal at this stage is to get feedback on the underlying design: comments welcome!
Looking at it from a libvirt architecture POV, i think its all basically a sane approach. It appears, so far, to be generic enough that we could plug into an alternate XSM based impl for the Xen world, or delegate to whatever APIs something like VMWare / Hyper-V might provide.
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 35b80d0..58ded58 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -111,6 +111,53 @@ typedef enum { } virDomainCreateFlags;
/** + * VIR_SECLABEL_LABEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * label string. Note that this value is based on that used + * by Labeled NFS. + */ +#define VIR_SECLABEL_LABEL_BUFLEN (4096 + 1) + +/** + * VIR_SECLABEL_MODEL_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * model string. + */ +#define VIR_SECLABEL_MODEL_BUFLEN (256 + 1) + +/** + * VIR_SECLABEL_POLICYTYPE_BUFLEN: + * + * Macro providing the maximum length of the virDomainSecLabel + * policy string. + */ +#define VIR_SECLABEL_POLICYTYPE_BUFLEN (256 + 1) + +/** + * virDomainSecLabel: + * + * a virDomainSecLabel is a structure filled by virDomainGetSecLabel(), + * providing the security label and associated attributes for the specified + * domain. + * + */ +typedef struct _virDomainSecLabel { + char model[VIR_SECLABEL_MODEL_BUFLEN]; /* name of security labeling model */ + char label[VIR_SECLABEL_LABEL_BUFLEN]; /* security label string */ + char policytype[VIR_SECLABEL_POLICYTYPE_BUFLEN]; /* policy type */ + int enforcing; /* 1 if security policy is being enforced for domain */ +} virDomainSecLabel;
The policytype/model would seem redundant here as per-host attributes ? I guess since SELinux gained ability to specify that individual security domains are permissive, we do arguably still need an explicit flag 'enforcing' flag here, independantly of the global per-host 'enforcing' vs 'permissive' flag. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 21 Oct 2008, Daniel P. Berrange wrote:
As I mentioned in my reply to Dan Walsh's comments, I thing that the policy type & its state (disabled, permissive, enforcing) is really a property of the host, rather than the VM, and so should live in the host capabilities XML document.
I think we need to differentiate between what the host is capable of supporting (e.g. multiple virt schemes with different security models, or even emulating/translating other security models), and what the current label on the domain actually is. In the latter case, we need to bind the DOI, enforcing state and security model to the domain security label.
That all makes sense to me - you'll also likely need to expose the hypervisor driver's active security driver, to the storage & network drivers. For that I reckon extending the 'virDriverPtr' struct to add a internal only method
virSecLabelDriverPtr (*getSecLabelDriver)(void);
would be a suitable approach. This would avoid the storage/network drivers needing to know about the internal state of the HV driver.
Ok, I need to investigate this further.
+typedef struct _virDomainSecLabel { + char model[VIR_SECLABEL_MODEL_BUFLEN]; /* name of security labeling model */ + char label[VIR_SECLABEL_LABEL_BUFLEN]; /* security label string */ + char policytype[VIR_SECLABEL_POLICYTYPE_BUFLEN]; /* policy type */ + int enforcing; /* 1 if security policy is being enforced for domain */ +} virDomainSecLabel;
The policytype/model would seem redundant here as per-host attributes ?
As mentioned, I think we need to differentiate host capabilities from specific security labeling state for a domain on that host.
I guess since SELinux gained ability to specify that individual security domains are permissive, we do arguably still need an explicit flag 'enforcing' flag here, independantly of the global per-host 'enforcing' vs 'permissive' flag.
Yep. - James -- James Morris <jmorris@namei.org>

Hi, James I have a question just for interest. The security context stores like /etc/selinux/targeted/contexts/files/file_contexts. But you are storeing the domain security label on libvirt specific XML. Of course, this is good for libvirt POV. Is it permitted for SELinux policy POV? By the way, I want to see the further discussion of the Requirements.
Requirements not yet addressed include:
Thanks Atsushi SAKAI James Morris <jmorris@namei.org> wrote: [snip]
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
It's possible to query the security label of a running domain via virsh:
# virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing)
The security label is deterimed via the new virDomainGetSecLabel() API method, which is transported over RPC to the backend driver (qemu in this case), and is entirely independent of the local security model, if any. e.g. this command could be run remotely from an entirely different platform: you just see what's happening on the remote system, as with other attributes of the domain.
Feedback on the design thus far is sought before proceeding to more comprehensive integration.
In particular, I'd be interested in any thoughts on the placement of the security labeling driver within libvirt, as this seems to be the most critical architectural issue (I've already refactored this aspect once).
Currently, the idea is to attach the security labeling driver to the virt driver, rather than implement it independently as a top-level component as in the case of other types of drivers (e.g. storage). This is because process-based security labeling is highly dependent on the kind of virtualization in use, and may not make sense at all in some cases (e.g. when using a non-Linux hypervisor, or containers).
In the case of qemu, a security labeling driver is added to qemud:
@@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen;
virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; };
and then initialized during qemud startup from qemudSecLabelInit().
During initialization, any available security labeling drivers are probed, and the first one which thinks it should be used is installed. Top-level libvirt API calls are then dispatched to the active security labeling driver via the backend virt driver, as necessary.
Note that the security labeling framework in this release is always built-in -- it can be made a compile-time option later if desired.
Requirements not yet addressed include: - Labeling of resources and generally comprehensive labeling management - Automatic labeling (e.g. for the simple isolation use-case) - Integration of labeling support into higher-level management tools such as virt-manager - Integration with the audit subsystem to help with administration and debugging - Domain of interpretation (DOI) checking/translation - Python bindings
As mentioned, the goal at this stage is to get feedback on the underlying design: comments welcome!
- James -- James Morris <jmorris@namei.org>

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Atsushi SAKAI wrote:
Hi, James
I have a question just for interest.
The security context stores like /etc/selinux/targeted/contexts/files/file_contexts.
But you are storeing the domain security label on libvirt specific XML. Of course, this is good for libvirt POV.
Is it permitted for SELinux policy POV?
By the way, I want to see the further discussion of the Requirements.
Requirements not yet addressed include:
Thanks Atsushi SAKAI
Both /etc/selinux/targeted/contexts/files/file_contexts and libvirt specific XML are just indicators of the way the system should be setup. The kernel policy is the final arbiter of the policy. So if the kernel does not understand virt_image_t in /etc/selinux/targeted/contexts/files/file_contexts, it will not allow tools like rpm or restorecon to set it as a file context. Similarly if the process label qemu_t is specified in the libvirt xml, and the kernel policy does not know what a qemu_t is, it will not allow libvirt to start a processes labeled qemu_t.
James Morris <jmorris@namei.org> wrote:
[snip]
The domain security label configuration format is as follows:
# virsh dumpxml sys1 <domain> .... <seclabel model='selinux'> <label>system_u:system_r:virtd_t:s0</label> <policytype>targeted</policytype> </seclabel> </domain>
It's possible to query the security label of a running domain via virsh:
# virsh dominfo sys1 Id: 1 Name: sys1 UUID: fa3c8e06-0877-2a08-06fd-f2479b7bacb4 OS Type: hvm State: running CPU(s): 1 CPU time: 11.4s Max memory: 524288 kB Used memory: 524288 kB Autostart: disable Security label: system_u:system_r:virtd_t:s0 (selinux/targeted/enforcing)
The security label is deterimed via the new virDomainGetSecLabel() API method, which is transported over RPC to the backend driver (qemu in this case), and is entirely independent of the local security model, if any. e.g. this command could be run remotely from an entirely different platform: you just see what's happening on the remote system, as with other attributes of the domain.
Feedback on the design thus far is sought before proceeding to more comprehensive integration.
In particular, I'd be interested in any thoughts on the placement of the security labeling driver within libvirt, as this seems to be the most critical architectural issue (I've already refactored this aspect once).
Currently, the idea is to attach the security labeling driver to the virt driver, rather than implement it independently as a top-level component as in the case of other types of drivers (e.g. storage). This is because process-based security labeling is highly dependent on the kind of virtualization in use, and may not make sense at all in some cases (e.g. when using a non-Linux hypervisor, or containers).
In the case of qemu, a security labeling driver is added to qemud:
@@ -63,6 +64,7 @@ struct qemud_driver { char *vncListen;
virCapsPtr caps; + virSecLabelDriverPtr secLabelDriver; };
and then initialized during qemud startup from qemudSecLabelInit().
During initialization, any available security labeling drivers are probed, and the first one which thinks it should be used is installed. Top-level libvirt API calls are then dispatched to the active security labeling driver via the backend virt driver, as necessary.
Note that the security labeling framework in this release is always built-in -- it can be made a compile-time option later if desired.
Requirements not yet addressed include: - Labeling of resources and generally comprehensive labeling management - Automatic labeling (e.g. for the simple isolation use-case) - Integration of labeling support into higher-level management tools such as virt-manager - Integration with the audit subsystem to help with administration and debugging - Domain of interpretation (DOI) checking/translation - Python bindings
As mentioned, the goal at this stage is to get feedback on the underlying design: comments welcome!
- James -- James Morris <jmorris@namei.org>
-- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message.
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org iEYEARECAAYFAkkKCHgACgkQrlYvE4MpobO44ACdG8CX5Y6ptaUTd2RtP4rtjaTo u1sAniwNi1WoYUuxkO3zM9A8hNUGLhTO =jtTR -----END PGP SIGNATURE-----
participants (7)
-
Atsushi SAKAI
-
Daniel J Walsh
-
Daniel P. Berrange
-
David P. Quigley
-
James Morris
-
Paul Moore
-
Stefan Berger