[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