[libvirt] [PATCHv3] security: Don't ignore errors when parsing DAC security labels

The DAC security driver silently ignored errors when parsing the DAC label and used default values instead. With a domain containing the following label definition: <seclabel type='static' model='dac' relabel='yes'> <label>sdfklsdjlfjklsdjkl</label> </seclabel> the domain would start normaly but the disk images would be still owned by root and no error was displayed. This patch changes the behavior if the parsing of the label fails (note that a not present label is not a failure and in this case the default label should be used) the error isn't masked but is raised that causes the domain start to fail with a descriptive error message: virsh # start tr error: Failed to start domain tr error: internal error invalid argument: failed to parse DAC label 'sdfklsdjlfjklsdjkl' for domain 'tr' I also changed the error code to "invalid argument" from "internal error" and tweaked the various error messages to contain correct and useful information. --- Diff to v2: - Fixed all error reporting paths to contain useful messages - Tweaked error messages to contain more information - Fixed printing of seclabel->label instead of seclabel->imagelabel in the imagelabel parsing func. src/security/security_dac.c | 95 +++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 211fb37..be65d6e 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -90,6 +90,7 @@ int parseIds(const char *label, uid_t *uidPtr, gid_t *gidPtr) return 0; } +/* returns 1 if label isn't found, 0 on success, -1 on error */ static int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) { @@ -98,20 +99,18 @@ int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) virSecurityLabelDefPtr seclabel; if (def == NULL) - return -1; + return 1; seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); if (seclabel == NULL || seclabel->label == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("security label for DAC not found in domain %s"), - def->name); - return -1; + VIR_DEBUG("DAC seclabel for domain '%s' wasn't found", def->name); + return 1; } if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse uid and gid for DAC " - "security driver: %s"), seclabel->label); + virReportError(VIR_ERR_INVALID_ARG, + _("failed to parse DAC label '%s' for domain '%s'"), + seclabel->label, def->name); return -1; } @@ -127,19 +126,35 @@ static int virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv, uid_t *uidPtr, gid_t *gidPtr) { - if (virSecurityDACParseIds(def, uidPtr, gidPtr) == 0) - return 0; + int ret; - if (priv) { - if (uidPtr) - *uidPtr = priv->user; - if (gidPtr) - *gidPtr = priv->group; - return 0; + if (!def && !priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to determine default DAC label " + "for an unknown object")); + return -1; } - return -1; + + if ((ret = virSecurityDACParseIds(def, uidPtr, gidPtr)) <= 0) + return ret; + + if (!priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("DAC security label couldn't be determined " + "for domain '%s'"), def->name); + return -1; + } + + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + + return 0; } + +/* returns 1 if label isn't found, 0 on success, -1 on error */ static int virSecurityDACParseImageIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) @@ -149,21 +164,19 @@ int virSecurityDACParseImageIds(virDomainDefPtr def, virSecurityLabelDefPtr seclabel; if (def == NULL) - return -1; + return 1; seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); if (seclabel == NULL || seclabel->imagelabel == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("security label for DAC not found in domain %s"), - def->name); - return -1; + VIR_DEBUG("DAC imagelabel for domain '%s' wasn't found", def->name); + return 1; } if (seclabel->imagelabel && parseIds(seclabel->imagelabel, &uid, &gid)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse uid and gid for DAC " - "security driver: %s"), seclabel->label); + virReportError(VIR_ERR_INVALID_ARG, + _("failed to parse DAC imagelabel '%s' for domain '%s'"), + seclabel->imagelabel, def->name); return -1; } @@ -179,17 +192,31 @@ static int virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv, uid_t *uidPtr, gid_t *gidPtr) { - if (virSecurityDACParseImageIds(def, uidPtr, gidPtr) == 0) - return 0; + int ret; - if (priv) { - if (uidPtr) - *uidPtr = priv->user; - if (gidPtr) - *gidPtr = priv->group; - return 0; + 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) + return ret; + + if (!priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("DAC security imagelabel couldn't be determined " + "for domain '%s'"), def->name); + return -1; } - return -1; + + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + + return 0; } -- 1.7.12

On 09/19/2012 02:42 PM, Peter Krempa wrote:
The DAC security driver silently ignored errors when parsing the DAC label and used default values instead.
With a domain containing the following label definition:
<seclabel type='static' model='dac' relabel='yes'> <label>sdfklsdjlfjklsdjkl</label> </seclabel>
the domain would start normaly but the disk images would be still owned by root and no error was displayed.
This patch changes the behavior if the parsing of the label fails (note that a not present label is not a failure and in this case the default label should be used) the error isn't masked but is raised that causes the domain start to fail with a descriptive error message:
virsh # start tr error: Failed to start domain tr error: internal error invalid argument: failed to parse DAC label 'sdfklsdjlfjklsdjkl' for domain 'tr'
I also changed the error code to "invalid argument" from "internal error" and tweaked the various error messages to contain correct and useful information. --- Diff to v2: - Fixed all error reporting paths to contain useful messages - Tweaked error messages to contain more information - Fixed printing of seclabel->label instead of seclabel->imagelabel in the imagelabel parsing func.
src/security/security_dac.c | 95 +++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 34 deletions(-)
diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 211fb37..be65d6e 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -90,6 +90,7 @@ int parseIds(const char *label, uid_t *uidPtr, gid_t *gidPtr) return 0; }
+/* returns 1 if label isn't found, 0 on success, -1 on error */ static int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) { @@ -98,20 +99,18 @@ int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) virSecurityLabelDefPtr seclabel;
if (def == NULL) - return -1; + return 1;
seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); if (seclabel == NULL || seclabel->label == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("security label for DAC not found in domain %s"), - def->name); - return -1; + VIR_DEBUG("DAC seclabel for domain '%s' wasn't found", def->name);
You use "seclabel" here, ...
+ return 1; }
if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse uid and gid for DAC " - "security driver: %s"), seclabel->label); + virReportError(VIR_ERR_INVALID_ARG, + _("failed to parse DAC label '%s' for domain '%s'"),
... "label" here ...
+ seclabel->label, def->name); return -1; }
@@ -127,19 +126,35 @@ static int virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv, uid_t *uidPtr, gid_t *gidPtr) { - if (virSecurityDACParseIds(def, uidPtr, gidPtr) == 0) - return 0; + int ret;
- if (priv) { - if (uidPtr) - *uidPtr = priv->user; - if (gidPtr) - *gidPtr = priv->group; - return 0; + if (!def && !priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to determine default DAC label "
... and here ...
+ "for an unknown object")); + return -1; } - return -1; + + if ((ret = virSecurityDACParseIds(def, uidPtr, gidPtr)) <= 0) + return ret; + + if (!priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("DAC security label couldn't be determined "
..., but "security label" here.
+ "for domain '%s'"), def->name); + return -1; + } + + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + + return 0; }
+ +/* returns 1 if label isn't found, 0 on success, -1 on error */ static int virSecurityDACParseImageIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr) @@ -149,21 +164,19 @@ int virSecurityDACParseImageIds(virDomainDefPtr def, virSecurityLabelDefPtr seclabel;
if (def == NULL) - return -1; + return 1;
seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME); if (seclabel == NULL || seclabel->imagelabel == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("security label for DAC not found in domain %s"), - def->name); - return -1; + VIR_DEBUG("DAC imagelabel for domain '%s' wasn't found", def->name); + return 1; }
if (seclabel->imagelabel && parseIds(seclabel->imagelabel, &uid, &gid)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse uid and gid for DAC " - "security driver: %s"), seclabel->label); + virReportError(VIR_ERR_INVALID_ARG, + _("failed to parse DAC imagelabel '%s' for domain '%s'"), + seclabel->imagelabel, def->name); return -1; }
@@ -179,17 +192,31 @@ static int virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv, uid_t *uidPtr, gid_t *gidPtr) { - if (virSecurityDACParseImageIds(def, uidPtr, gidPtr) == 0) - return 0; + int ret;
- if (priv) { - if (uidPtr) - *uidPtr = priv->user; - if (gidPtr) - *gidPtr = priv->group; - return 0; + 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) + return ret; + + if (!priv) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("DAC security imagelabel couldn't be determined "
And here you have "security imagelabel" as opposed to the other "imagelabel"-only messages.
+ "for domain '%s'"), def->name); + return -1; } - return -1; + + if (uidPtr) + *uidPtr = priv->user; + if (gidPtr) + *gidPtr = priv->group; + + return 0; }
Code seems fine, though, so ACK with unifying those messages. I suggest either "seclabel" and "imagelabel" OR 'security label" and "security imagelabel", whatever you think suits the error and XML better, but one for all errors with the same label. Martin

On 09/20/12 16:04, Martin Kletzander wrote:
On 09/19/2012 02:42 PM, Peter Krempa wrote:
The DAC security driver silently ignored errors when parsing the DAC label and used default values instead.
With a domain containing the following label definition:
<seclabel type='static' model='dac' relabel='yes'> <label>sdfklsdjlfjklsdjkl</label> </seclabel>
the domain would start normaly but the disk images would be still owned by root and no error was displayed.
This patch changes the behavior if the parsing of the label fails (note that a not present label is not a failure and in this case the default label should be used) the error isn't masked but is raised that causes the domain start to fail with a descriptive error message:
virsh # start tr error: Failed to start domain tr error: internal error invalid argument: failed to parse DAC label 'sdfklsdjlfjklsdjkl' for domain 'tr'
I also changed the error code to "invalid argument" from "internal error" and tweaked the various error messages to contain correct and useful information. --- Diff to v2: - Fixed all error reporting paths to contain useful messages - Tweaked error messages to contain more information - Fixed printing of seclabel->label instead of seclabel->imagelabel in the imagelabel parsing func.
src/security/security_dac.c | 95 +++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 34 deletions(-)
...
Code seems fine, though, so ACK with unifying those messages. I suggest either "seclabel" and "imagelabel" OR 'security label" and "security imagelabel", whatever you think suits the error and XML better, but one for all errors with the same label.
I've gone with the first option and pushed the patch. Thanks for the review. Peter
participants (2)
-
Martin Kletzander
-
Peter Krempa