Add support for setting socket MLS level in SELinux driver

When SELinux is running in MLS mode, libvirtd will have a
different security level to the VMs. For libvirtd to be
able to connect to the monitor console, the client end of
the UNIX domain socket needs a different label. This adds
infrastructure to set the socket label via the security
driver framework

* src/qemu/qemu_driver.c: Call out to socket label APIs in
  security driver
* src/qemu/qemu_security_stacked.c: Wire up socket label
  drivers
* src/security/security_driver.h: Define security driver
  entry points for socket labelling
* src/security/security_selinux.c: Set socket label based on
  VM label
This commit is contained in:
Daniel J Walsh 2010-05-27 16:44:47 +01:00 committed by Daniel P. Berrange
parent 3bb3743934
commit e72cc3c11d
4 changed files with 176 additions and 2 deletions

View File

@ -1186,27 +1186,44 @@ static int
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret;
int ret = -1;
/* Hold an extra reference because we can't allow 'vm' to be
* deleted while the monitor is active */
virDomainObjRef(vm);
if ((driver->securityDriver &&
driver->securityDriver->domainSetSecuritySocketLabel &&
driver->securityDriver->domainSetSecuritySocketLabel(driver->securityDriver,vm)) < 0) {
VIR_ERROR(_("Failed to set security context for monitor for %s"), vm->def->name);
goto error;
}
if ((priv->mon = qemuMonitorOpen(vm,
priv->monConfig,
priv->monJSON,
&monitorCallbacks)) == NULL) {
VIR_ERROR(_("Failed to connect monitor for %s"), vm->def->name);
return -1;
goto error;
}
if ((driver->securityDriver &&
driver->securityDriver->domainClearSecuritySocketLabel &&
driver->securityDriver->domainClearSecuritySocketLabel(driver->securityDriver,vm)) < 0) {
VIR_ERROR(_("Failed to set security context for monitor for %s"), vm->def->name);
goto error;
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorSetCapabilities(priv->mon);
qemuDomainObjExitMonitorWithDriver(driver, vm);
ret = 0;
error:
if (ret < 0) {
qemuMonitorClose(priv->mon);
priv->mon = NULL;
virDomainObjUnref(vm);
}
return ret;

View File

@ -310,6 +310,51 @@ qemuSecurityStackedGetProcessLabel(virDomainObjPtr vm,
return rc;
}
static int
qemuSecurityStackedSetSocketLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
virDomainObjPtr vm)
{
int rc = 0;
if (driver->securityPrimaryDriver &&
driver->securityPrimaryDriver->domainSetSecuritySocketLabel &&
driver->securityPrimaryDriver->domainSetSecuritySocketLabel(driver->securityPrimaryDriver,
vm) < 0)
rc = -1;
if (driver->securitySecondaryDriver &&
driver->securitySecondaryDriver->domainSetSecuritySocketLabel &&
driver->securitySecondaryDriver->domainSetSecuritySocketLabel(driver->securitySecondaryDriver,
vm) < 0)
rc = -1;
return rc;
}
static int
qemuSecurityStackedClearSocketLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
virDomainObjPtr vm)
{
int rc = 0;
if (driver->securitySecondaryDriver &&
driver->securitySecondaryDriver->domainClearSecuritySocketLabel &&
driver->securitySecondaryDriver->domainClearSecuritySocketLabel(driver->securitySecondaryDriver,
vm) < 0)
rc = -1;
if (driver->securityPrimaryDriver &&
driver->securityPrimaryDriver->domainClearSecuritySocketLabel &&
driver->securityPrimaryDriver->domainClearSecuritySocketLabel(driver->securityPrimaryDriver,
vm) < 0)
rc = -1;
return rc;
}
virSecurityDriver qemuStackedSecurityDriver = {
.name = "qemuStacked",
.domainSecurityVerify = qemuSecurityStackedVerify,
@ -332,4 +377,7 @@ virSecurityDriver qemuStackedSecurityDriver = {
.domainSetSavedStateLabel = qemuSecurityStackedSetSavedStateLabel,
.domainRestoreSavedStateLabel = qemuSecurityStackedRestoreSavedStateLabel,
.domainClearSecuritySocketLabel = qemuSecurityStackedClearSocketLabel,
.domainSetSecuritySocketLabel = qemuSecurityStackedSetSocketLabel,
};

View File

@ -32,6 +32,10 @@ typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv);
typedef int (*virSecurityDomainRestoreImageLabel) (virDomainObjPtr vm,
virDomainDiskDefPtr disk);
typedef int (*virSecurityDomainSetSocketLabel) (virSecurityDriverPtr drv,
virDomainObjPtr vm);
typedef int (*virSecurityDomainClearSocketLabel)(virSecurityDriverPtr drv,
virDomainObjPtr vm);
typedef int (*virSecurityDomainSetImageLabel) (virDomainObjPtr vm,
virDomainDiskDefPtr disk);
typedef int (*virSecurityDomainRestoreHostdevLabel) (virDomainObjPtr vm,
@ -61,6 +65,8 @@ struct _virSecurityDriver {
virSecurityDriverOpen open;
virSecurityDomainSecurityVerify domainSecurityVerify;
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
virSecurityDomainSetSocketLabel domainSetSecuritySocketLabel;
virSecurityDomainClearSocketLabel domainClearSecuritySocketLabel;
virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
virSecurityDomainGenLabel domainGenSecurityLabel;
virSecurityDomainReserveLabel domainReserveSecurityLabel;

View File

@ -754,6 +754,107 @@ SELinuxSetSecurityProcessLabel(virSecurityDriverPtr drv,
return 0;
}
static int
SELinuxSetSecuritySocketLabel(virSecurityDriverPtr drv,
virDomainObjPtr vm)
{
/* TODO: verify DOI */
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
context_t execcon = NULL;
context_t proccon = NULL;
security_context_t scon = NULL;
int rc = -1;
if (vm->def->seclabel.label == NULL)
return 0;
if (!STREQ(drv->name, secdef->model)) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("security label driver mismatch: "
"'%s' model configured for domain, but "
"hypervisor driver is '%s'."),
secdef->model, drv->name);
goto done;
}
if ( !(execcon = context_new(secdef->label)) ) {
virReportSystemError(errno,
_("unable to allocate socket security context '%s'"),
secdef->label);
goto done;
}
if (getcon(&scon) == -1) {
virReportSystemError(errno,
_("unable to get current process context '%s'"),
secdef->label);
goto done;
}
if ( !(proccon = context_new(scon)) ) {
virReportSystemError(errno,
_("unable to set socket security context '%s'"),
secdef->label);
goto done;
}
if (context_range_set(proccon, context_range_get(execcon)) == -1) {
virReportSystemError(errno,
_("unable to set socket security context range '%s'"),
secdef->label);
goto done;
}
VIR_DEBUG("Setting VM %s socket context %s",
vm->def->name, context_str(proccon));
if (setsockcreatecon(context_str(proccon)) == -1) {
virReportSystemError(errno,
_("unable to set socket security context '%s'"),
context_str(proccon));
goto done;
}
rc = 0;
done:
if (security_getenforce() != 1)
rc = 0;
if (execcon) context_free(execcon);
if (proccon) context_free(proccon);
freecon(scon);
return rc;
}
static int
SELinuxClearSecuritySocketLabel(virSecurityDriverPtr drv,
virDomainObjPtr vm)
{
/* TODO: verify DOI */
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (vm->def->seclabel.label == NULL)
return 0;
if (!STREQ(drv->name, secdef->model)) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("security label driver mismatch: "
"'%s' model configured for domain, but "
"hypervisor driver is '%s'."),
secdef->model, drv->name);
if (security_getenforce() == 1)
return -1;
}
if (setsockcreatecon(NULL) == -1) {
virReportSystemError(errno,
_("unable to clear socket security context '%s'"),
secdef->label);
if (security_getenforce() == 1)
return -1;
}
return 0;
}
static int
SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
{
@ -795,6 +896,8 @@ virSecurityDriver virSELinuxSecurityDriver = {
.open = SELinuxSecurityDriverOpen,
.domainSecurityVerify = SELinuxSecurityVerify,
.domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
.domainSetSecuritySocketLabel = SELinuxSetSecuritySocketLabel,
.domainClearSecuritySocketLabel = SELinuxClearSecuritySocketLabel,
.domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
.domainGenSecurityLabel = SELinuxGenSecurityLabel,
.domainReserveSecurityLabel = SELinuxReserveSecurityLabel,