mirror of https://gitee.com/openkylin/libvirt.git
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:
parent
3bb3743934
commit
e72cc3c11d
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue