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)
|
qemuConnectMonitor(struct qemud_driver *driver, virDomainObjPtr vm)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
int ret;
|
int ret = -1;
|
||||||
|
|
||||||
/* Hold an extra reference because we can't allow 'vm' to be
|
/* Hold an extra reference because we can't allow 'vm' to be
|
||||||
* deleted while the monitor is active */
|
* deleted while the monitor is active */
|
||||||
virDomainObjRef(vm);
|
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,
|
if ((priv->mon = qemuMonitorOpen(vm,
|
||||||
priv->monConfig,
|
priv->monConfig,
|
||||||
priv->monJSON,
|
priv->monJSON,
|
||||||
&monitorCallbacks)) == NULL) {
|
&monitorCallbacks)) == NULL) {
|
||||||
VIR_ERROR(_("Failed to connect monitor for %s"), vm->def->name);
|
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);
|
qemuDomainObjEnterMonitorWithDriver(driver, vm);
|
||||||
ret = qemuMonitorSetCapabilities(priv->mon);
|
ret = qemuMonitorSetCapabilities(priv->mon);
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
qemuDomainObjExitMonitorWithDriver(driver, vm);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
error:
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
qemuMonitorClose(priv->mon);
|
qemuMonitorClose(priv->mon);
|
||||||
priv->mon = NULL;
|
priv->mon = NULL;
|
||||||
|
virDomainObjUnref(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -310,6 +310,51 @@ qemuSecurityStackedGetProcessLabel(virDomainObjPtr vm,
|
||||||
return rc;
|
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 = {
|
virSecurityDriver qemuStackedSecurityDriver = {
|
||||||
.name = "qemuStacked",
|
.name = "qemuStacked",
|
||||||
.domainSecurityVerify = qemuSecurityStackedVerify,
|
.domainSecurityVerify = qemuSecurityStackedVerify,
|
||||||
|
@ -332,4 +377,7 @@ virSecurityDriver qemuStackedSecurityDriver = {
|
||||||
|
|
||||||
.domainSetSavedStateLabel = qemuSecurityStackedSetSavedStateLabel,
|
.domainSetSavedStateLabel = qemuSecurityStackedSetSavedStateLabel,
|
||||||
.domainRestoreSavedStateLabel = qemuSecurityStackedRestoreSavedStateLabel,
|
.domainRestoreSavedStateLabel = qemuSecurityStackedRestoreSavedStateLabel,
|
||||||
|
|
||||||
|
.domainClearSecuritySocketLabel = qemuSecurityStackedClearSocketLabel,
|
||||||
|
.domainSetSecuritySocketLabel = qemuSecurityStackedSetSocketLabel,
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,6 +32,10 @@ typedef virSecurityDriverStatus (*virSecurityDriverProbe) (void);
|
||||||
typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv);
|
typedef int (*virSecurityDriverOpen) (virSecurityDriverPtr drv);
|
||||||
typedef int (*virSecurityDomainRestoreImageLabel) (virDomainObjPtr vm,
|
typedef int (*virSecurityDomainRestoreImageLabel) (virDomainObjPtr vm,
|
||||||
virDomainDiskDefPtr disk);
|
virDomainDiskDefPtr disk);
|
||||||
|
typedef int (*virSecurityDomainSetSocketLabel) (virSecurityDriverPtr drv,
|
||||||
|
virDomainObjPtr vm);
|
||||||
|
typedef int (*virSecurityDomainClearSocketLabel)(virSecurityDriverPtr drv,
|
||||||
|
virDomainObjPtr vm);
|
||||||
typedef int (*virSecurityDomainSetImageLabel) (virDomainObjPtr vm,
|
typedef int (*virSecurityDomainSetImageLabel) (virDomainObjPtr vm,
|
||||||
virDomainDiskDefPtr disk);
|
virDomainDiskDefPtr disk);
|
||||||
typedef int (*virSecurityDomainRestoreHostdevLabel) (virDomainObjPtr vm,
|
typedef int (*virSecurityDomainRestoreHostdevLabel) (virDomainObjPtr vm,
|
||||||
|
@ -61,6 +65,8 @@ struct _virSecurityDriver {
|
||||||
virSecurityDriverOpen open;
|
virSecurityDriverOpen open;
|
||||||
virSecurityDomainSecurityVerify domainSecurityVerify;
|
virSecurityDomainSecurityVerify domainSecurityVerify;
|
||||||
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
|
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
|
||||||
|
virSecurityDomainSetSocketLabel domainSetSecuritySocketLabel;
|
||||||
|
virSecurityDomainClearSocketLabel domainClearSecuritySocketLabel;
|
||||||
virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
|
virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
|
||||||
virSecurityDomainGenLabel domainGenSecurityLabel;
|
virSecurityDomainGenLabel domainGenSecurityLabel;
|
||||||
virSecurityDomainReserveLabel domainReserveSecurityLabel;
|
virSecurityDomainReserveLabel domainReserveSecurityLabel;
|
||||||
|
|
|
@ -754,6 +754,107 @@ SELinuxSetSecurityProcessLabel(virSecurityDriverPtr drv,
|
||||||
return 0;
|
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
|
static int
|
||||||
SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -795,6 +896,8 @@ virSecurityDriver virSELinuxSecurityDriver = {
|
||||||
.open = SELinuxSecurityDriverOpen,
|
.open = SELinuxSecurityDriverOpen,
|
||||||
.domainSecurityVerify = SELinuxSecurityVerify,
|
.domainSecurityVerify = SELinuxSecurityVerify,
|
||||||
.domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
|
.domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
|
||||||
|
.domainSetSecuritySocketLabel = SELinuxSetSecuritySocketLabel,
|
||||||
|
.domainClearSecuritySocketLabel = SELinuxClearSecuritySocketLabel,
|
||||||
.domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
|
.domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
|
||||||
.domainGenSecurityLabel = SELinuxGenSecurityLabel,
|
.domainGenSecurityLabel = SELinuxGenSecurityLabel,
|
||||||
.domainReserveSecurityLabel = SELinuxReserveSecurityLabel,
|
.domainReserveSecurityLabel = SELinuxReserveSecurityLabel,
|
||||||
|
|
Loading…
Reference in New Issue