security_dac: Remember old labels

This also requires the same DAC label to be used for shared
paths. If a path is already in use by a domain (or domains) then
and the domain we are starting now wants to access the path it
has to have the same DAC label. This might look too restrictive
as the new label can still guarantee access to already running
domains but in reality it is very unlikely and usually an admin
mistake.

This requirement also simplifies seclabel remembering, because we
can store only one seclabel and have a refcounter for how many
times the path is in use. If we were to allow different labels
and store them in some sort of array the algorithm to match
labels to domains would be needlessly complicated.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Michal Privoznik 2018-08-06 12:14:52 +02:00
parent fa808763b2
commit 1845d3ad5d

View File

@ -29,6 +29,7 @@
#endif
#include "security_dac.h"
#include "security_util.h"
#include "virerror.h"
#include "virfile.h"
#include "viralloc.h"
@ -411,15 +412,26 @@ virSecurityDACGetImageIds(virSecurityLabelDefPtr seclabel,
*
* Remember the owner of @path (represented by @uid:@gid).
*
* Returns: 0 on success, -1 on failure
* Returns: the @path refcount, or
* -1 on failure
*/
static int
virSecurityDACRememberLabel(virSecurityDACDataPtr priv ATTRIBUTE_UNUSED,
const char *path ATTRIBUTE_UNUSED,
uid_t uid ATTRIBUTE_UNUSED,
gid_t gid ATTRIBUTE_UNUSED)
const char *path,
uid_t uid,
gid_t gid)
{
return 0;
char *label = NULL;
int ret = -1;
if (virAsprintf(&label, "+%u:+%u",
(unsigned int)uid,
(unsigned int)gid) < 0)
return -1;
ret = virSecuritySetRememberedLabel(SECURITY_DAC_NAME, path, label);
VIR_FREE(label);
return ret;
}
/**
@ -439,11 +451,27 @@ virSecurityDACRememberLabel(virSecurityDACDataPtr priv ATTRIBUTE_UNUSED,
*/
static int
virSecurityDACRecallLabel(virSecurityDACDataPtr priv ATTRIBUTE_UNUSED,
const char *path ATTRIBUTE_UNUSED,
uid_t *uid ATTRIBUTE_UNUSED,
gid_t *gid ATTRIBUTE_UNUSED)
const char *path,
uid_t *uid,
gid_t *gid)
{
return 0;
char *label;
int ret = -1;
if (virSecurityGetRememberedLabel(SECURITY_DAC_NAME,
path, &label) < 0)
goto cleanup;
if (!label)
return 1;
if (virParseOwnershipIds(label, uid, gid) < 0)
goto cleanup;
ret = 0;
cleanup:
VIR_FREE(label);
return ret;
}
static virSecurityDriverStatus
@ -709,6 +737,7 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
{
virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
struct stat sb;
int refcount;
int rc;
if (!path && src && src->path &&
@ -729,8 +758,22 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
return -1;
}
if (virSecurityDACRememberLabel(priv, path, sb.st_uid, sb.st_gid) < 0)
refcount = virSecurityDACRememberLabel(priv, path, sb.st_uid, sb.st_gid);
if (refcount < 0) {
return -1;
} else if (refcount > 1) {
/* Refcount is greater than 1 which means that there
* is @refcount domains using the @path. Do not
* change the label (as it would almost certainly
* cause the other domains to lose access to the
* @path). */
if (sb.st_uid != uid || sb.st_gid != gid) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("Setting different DAC user or group on %s "
"which is already in use"), path);
return -1;
}
}
}
VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",