mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
Apply security label when entering LXC namespaces
Add a new virDomainLxcEnterSecurityLabel() function as a counterpart to virDomainLxcEnterNamespaces(), which can change the current calling process to have a new security context. This call runs client side, not in libvirtd so we can't use the security driver infrastructure. When entering a namespace, the process spawned from virsh will default to running with the security label of virsh. The actual desired behaviour is to run with the security label of the container most of the time. So this changes virsh lxc-enter-namespace command to invoke the virDomainLxcEnterSecurityLabel method. The current behaviour is: LABEL PID TTY TIME CMD system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 1 pts/0 00:00:00 systemd system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 3 pts/1 00:00:00 sh system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 24 ? 00:00:00 systemd-journal system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 29 ? 00:00:00 dhclient staff_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 47 ? 00:00:00 ps Note the ps command is running as unconfined_t, After this patch, The new behaviour is this: virsh -c lxc:/// lxc-enter-namespace dan -- /bin/ps -eZ LABEL PID TTY TIME CMD system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 1 pts/0 00:00:00 systemd system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 3 pts/1 00:00:00 sh system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 24 ? 00:00:00 systemd-journal system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 32 ? 00:00:00 dhclient system_u:system_r:svirt_lxc_net_t:s0:c0.c1023 38 ? 00:00:00 ps The '--noseclabel' flag can be used to skip security labelling. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
3b94239ffb
commit
e4e69e899e
@ -42,6 +42,10 @@ int virDomainLxcEnterNamespace(virDomainPtr domain,
|
||||
unsigned int *noldfdlist,
|
||||
int **oldfdlist,
|
||||
unsigned int flags);
|
||||
int virDomainLxcEnterSecurityLabel(virSecurityModelPtr model,
|
||||
virSecurityLabelPtr label,
|
||||
virSecurityLabelPtr oldlabel,
|
||||
unsigned int flags);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ src/interface/interface_backend_netcf.c
|
||||
src/interface/interface_backend_udev.c
|
||||
src/internal.h
|
||||
src/libvirt.c
|
||||
src/libvirt-lxc.c
|
||||
src/libvirt-qemu.c
|
||||
src/locking/lock_daemon.c
|
||||
src/locking/lock_daemon_config.c
|
||||
|
@ -557,6 +557,7 @@ skip_function = (
|
||||
|
||||
lxc_skip_function = (
|
||||
"virDomainLxcEnterNamespace",
|
||||
"virDomainLxcEnterSecurityLabel",
|
||||
)
|
||||
qemu_skip_function = (
|
||||
#"virDomainQemuAttach",
|
||||
|
@ -29,6 +29,9 @@
|
||||
#include "virlog.h"
|
||||
#include "virprocess.h"
|
||||
#include "datatypes.h"
|
||||
#ifdef WITH_SELINUX
|
||||
# include <selinux/selinux.h>
|
||||
#endif
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||
|
||||
@ -163,3 +166,96 @@ error:
|
||||
virDispatchError(domain->conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* virDomainLxcEnterSecurityLabel:
|
||||
* @model: the security model to set
|
||||
* @label: the security label to apply
|
||||
* @oldlabel: filled with old security label
|
||||
* @flags: currently unused, pass 0
|
||||
*
|
||||
* This API is LXC specific, so it will only work with hypervisor
|
||||
* connections to the LXC driver.
|
||||
*
|
||||
* Attaches the process to the security label specified
|
||||
* by @label. @label is interpreted relative to @model
|
||||
* Depending on the security driver, this may
|
||||
* not take effect until the next call to exec().
|
||||
*
|
||||
* If @oldlabel is not NULL, it will be filled with info
|
||||
* about the current security label. This may let the
|
||||
* process be moved back to the previous label if no
|
||||
* exec() has yet been performed.
|
||||
*
|
||||
* Returns 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
virDomainLxcEnterSecurityLabel(virSecurityModelPtr model,
|
||||
virSecurityLabelPtr label,
|
||||
virSecurityLabelPtr oldlabel,
|
||||
unsigned int flags)
|
||||
{
|
||||
virCheckFlagsGoto(0, error);
|
||||
|
||||
virCheckNonNullArgGoto(model, error);
|
||||
virCheckNonNullArgGoto(label, error);
|
||||
|
||||
if (oldlabel)
|
||||
memset(oldlabel, 0, sizeof(*oldlabel));
|
||||
|
||||
if (STREQ(model->model, "selinux")) {
|
||||
#ifdef WITH_SELINUX
|
||||
if (oldlabel) {
|
||||
security_context_t ctx;
|
||||
|
||||
if (getcon(&ctx) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("unable to get PID %d security context"),
|
||||
getpid());
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("security label exceeds "
|
||||
"maximum length: %d"),
|
||||
VIR_SECURITY_LABEL_BUFLEN - 1);
|
||||
freecon(ctx);
|
||||
goto error;
|
||||
}
|
||||
|
||||
strcpy(oldlabel->label, (char *) ctx);
|
||||
freecon(ctx);
|
||||
|
||||
if ((oldlabel->enforcing = security_getenforce()) < 0) {
|
||||
virReportSystemError(errno, "%s",
|
||||
_("error calling security_getenforce()"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (setexeccon(label->label) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Cannot set context %s"),
|
||||
label->label);
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
||||
_("Support for SELinux is not enabled"));
|
||||
goto error;
|
||||
#endif
|
||||
} else {
|
||||
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
||||
_("Security model %s cannot be entered"),
|
||||
model->model);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
virDispatchError(NULL);
|
||||
return -1;
|
||||
}
|
||||
|
@ -15,3 +15,8 @@ LIBVIRT_LXC_1.0.2 {
|
||||
virDomainLxcEnterNamespace;
|
||||
virDomainLxcOpenNamespace;
|
||||
};
|
||||
|
||||
LIBVIRT_LXC_1.0.4 {
|
||||
global:
|
||||
virDomainLxcEnterSecurityLabel;
|
||||
} LIBVIRT_LXC_1.0.2;
|
||||
|
@ -7992,6 +7992,7 @@ static const vshCmdInfo info_lxc_enter_namespace[] = {
|
||||
|
||||
static const vshCmdOptDef opts_lxc_enter_namespace[] = {
|
||||
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
|
||||
{"noseclabel", VSH_OT_BOOL, 0, N_("Do not change process security label")},
|
||||
{"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("namespace")},
|
||||
{NULL, 0, 0, NULL}
|
||||
};
|
||||
@ -8008,11 +8009,17 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
||||
int nfdlist;
|
||||
int *fdlist;
|
||||
size_t i;
|
||||
bool setlabel = true;
|
||||
virSecurityModelPtr secmodel = NULL;
|
||||
virSecurityLabelPtr seclabel = NULL;
|
||||
|
||||
dom = vshCommandOptDomain(ctl, cmd, NULL);
|
||||
if (dom == NULL)
|
||||
goto cleanup;
|
||||
|
||||
if (vshCommandOptBool(cmd, "noseclabel"))
|
||||
setlabel = false;
|
||||
|
||||
while ((opt = vshCommandOptArgv(cmd, opt))) {
|
||||
if (VIR_EXPAND_N(cmdargv, ncmdargv, 1) < 0) {
|
||||
vshError(ctl, _("%s: %d: failed to allocate argv"),
|
||||
@ -8029,12 +8036,34 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
||||
if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (setlabel) {
|
||||
if (VIR_ALLOC(secmodel) < 0) {
|
||||
vshError(ctl, "%s", _("Failed to allocate security model"));
|
||||
goto cleanup;
|
||||
}
|
||||
if (VIR_ALLOC(seclabel) < 0) {
|
||||
vshError(ctl, "%s", _("Failed to allocate security label"));
|
||||
goto cleanup;
|
||||
}
|
||||
if (virNodeGetSecurityModel(ctl->conn, secmodel) < 0)
|
||||
goto cleanup;
|
||||
if (virDomainGetSecurityLabel(dom, seclabel) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Fork once because we don't want to affect
|
||||
* virsh's namespace itself
|
||||
*/
|
||||
if (virFork(&pid) < 0)
|
||||
goto cleanup;
|
||||
if (pid == 0) {
|
||||
if (setlabel &&
|
||||
virDomainLxcEnterSecurityLabel(secmodel,
|
||||
seclabel,
|
||||
NULL,
|
||||
0) < 0)
|
||||
_exit(255);
|
||||
|
||||
if (virDomainLxcEnterNamespace(dom,
|
||||
nfdlist,
|
||||
fdlist,
|
||||
@ -8067,6 +8096,8 @@ cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
||||
ret = true;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(seclabel);
|
||||
VIR_FREE(secmodel);
|
||||
if (dom)
|
||||
virDomainFree(dom);
|
||||
VIR_FREE(cmdargv);
|
||||
|
Loading…
Reference in New Issue
Block a user