diff --git a/include/libvirt/libvirt-lxc.h b/include/libvirt/libvirt-lxc.h index f2c87fb490..50218137b0 100644 --- a/include/libvirt/libvirt-lxc.h +++ b/include/libvirt/libvirt-lxc.h @@ -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 } diff --git a/po/POTFILES.in b/po/POTFILES.in index bd2c02e4c1..5b5c3c2873 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/python/generator.py b/python/generator.py index 8236bd2c98..6a25c2d247 100755 --- a/python/generator.py +++ b/python/generator.py @@ -557,6 +557,7 @@ skip_function = ( lxc_skip_function = ( "virDomainLxcEnterNamespace", + "virDomainLxcEnterSecurityLabel", ) qemu_skip_function = ( #"virDomainQemuAttach", diff --git a/src/libvirt-lxc.c b/src/libvirt-lxc.c index f580c3c797..c28f33dd71 100644 --- a/src/libvirt-lxc.c +++ b/src/libvirt-lxc.c @@ -29,6 +29,9 @@ #include "virlog.h" #include "virprocess.h" #include "datatypes.h" +#ifdef WITH_SELINUX +# include +#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; +} diff --git a/src/libvirt_lxc.syms b/src/libvirt_lxc.syms index b5be18b6db..ccf1be9897 100644 --- a/src/libvirt_lxc.syms +++ b/src/libvirt_lxc.syms @@ -15,3 +15,8 @@ LIBVIRT_LXC_1.0.2 { virDomainLxcEnterNamespace; virDomainLxcOpenNamespace; }; + +LIBVIRT_LXC_1.0.4 { + global: + virDomainLxcEnterSecurityLabel; +} LIBVIRT_LXC_1.0.2; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 7caa36481a..ab90f5827c 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -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);