[Libguestfs] [PATCH v2 4/5] add-domain: Pass SELinux label from guest to appliance (RHBZ#912499).

Matthew Booth mbooth at redhat.com
Fri Mar 1 12:33:49 UTC 2013


On Thu, 2013-02-28 at 16:02 +0000, Richard W.M. Jones wrote:
> From: "Richard W.M. Jones" <rjones at redhat.com>
> 
> When adding a domain (ie. guestfs_add_domain), read the SELinux
> <label/> and <imagelabel/> from the guest and use them for the
> appliance.  The appliance is statically labelled the same as the
> guest, so it is able to read its disks.
> 
> However tell libvirt not to try relabelling the disks, to prevent
> libvirt from disturbing the existing labels on the disks (in
> particular when the libvirt connection is closed, we don't want
> libvirt to try to restore some other label on the disks).
> ---
>  src/libvirt-domain.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 73 insertions(+)
> 
> diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
> index 3f5b1ed..768ed78 100644
> --- a/src/libvirt-domain.c
> +++ b/src/libvirt-domain.c
> @@ -20,6 +20,7 @@
>  
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <stdbool.h>
>  #include <assert.h>
>  
>  #ifdef HAVE_LIBVIRT
> @@ -42,6 +43,7 @@
>  
>  static xmlDocPtr get_domain_xml (guestfs_h *g, virDomainPtr dom);
>  static ssize_t for_each_disk (guestfs_h *g, xmlDocPtr doc, int (*f) (guestfs_h *g, const char *filename, const char *format, int readonly, void *data), void *data);
> +static int libvirt_selinux_label (guestfs_h *g, xmlDocPtr doc, char **label_rtn, char **imagelabel_rtn);
>  
>  static void
>  ignore_errors (void *ignore, virErrorPtr ignore2)
> @@ -169,6 +171,7 @@ guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
>    size_t ckp;
>    struct add_disk_data data;
>    CLEANUP_XMLFREEDOC xmlDocPtr doc = NULL;
> +  CLEANUP_FREE char *label = NULL, *imagelabel = NULL;
>  
>    readonly =
>      optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK
> @@ -234,6 +237,16 @@ guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
>    if ((doc = get_domain_xml (g, dom)) == NULL)
>      return -1;
>  
> +  /* Find and pass the SELinux security label to the libvirt back end. */
> +  if (libvirt_selinux_label (g, doc, &label, &imagelabel) == -1)
> +    return -1;
> +  if (label && imagelabel) {
> +    guestfs_internal_set_libvirt_selinux_label (g, label, imagelabel);
> +    guestfs_internal_set_libvirt_selinux_norelabel_disks (g, 1);

Do we need both internal apis? 1 seems to imply the other.

> +  }
> +  else
> +    guestfs_internal_set_libvirt_selinux_norelabel_disks (g, 0);
> +
>    /* Add the disks. */
>    data.optargs.bitmask = 0;
>    data.readonly = readonly;
> @@ -374,6 +387,66 @@ connect_live (guestfs_h *g, virDomainPtr dom)
>    return guestfs_set_attach_method (g, attach_method);
>  }
>  
> +/* Find the <seclabel/> element in the libvirt XML, and if it exists
> + * get the SELinux process label and image label from it.
> + *
> + * The reason for all this is because of sVirt:
> + * https://bugzilla.redhat.com/show_bug.cgi?id=912499#c7
> + */
> +static int
> +libvirt_selinux_label (guestfs_h *g, xmlDocPtr doc,
> +                       char **label_rtn, char **imagelabel_rtn)
> +{
> +  CLEANUP_XMLXPATHFREECONTEXT xmlXPathContextPtr xpathCtx = NULL;
> +  CLEANUP_XMLXPATHFREEOBJECT xmlXPathObjectPtr xpathObj = NULL;
> +  xmlNodeSetPtr nodes;
> +  size_t nr_nodes;
> +  xmlNodePtr node, child;
> +  bool gotlabel = 0, gotimagelabel = 0;

gotlabel and gotimagelabel appear to be unused apart from assignment.

> +  xpathCtx = xmlXPathNewContext (doc);
> +  if (xpathCtx == NULL) {
> +    error (g, _("unable to create new XPath context"));
> +    return -1;
> +  }
> +
> +  /* This gives us a set of all the <seclabel/> nodes, hopefully only one. */
> +  xpathObj = xmlXPathEvalExpression (BAD_CAST "/domain/seclabel",
> +                                     xpathCtx);
> +  if (xpathObj == NULL) {
> +    error (g, _("unable to evaluate XPath expression"));
> +    return -1;
> +  }
> +
> +  nodes = xpathObj->nodesetval;
> +  nr_nodes = nodes->nodeNr;
> +
> +  if (nr_nodes == 0 || nr_nodes > 1)
> +    return 0;

Not terribly important, but I wouldn't silently bomb out here if
nr_nodes > 1. If you're going to catch it at all I'd add a warning and
continue.

> +  node = nodes->nodeTab[0];
> +  if (node->type != XML_ELEMENT_NODE) {
> +    error (g, _("expected <seclabel/> to be an XML element"));
> +    return -1;
> +  }

For this to happen would require bugs in both libvirt and
xmlXPathEvalExpression(). For clarity and brevity I wouldn't bother
error checking this.

> +
> +  /* Find the <label/> and <imagelabel/> child nodes. */
> +  for (child = node->children; child != NULL; child = child->next) {
> +    if (!gotlabel && STREQ ((char *) child->name, "label")) {
> +      /* Get the label content. */
> +      *label_rtn = (char *) xmlNodeGetContent (child);
> +      gotlabel = 1;
> +    }
> +    if (!gotimagelabel && STREQ ((char *) child->name, "imagelabel")) {
> +      /* Get the imagelabel content. */
> +      *imagelabel_rtn = (char *) xmlNodeGetContent (child);
> +      gotimagelabel = 1;
> +    }
> +  }

Alternatively:

labelObj = xmlXPathEvalExpression
  (BAD_CAST "/domain/seclabel[1]/label", xpathCtx);
imageLabelObj = xmlXPathEvalExpression
  (BAD_CAST "/domain/seclabel[1]/imagelabel", xpathCtx);
if (labelObj == NULL || imageLabelObj == NULL) {
  error (g, _("unable to evaluate XPath expression"));
  return -1;
}

labelNodes = labelObj->nodesetval;
imageLabelNodes = imageLabelObj->nodesetval;

if (labelNodes->nodeNr == 0 || imageLabelNodes->nodeNr == 0)
  return 0;

*label_rtn =
  (char *) xmlNodeGetContent (labelNodes->nodeTab[0]);
*imagelabel_rtn =
  (char *) xmlNodeGetContent (imageLabelNodes->nodeTab[0]);

> +
> +  return 0;
> +}
> +
>  /* The callback function 'f' is called once for each disk.
>   *
>   * Returns number of disks, or -1 if there was an error.

Matt




More information about the Libguestfs mailing list