[libvirt] [PATCH] security_dac: Honor norelabel attribute

Jiri Denemark jdenemar at redhat.com
Wed Mar 26 15:54:17 UTC 2014


On Mon, Mar 24, 2014 at 17:37:07 +0100, Michal Privoznik wrote:
> The inspiration for this patch comes from a question on the list
> asking if there's a way to not label some disks. Well, in DAC driver
> there's not. Even if user have requested norelabel:
> 
>     <disk type='file' device='disk'>
>       <driver name='qemu' type='raw'/>
>       <source file='/some/dummy/path/test.bin'>
>         <seclabel model='dac' relabel='no'/>
>       </source>
>       <target dev='vdb' bus='virtio'/>
>       <readonly/>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
>     </disk>
> 
> the DAC driver ignores this completely. When adjusting the code, I
> realized it's a ragbag with plenty of things that we try to avoid.
> >From the variety just a few things: callback data were passed as:
> 
>     void params[2];
>     params[0] = mgr;
>     params[1] = def;
> 
> Or my favorite - checking for passed pointer being non NULL on each
> level of the stack, in each callee. As a pattern of readable code the
> selinux driver was used.
> 
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
>  src/security/security_dac.c | 244 ++++++++++++++++++++++++--------------------
>  1 file changed, 131 insertions(+), 113 deletions(-)
> 
> diff --git a/src/security/security_dac.c b/src/security/security_dac.c
> index 9f45063..3b8fe04 100644
> --- a/src/security/security_dac.c
> +++ b/src/security/security_dac.c
> @@ -53,6 +53,15 @@ struct _virSecurityDACData {
>      char *baselabel;
>  };
>  
> +typedef struct _virSecurityDACCallbackData virSecurityDACCallbackData;
> +typedef virSecurityDACCallbackData *virSecurityDACCallbackDataPtr;
> +
> +struct _virSecurityDACCallbackData {
> +    virSecurityManagerPtr manager;
> +    virSecurityLabelDefPtr secdef;
> +};
> +
> +
>  /* returns -1 on error, 0 on success */
>  int
>  virSecurityDACSetUserAndGroup(virSecurityManagerPtr mgr,
> @@ -81,65 +90,42 @@ virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
>  
>  /* returns 1 if label isn't found, 0 on success, -1 on error */
>  static int
> -virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr)
> +virSecurityDACParseIds(virSecurityLabelDefPtr seclabel,
> +                       uid_t *uidPtr, gid_t *gidPtr)
>  {
> -    uid_t uid;
> -    gid_t gid;
> -    virSecurityLabelDefPtr seclabel;
> -
> -    if (def == NULL)
> -        return 1;
> -
> -    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> -    if (seclabel == NULL || seclabel->label == NULL) {
> -        VIR_DEBUG("DAC seclabel for domain '%s' wasn't found", def->name);
> +    if (!seclabel || !seclabel->label)
>          return 1;
> -    }
>  
> -    if (virParseOwnershipIds(seclabel->label, &uid, &gid) < 0)
> +    if (virParseOwnershipIds(seclabel->label, uidPtr, gidPtr) < 0)
>          return -1;
>  
> -    if (uidPtr)
> -        *uidPtr = uid;
> -    if (gidPtr)
> -        *gidPtr = gid;
> -
>      return 0;
>  }
>  
>  static int
> -virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
> +virSecurityDACGetIds(virSecurityLabelDefPtr seclabel,
> +                     virSecurityDACDataPtr priv,
>                       uid_t *uidPtr, gid_t *gidPtr,
>                       gid_t **groups, int *ngroups)
>  {
>      int ret;
>  
> -    if (!def && !priv) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                       _("Failed to determine default DAC seclabel "
> -                         "for an unknown object"));
> -        return -1;
> -    }
> -
>      if (groups)
>          *groups = priv ? priv->groups : NULL;
>      if (ngroups)
>          *ngroups = priv ? priv->ngroups : 0;
>  
> -    if ((ret = virSecurityDACParseIds(def, uidPtr, gidPtr)) <= 0)
> +    if ((ret = virSecurityDACParseIds(seclabel, uidPtr, gidPtr)) <= 0)
>          return ret;
>  
>      if (!priv) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("DAC seclabel couldn't be determined "
> -                         "for domain '%s'"), def->name);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("DAC seclabel couldn't be determined"));
>          return -1;
>      }
>  
> -    if (uidPtr)
> -        *uidPtr = priv->user;
> -    if (gidPtr)
> -        *gidPtr = priv->group;
> +    *uidPtr = priv->user;
> +    *gidPtr = priv->group;
>  
>      return 0;
>  }
> @@ -147,60 +133,36 @@ virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
>  
>  /* returns 1 if label isn't found, 0 on success, -1 on error */
>  static int
> -virSecurityDACParseImageIds(virDomainDefPtr def,
> +virSecurityDACParseImageIds(virSecurityLabelDefPtr seclabel,
>                              uid_t *uidPtr, gid_t *gidPtr)
>  {
> -    uid_t uid;
> -    gid_t gid;
> -    virSecurityLabelDefPtr seclabel;
> -
> -    if (def == NULL)
> -        return 1;
> -
> -    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> -    if (seclabel == NULL || seclabel->imagelabel == NULL) {
> -        VIR_DEBUG("DAC imagelabel for domain '%s' wasn't found", def->name);
> +    if (!seclabel || !seclabel->imagelabel)
>          return 1;
> -    }
>  
> -    if (virParseOwnershipIds(seclabel->imagelabel, &uid, &gid) < 0)
> +    if (virParseOwnershipIds(seclabel->imagelabel, uidPtr, gidPtr) < 0)
>          return -1;
>  
> -    if (uidPtr)
> -        *uidPtr = uid;
> -    if (gidPtr)
> -        *gidPtr = gid;
> -
>      return 0;
>  }
>  
>  static int
> -virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
> +virSecurityDACGetImageIds(virSecurityLabelDefPtr seclabel,
> +                          virSecurityDACDataPtr priv,
>                            uid_t *uidPtr, gid_t *gidPtr)
>  {
>      int ret;
>  
> -    if (!def && !priv) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> -                       _("Failed to determine default DAC imagelabel "
> -                         "for an unknown object"));
> -        return -1;
> -    }
> -
> -    if ((ret = virSecurityDACParseImageIds(def, uidPtr, gidPtr)) <= 0)
> +    if ((ret = virSecurityDACParseImageIds(seclabel, uidPtr, gidPtr)) <= 0)
>          return ret;
>  
>      if (!priv) {
> -        virReportError(VIR_ERR_INTERNAL_ERROR,
> -                       _("DAC imagelabel couldn't be determined "
> -                         "for domain '%s'"), def->name);
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("DAC imagelabel couldn't be determined"));
>          return -1;
>      }
>  
> -    if (uidPtr)
> -        *uidPtr = priv->user;
> -    if (gidPtr)
> -        *gidPtr = priv->group;
> +    *uidPtr = priv->user;
> +    *gidPtr = priv->group;
>  
>      return 0;
>  }

It would have been nice to split the refactoring (such as the one above)
and the code implementing relabel=no for DAC driver :-)

> @@ -324,20 +286,32 @@ err:
>  
>  
>  static int
> -virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
> +virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk,
>                                     const char *path,
>                                     size_t depth ATTRIBUTE_UNUSED,
>                                     void *opaque)
>  {
> -    void **params = opaque;
> -    virSecurityManagerPtr mgr = params[0];
> -    virDomainDefPtr def = params[1];
> +    virSecurityDACCallbackDataPtr cbdata = opaque;
> +    virSecurityManagerPtr mgr = cbdata->manager;
> +    virSecurityLabelDefPtr secdef = cbdata->secdef;
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityDeviceLabelDefPtr disk_seclabel;
>      uid_t user;
>      gid_t group;
>  
> -    if (virSecurityDACGetImageIds(def, priv, &user, &group))
> -        return -1;
> +    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
> +                                                        SECURITY_DAC_NAME);
> +
> +    if (disk_seclabel && disk_seclabel->norelabel)
> +        return 0;
> +
> +    if (disk_seclabel && disk_seclabel->label) {
> +        if (virParseOwnershipIds(disk_seclabel->label, &user, &group) < 0)
> +            return -1;
> +    } else {
> +        if (virSecurityDACGetImageIds(secdef, priv, &user, &group))

Shouldn't this check for < 0?

> +            return -1;
> +    }
>  
>      return virSecurityDACSetOwnership(path, user, group);
>  }
> @@ -349,8 +323,9 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
>                                      virDomainDiskDefPtr disk)
>  
>  {
> -    void *params[2];
> +    virSecurityDACCallbackData cbdata;
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr secdef;
>  
>      if (!priv->dynamicOwnership)
>          return 0;
> @@ -358,12 +333,16 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
>      if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
>          return 0;
>  
> -    params[0] = mgr;
> -    params[1] = def;
> +    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +    if (secdef && secdef->norelabel)
> +        return 0;
> +
> +    cbdata.manager = mgr;
> +    cbdata.secdef = secdef;
>      return virDomainDiskDefForeachPath(disk,
>                                         false,
>                                         virSecurityDACSetSecurityFileLabel,
> -                                       params);
> +                                       &cbdata);
>  }
>  
>  
> @@ -428,14 +407,14 @@ static int
>  virSecurityDACSetSecurityHostdevLabelHelper(const char *file,
>                                              void *opaque)
>  {
> -    void **params = opaque;
> -    virSecurityManagerPtr mgr = params[0];
> -    virDomainDefPtr def = params[1];
> +    virSecurityDACCallbackDataPtr cbdata = opaque;
> +    virSecurityManagerPtr mgr = cbdata->manager;
> +    virSecurityLabelDefPtr secdef = cbdata->secdef;
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
>      uid_t user;
>      gid_t group;
>  
> -    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
> +    if (virSecurityDACGetIds(secdef, priv, &user, &group, NULL, NULL))
>          return -1;
>  
>      return virSecurityDACSetOwnership(file, user, group);
> @@ -475,8 +454,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
>                                        virDomainHostdevDefPtr dev,
>                                        const char *vroot)
>  {
> -    void *params[] = {mgr, def};
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityDACCallbackData cbdata;
>      int ret = -1;
>  
>      if (!priv->dynamicOwnership)
> @@ -485,7 +464,13 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
>      if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
>          return 0;
>  
> -    switch (dev->source.subsys.type) {
> +    cbdata.manager = mgr;
> +    cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +
> +    if (cbdata.secdef && cbdata.secdef->norelabel)
> +        return 0;
> +
> +    switch ((enum virDomainHostdevSubsysType) dev->source.subsys.type) {
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
>          virUSBDevicePtr usb;
>  
> @@ -498,8 +483,9 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
>          if (!usb)
>              goto done;
>  
> -        ret = virUSBDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel,
> -                                      params);
> +        ret = virUSBDeviceFileIterate(usb,
> +                                      virSecurityDACSetSecurityUSBLabel,
> +                                      &cbdata);
>          virUSBDeviceFree(usb);
>          break;
>      }
> @@ -522,11 +508,12 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
>                  virPCIDeviceFree(pci);
>                  goto done;
>              }
> -            ret = virSecurityDACSetSecurityPCILabel(pci, vfioGroupDev, params);
> +            ret = virSecurityDACSetSecurityPCILabel(pci, vfioGroupDev, &cbdata);
>              VIR_FREE(vfioGroupDev);
>          } else {
> -            ret = virPCIDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel,
> -                                          params);
> +            ret = virPCIDeviceFileIterate(pci,
> +                                          virSecurityDACSetSecurityPCILabel,
> +                                          &cbdata);
>          }
>  
>          virPCIDeviceFree(pci);
> @@ -546,15 +533,15 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
>          if (!scsi)
>              goto done;
>  
> -        ret = virSCSIDeviceFileIterate(scsi, virSecurityDACSetSecuritySCSILabel,
> -                                       params);
> +        ret = virSCSIDeviceFileIterate(scsi,
> +                                       virSecurityDACSetSecuritySCSILabel,
> +                                       &cbdata);
>          virSCSIDeviceFree(scsi);
>  
>          break;
>      }
>  
> -    default:
> -        ret = 0;
> +    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
>          break;
>      }
>  
> @@ -606,7 +593,7 @@ virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
>      if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
>          return 0;
>  
> -    switch (dev->source.subsys.type) {
> +    switch ((enum virDomainHostdevSubsysType) dev->source.subsys.type) {
>      case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
>          virUSBDevicePtr usb;
>  
> @@ -684,34 +671,52 @@ done:
>  static int
>  virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
>                                virDomainDefPtr def,
> -                              virDomainChrSourceDefPtr dev)
> +                              virDomainChrDefPtr dev,
> +                              virDomainChrSourceDefPtr dev_source)
>  
>  {
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr seclabel;
> +    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
>      char *in = NULL, *out = NULL;
>      int ret = -1;
>      uid_t user;
>      gid_t group;
>  
> -    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
> -        return -1;
> +    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
>  
> -    switch (dev->type) {
> +    if (dev)
> +        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
> +                                                          SECURITY_DAC_NAME);
> +
> +    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
> +        return 0;
> +
> +    if (chr_seclabel && chr_seclabel->label) {
> +        if (virParseOwnershipIds(chr_seclabel->label, &user, &group) < 0)
> +            return -1;
> +    } else {
> +        if (virSecurityDACGetIds(seclabel, priv, &user, &group, NULL, NULL))

Missing < 0 again.

> +            return -1;
> +    }
> +
> +    switch ((enum virDomainChrType) dev_source->type) {
>      case VIR_DOMAIN_CHR_TYPE_DEV:
>      case VIR_DOMAIN_CHR_TYPE_FILE:
> -        ret = virSecurityDACSetOwnership(dev->data.file.path, user, group);
> +        ret = virSecurityDACSetOwnership(dev_source->data.file.path,
> +                                         user, group);
>          break;
>  
>      case VIR_DOMAIN_CHR_TYPE_PIPE:
> -        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
> -            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0))
> +        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
> +            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
>              goto done;
>          if (virFileExists(in) && virFileExists(out)) {
>              if ((virSecurityDACSetOwnership(in, user, group) < 0) ||
>                  (virSecurityDACSetOwnership(out, user, group) < 0)) {
>                  goto done;
>              }
> -        } else if (virSecurityDACSetOwnership(dev->data.file.path,
> +        } else if (virSecurityDACSetOwnership(dev_source->data.file.path,
>                                                user, group) < 0) {
>              goto done;
>          }
> @@ -736,7 +741,7 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
>      char *in = NULL, *out = NULL;
>      int ret = -1;
>  
> -    switch (dev->type) {
> +    switch ((enum virDomainChrType) dev->type) {
>      case VIR_DOMAIN_CHR_TYPE_DEV:
>      case VIR_DOMAIN_CHR_TYPE_FILE:
>          ret = virSecurityDACRestoreSecurityFileLabel(dev->data.file.path);
> @@ -789,7 +794,7 @@ virSecurityDACSetSecurityTPMFileLabel(virSecurityManagerPtr mgr,
>  
>      switch (tpm->type) {
>      case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> -        ret = virSecurityDACSetChardevLabel(mgr, def,
> +        ret = virSecurityDACSetChardevLabel(mgr, def, NULL,
>                                              &tpm->data.passthrough.source);
>          break;
>      case VIR_DOMAIN_TPM_TYPE_LAST:
> @@ -885,7 +890,7 @@ virSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
>  {
>      virSecurityManagerPtr mgr = opaque;
>  
> -    return virSecurityDACSetChardevLabel(mgr, def, &dev->source);
> +    return virSecurityDACSetChardevLabel(mgr, def, dev,  &dev->source);

s/,  /, /

>  }
>  
>  
> @@ -895,13 +900,17 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
>                                    const char *stdin_path ATTRIBUTE_UNUSED)
>  {
>      virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr secdef;
>      size_t i;
>      uid_t user;
>      gid_t group;
>  
> -    if (!priv->dynamicOwnership)
> +    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +
> +    if (!priv->dynamicOwnership || (secdef && secdef->norelabel))
>          return 0;
>  
> +

Leftover empty line.

>      for (i = 0; i < def->ndisks; i++) {
>          /* XXX fixme - we need to recursively label the entire tree :-( */
>          if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR)
> @@ -932,7 +941,7 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
>              return -1;
>      }
>  
> -    if (virSecurityDACGetImageIds(def, priv, &user, &group))
> +    if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
>          return -1;
>  
>      if (def->os.kernel &&
> @@ -956,11 +965,14 @@ virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
>                                   virDomainDefPtr def,
>                                   const char *savefile)
>  {
> +    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr secdef;
>      uid_t user;
>      gid_t group;
> -    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
>  
> -    if (virSecurityDACGetImageIds(def, priv, &user, &group))
> +    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +
> +    if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
>          return -1;
>  
>      return virSecurityDACSetOwnership(savefile, user, group);
> @@ -985,13 +997,16 @@ static int
>  virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
>                                virDomainDefPtr def ATTRIBUTE_UNUSED)
>  {
> +    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr secdef;
>      uid_t user;
>      gid_t group;
>      gid_t *groups;
>      int ngroups;
> -    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
>  
> -    if (virSecurityDACGetIds(def, priv, &user, &group, &groups, &ngroups))
> +    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +
> +    if (virSecurityDACGetIds(secdef, priv, &user, &group, &groups, &ngroups))
>          return -1;
>  
>      VIR_DEBUG("Dropping privileges of DEF to %u:%u, %d supplemental groups",
> @@ -1009,11 +1024,14 @@ virSecurityDACSetChildProcessLabel(virSecurityManagerPtr mgr,
>                                     virDomainDefPtr def ATTRIBUTE_UNUSED,
>                                     virCommandPtr cmd)
>  {
> +    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
> +    virSecurityLabelDefPtr secdef;
>      uid_t user;
>      gid_t group;
> -    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
>  
> -    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
> +    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
> +
> +    if (virSecurityDACGetIds(secdef, priv, &user, &group, NULL, NULL))
>          return -1;
>  
>      VIR_DEBUG("Setting child to drop privileges of DEF to %u:%u",

The patch looks correct, although I'd be more confident about its
correctness if it was split into more patches doing one thing at a time.

Jirka




More information about the libvir-list mailing list