[libvirt] [PATCH] security: chown/label bidrectional and unidirectional fifos

This patch fixes the regression with using named pipes for qemu serial devices noted in: https://bugzilla.redhat.com/show_bug.cgi?id=740478 The problem was that, while new code in libvirt looks for a single bidirectional fifo of the name given in the config, then relabels that and continues without looking for / relabelling the two unidirectional fifos named ${name}.in and ${name}.out, qemu looks in the opposite order. So if the user had naively created all three fifos, libvirt would relabel the bidirectional fifo to allow qemu access, but qemu would attempt to use the two unidirectional fifos and fail (because it didn't have proper permissions/rights). The solution implemented here is to always look for and chown/relabel both types of fifos, then let qemu decide which one it wants to use (in the unusual case that both are present). If one of the types is present, libvirt will silently ignore when the other type is missing (since that will be the most common case), but if neither type is present, there will be an error logged about failing to relabel/chown one of the bidirectional pipes. (Likewise, if one direction of the unidirectional pipes is present but the other is missing, this will also result in an error log). (Note commit d37c6a3a (which first appeared in libvirt-0.9.2) added the code that checked for a bidirectional fifo. Prior to that commit, bidirectional fifos fdor serial devices didn't work unless the fifo was pre-owned/labelled such that qemu could access it.) --- src/security/security_dac.c | 39 ++++++++++++++++++++++++++++++--------- src/security/security_selinux.c | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index af02236..f97d2d6 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -397,6 +397,7 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, { virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1; switch (dev->type) { @@ -406,19 +407,28 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, break; case VIR_DOMAIN_CHR_TYPE_PIPE: + /* look for / chown both bidirectional pipe and dual uni-directional + * pipes if found; let the hypervisor decide which to use. + */ if (virFileExists(dev->data.file.path)) { + found_bipipe = true; if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group) < 0) goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } - if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) - goto done; } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (found_bipipe && + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } + if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || + (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) + goto done; + ret = 0; break; @@ -438,6 +448,7 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainChrSourceDefPtr dev) { char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1; switch (dev->type) { @@ -447,11 +458,21 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, break; case VIR_DOMAIN_CHR_TYPE_PIPE: + if (virFileExists(dev->data.file.path)) { + found_bipipe = true; + if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) + goto done; + } if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) || (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) { virReportOOMError(); goto done; } + if (found_bipipe && + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) || (virSecurityDACRestoreSecurityFileLabel(in) < 0)) goto done; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0807a34..e7a18a6 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -794,6 +794,7 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1; if (secdef->norelabel) @@ -806,19 +807,28 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, break; case VIR_DOMAIN_CHR_TYPE_PIPE: + /* look for / chown both bidirectional pipe and dual uni-directional + * pipes if found; let the hypervisor decide which to use. + */ if (virFileExists(dev->data.file.path)) { + found_bipipe = true; if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } - if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) || - (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) - goto done; } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (found_bipipe && + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } + if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) || + (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) + goto done; + ret = 0; break; @@ -840,6 +850,7 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1; if (secdef->norelabel) @@ -853,11 +864,21 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, ret = 0; break; case VIR_DOMAIN_CHR_TYPE_PIPE: + if (virFileExists(dev->data.file.path)) { + found_bipipe = true; + if (SELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) + goto done; + } if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) || (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) { virReportOOMError(); goto done; } + if (found_bipipe && + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } if ((SELinuxRestoreSecurityFileLabel(out) < 0) || (SELinuxRestoreSecurityFileLabel(in) < 0)) goto done; -- 1.7.3.4

Sigh. I just looked at my bugzilla mail backlog and saw that this morning Dan Berrange voted for the simpler method of fixing this, but I didn't notice it before implementing this patch. I'll be back shortly with a v2 that does it the other way. On 09/27/2011 02:36 PM, Laine Stump wrote:
This patch fixes the regression with using named pipes for qemu serial devices noted in:
https://bugzilla.redhat.com/show_bug.cgi?id=740478
The problem was that, while new code in libvirt looks for a single bidirectional fifo of the name given in the config, then relabels that and continues without looking for / relabelling the two unidirectional fifos named ${name}.in and ${name}.out, qemu looks in the opposite order. So if the user had naively created all three fifos, libvirt would relabel the bidirectional fifo to allow qemu access, but qemu would attempt to use the two unidirectional fifos and fail (because it didn't have proper permissions/rights).
The solution implemented here is to always look for and chown/relabel both types of fifos, then let qemu decide which one it wants to use (in the unusual case that both are present). If one of the types is present, libvirt will silently ignore when the other type is missing (since that will be the most common case), but if neither type is present, there will be an error logged about failing to relabel/chown one of the bidirectional pipes. (Likewise, if one direction of the unidirectional pipes is present but the other is missing, this will also result in an error log).
(Note commit d37c6a3a (which first appeared in libvirt-0.9.2) added the code that checked for a bidirectional fifo. Prior to that commit, bidirectional fifos fdor serial devices didn't work unless the fifo was pre-owned/labelled such that qemu could access it.) --- src/security/security_dac.c | 39 ++++++++++++++++++++++++++++++--------- src/security/security_selinux.c | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 18 deletions(-)
diff --git a/src/security/security_dac.c b/src/security/security_dac.c index af02236..f97d2d6 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -397,6 +397,7 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, { virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr); char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1;
switch (dev->type) { @@ -406,19 +407,28 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: + /* look for / chown both bidirectional pipe and dual uni-directional + * pipes if found; let the hypervisor decide which to use. + */ if (virFileExists(dev->data.file.path)) { + found_bipipe = true; if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group)< 0) goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { - virReportOOMError(); - goto done; - } - if ((virSecurityDACSetOwnership(in, priv->user, priv->group)< 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group)< 0)) - goto done; } + if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { + virReportOOMError(); + goto done; + } + if (found_bipipe&& + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } + if ((virSecurityDACSetOwnership(in, priv->user, priv->group)< 0) || + (virSecurityDACSetOwnership(out, priv->user, priv->group)< 0)) + goto done; + ret = 0; break;
@@ -438,6 +448,7 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainChrSourceDefPtr dev) { char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1;
switch (dev->type) { @@ -447,11 +458,21 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: + if (virFileExists(dev->data.file.path)) { + found_bipipe = true; + if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path)< 0) + goto done; + } if ((virAsprintf(&out, "%s.out", dev->data.file.path)< 0) || (virAsprintf(&in, "%s.in", dev->data.file.path)< 0)) { virReportOOMError(); goto done; } + if (found_bipipe&& + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } if ((virSecurityDACRestoreSecurityFileLabel(out)< 0) || (virSecurityDACRestoreSecurityFileLabel(in)< 0)) goto done; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0807a34..e7a18a6 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -794,6 +794,7 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, { const virSecurityLabelDefPtr secdef =&vm->def->seclabel; char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1;
if (secdef->norelabel) @@ -806,19 +807,28 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: + /* look for / chown both bidirectional pipe and dual uni-directional + * pipes if found; let the hypervisor decide which to use. + */ if (virFileExists(dev->data.file.path)) { + found_bipipe = true; if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel)< 0) goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { - virReportOOMError(); - goto done; - } - if ((SELinuxSetFilecon(in, secdef->imagelabel)< 0) || - (SELinuxSetFilecon(out, secdef->imagelabel)< 0)) - goto done; } + if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { + virReportOOMError(); + goto done; + } + if (found_bipipe&& + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } + if ((SELinuxSetFilecon(in, secdef->imagelabel)< 0) || + (SELinuxSetFilecon(out, secdef->imagelabel)< 0)) + goto done; + ret = 0; break;
@@ -840,6 +850,7 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, { const virSecurityLabelDefPtr secdef =&vm->def->seclabel; char *in = NULL, *out = NULL; + bool found_bipipe = false; int ret = -1;
if (secdef->norelabel) @@ -853,11 +864,21 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, ret = 0; break; case VIR_DOMAIN_CHR_TYPE_PIPE: + if (virFileExists(dev->data.file.path)) { + found_bipipe = true; + if (SELinuxRestoreSecurityFileLabel(dev->data.file.path)< 0) + goto done; + } if ((virAsprintf(&out, "%s.out", dev->data.file.path)< 0) || (virAsprintf(&in, "%s.in", dev->data.file.path)< 0)) { virReportOOMError(); goto done; } + if (found_bipipe&& + !(virFileExists(in) || virFileExists(out))) { + ret = 0; + goto done; + } if ((SELinuxRestoreSecurityFileLabel(out)< 0) || (SELinuxRestoreSecurityFileLabel(in)< 0)) goto done;

(v2: change to only relabel the uni-direction fifo pair if they're found, otherwise only relabel the bidirectional fifo, per comment in BZ by Dan Berrange) This patch fixes the regression with using named pipes for qemu serial devices noted in: https://bugzilla.redhat.com/show_bug.cgi?id=740478 The problem was that, while new code in libvirt looks for a single bidirectional fifo of the name given in the config, then relabels that and continues without looking for / relabelling the two unidirectional fifos named ${name}.in and ${name}.out, qemu looks in the opposite order. So if the user had naively created all three fifos, libvirt would relabel the bidirectional fifo to allow qemu access, but qemu would attempt to use the two unidirectional fifos and fail (because it didn't have proper permissions/rights). This patch changes the order that libvirt looks for the fifos to match what qemu does - first it looks for the dual fifos, then it looks for the single bidirectional fifo. If it finds the dual unidirectional fifos first, it labels/chowns them and ignores any possible bidirectional fifo. (Note commit d37c6a3a (which first appeared in libvirt-0.9.2) added the code that checked for a bidirectional fifo. Prior to that commit, bidirectional fifos fdor serial devices didn't work unless the fifo was pre-owned/labelled such that qemu could access it.) --- src/security/security_dac.c | 30 ++++++++++++++++++------------ src/security/security_selinux.c | 29 +++++++++++++++++------------ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index af02236..ac79e70 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -406,18 +406,19 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, break; case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group) < 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) { if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) + (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) { goto done; + } + } else if (virSecurityDACSetOwnership(dev->data.file.path, + priv->user, priv->group) < 0) { + goto done; } ret = 0; break; @@ -452,9 +453,14 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virReportOOMError(); goto done; } - if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) || - (virSecurityDACRestoreSecurityFileLabel(in) < 0)) + if (virFileExists(in) || virFileExists(out)) { + if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) || + (virSecurityDACRestoreSecurityFileLabel(in) < 0)) { goto done; + } + } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) { + goto done; + } ret = 0; break; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0807a34..9e5b668 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -806,18 +806,18 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, break; case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) { if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) || - (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) + (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) { goto done; + } + } else if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) { + goto done; } ret = 0; break; @@ -858,9 +858,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, virReportOOMError(); goto done; } - if ((SELinuxRestoreSecurityFileLabel(out) < 0) || - (SELinuxRestoreSecurityFileLabel(in) < 0)) + if (virFileExists(in) || virFileExists(out)) { + if ((SELinuxRestoreSecurityFileLabel(out) < 0) || + (SELinuxRestoreSecurityFileLabel(in) < 0)) { + goto done; + } + } else if (SELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) { goto done; + } ret = 0; break; -- 1.7.3.4

On Tue, Sep 27, 2011 at 09:00:15PM -0400, Laine Stump wrote:
(v2: change to only relabel the uni-direction fifo pair if they're found, otherwise only relabel the bidirectional fifo, per comment in BZ by Dan Berrange)
This patch fixes the regression with using named pipes for qemu serial devices noted in:
https://bugzilla.redhat.com/show_bug.cgi?id=740478
The problem was that, while new code in libvirt looks for a single bidirectional fifo of the name given in the config, then relabels that and continues without looking for / relabelling the two unidirectional fifos named ${name}.in and ${name}.out, qemu looks in the opposite order. So if the user had naively created all three fifos, libvirt would relabel the bidirectional fifo to allow qemu access, but qemu would attempt to use the two unidirectional fifos and fail (because it didn't have proper permissions/rights).
This patch changes the order that libvirt looks for the fifos to match what qemu does - first it looks for the dual fifos, then it looks for the single bidirectional fifo. If it finds the dual unidirectional fifos first, it labels/chowns them and ignores any possible bidirectional fifo.
(Note commit d37c6a3a (which first appeared in libvirt-0.9.2) added the code that checked for a bidirectional fifo. Prior to that commit, bidirectional fifos fdor serial devices didn't work unless the fifo was pre-owned/labelled such that qemu could access it.) --- src/security/security_dac.c | 30 ++++++++++++++++++------------ src/security/security_selinux.c | 29 +++++++++++++++++------------ 2 files changed, 35 insertions(+), 24 deletions(-)
diff --git a/src/security/security_dac.c b/src/security/security_dac.c index af02236..ac79e70 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -406,18 +406,19 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group) < 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) {
Actually the qemu code of qemu_chr_open_pipe() does if (fd_in < 0 || fd_out < 0) { close either if they opened and try to open the main file so the logic in libvirt should be if (virFileExists(in) && virFileExists(out)) {
if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) + (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) { goto done; + } + } else if (virSecurityDACSetOwnership(dev->data.file.path, + priv->user, priv->group) < 0) { + goto done; } ret = 0; break; @@ -452,9 +453,14 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virReportOOMError(); goto done; } - if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) || - (virSecurityDACRestoreSecurityFileLabel(in) < 0)) + if (virFileExists(in) || virFileExists(out)) {
Same
+ if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) || + (virSecurityDACRestoreSecurityFileLabel(in) < 0)) { goto done; + } + } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) { + goto done; + } ret = 0; break;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0807a34..9e5b668 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -806,18 +806,18 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) {
Same
if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) || - (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) + (SELinuxSetFilecon(out, secdef->imagelabel) < 0)) { goto done; + } + } else if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) { + goto done; } ret = 0; break; @@ -858,9 +858,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, virReportOOMError(); goto done; } - if ((SELinuxRestoreSecurityFileLabel(out) < 0) || - (SELinuxRestoreSecurityFileLabel(in) < 0)) + if (virFileExists(in) || virFileExists(out)) {
And same,
+ if ((SELinuxRestoreSecurityFileLabel(out) < 0) || + (SELinuxRestoreSecurityFileLabel(in) < 0)) { + goto done; + } + } else if (SELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) { goto done; + } ret = 0; break;
That bug got me a bit crazy, I would like to get it fixed :) ACK conditionned on the above four || replaced by && Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

Hello, I reproduced the symptoms (no output from designated pipe, guest hang after a while) with commit 05e2fc51, and with commit c7d1f598 they are gone. I also noticed libvirt needs to be built with --with-qemu-user=<user> --with-qemu-group=<group> to reproduce the symptoms, with older code, or the qemu process will be running as root and can write to un-chown'ed pipe. On 09/28/2011 03:01 PM, Daniel Veillard wrote:
On Tue, Sep 27, 2011 at 09:00:15PM -0400, Laine Stump wrote:
(v2: change to only relabel the uni-direction fifo pair if they're found, otherwise only relabel the bidirectional fifo, per comment in BZ by Dan Berrange)
This patch fixes the regression with using named pipes for qemu serial devices noted in:
https://bugzilla.redhat.com/show_bug.cgi?id=740478
The problem was that, while new code in libvirt looks for a single bidirectional fifo of the name given in the config, then relabels that and continues without looking for / relabelling the two unidirectional fifos named ${name}.in and ${name}.out, qemu looks in the opposite order. So if the user had naively created all three fifos, libvirt would relabel the bidirectional fifo to allow qemu access, but qemu would attempt to use the two unidirectional fifos and fail (because it didn't have proper permissions/rights).
This patch changes the order that libvirt looks for the fifos to match what qemu does - first it looks for the dual fifos, then it looks for the single bidirectional fifo. If it finds the dual unidirectional fifos first, it labels/chowns them and ignores any possible bidirectional fifo.
(Note commit d37c6a3a (which first appeared in libvirt-0.9.2) added the code that checked for a bidirectional fifo. Prior to that commit, bidirectional fifos fdor serial devices didn't work unless the fifo was pre-owned/labelled such that qemu could access it.) --- src/security/security_dac.c | 30 ++++++++++++++++++------------ src/security/security_selinux.c | 29 +++++++++++++++++------------ 2 files changed, 35 insertions(+), 24 deletions(-)
diff --git a/src/security/security_dac.c b/src/security/security_dac.c index af02236..ac79e70 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -406,18 +406,19 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group)< 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) {
Actually the qemu code of qemu_chr_open_pipe() does if (fd_in< 0 || fd_out< 0) { close either if they opened and try to open the main file so the logic in libvirt should be
if (virFileExists(in)&& virFileExists(out)) {
if ((virSecurityDACSetOwnership(in, priv->user, priv->group)< 0) || - (virSecurityDACSetOwnership(out, priv->user, priv->group)< 0)) + (virSecurityDACSetOwnership(out, priv->user, priv->group)< 0)) { goto done; + } + } else if (virSecurityDACSetOwnership(dev->data.file.path, + priv->user, priv->group)< 0) { + goto done; } ret = 0; break; @@ -452,9 +453,14 @@ virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virReportOOMError(); goto done; } - if ((virSecurityDACRestoreSecurityFileLabel(out)< 0) || - (virSecurityDACRestoreSecurityFileLabel(in)< 0)) + if (virFileExists(in) || virFileExists(out)) {
Same
+ if ((virSecurityDACRestoreSecurityFileLabel(out)< 0) || + (virSecurityDACRestoreSecurityFileLabel(in)< 0)) { goto done; + } + } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path)< 0) { + goto done; + } ret = 0; break;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 0807a34..9e5b668 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -806,18 +806,18 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, break;
case VIR_DOMAIN_CHR_TYPE_PIPE: - if (virFileExists(dev->data.file.path)) { - if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel)< 0) - goto done; - } else { - if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || - (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { - virReportOOMError(); - goto done; - } + if ((virAsprintf(&in, "%s.in", dev->data.file.path)< 0) || + (virAsprintf(&out, "%s.out", dev->data.file.path)< 0)) { + virReportOOMError(); + goto done; + } + if (virFileExists(in) || virFileExists(out)) {
Same
if ((SELinuxSetFilecon(in, secdef->imagelabel)< 0) || - (SELinuxSetFilecon(out, secdef->imagelabel)< 0)) + (SELinuxSetFilecon(out, secdef->imagelabel)< 0)) { goto done; + } + } else if (SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel)< 0) { + goto done; } ret = 0; break; @@ -858,9 +858,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, virReportOOMError(); goto done; } - if ((SELinuxRestoreSecurityFileLabel(out)< 0) || - (SELinuxRestoreSecurityFileLabel(in)< 0)) + if (virFileExists(in) || virFileExists(out)) {
And same,
+ if ((SELinuxRestoreSecurityFileLabel(out)< 0) || + (SELinuxRestoreSecurityFileLabel(in)< 0)) { + goto done; + } + } else if (SELinuxRestoreSecurityFileLabel(dev->data.file.path)< 0) { goto done; + } ret = 0; break;
That bug got me a bit crazy, I would like to get it fixed :)
ACK conditionned on the above four || replaced by&&
Daniel
-- Thanks. Hong Xiang
participants (3)
-
Daniel Veillard
-
Hong Xiang
-
Laine Stump