Hi Daniel,
Just a gentle reminder that we’ve replied to your comments and awaiting further
feedback.
One thing I wanted to ask was do you know if historically SetProcessLabel and
SetChildProcessLabel were one function call at some point or any reason there are two
calls if they seem to have the same effect (in the case of SELinux and it looks like
AppArmor as well)? Although our implementation currently requires both, perhaps if we
really don’t need both we can adjust the Smack driver to use only one function.
Thanks,
Randy
From: raghuram sudhaakar
<rssudhaakar@gmail.com<mailto:rssudhaakar@gmail.com>>
Date: Wednesday, June 15, 2016 at 15:40
To: "Daniel P. Berrange"
<berrange@redhat.com<mailto:berrange@redhat.com>>
Cc: Randy Aybar <raybar@cisco.com<mailto:raybar@cisco.com>>,
"libvir-list@redhat.com<mailto:libvir-list@redhat.com>"
<libvir-list@redhat.com<mailto:libvir-list@redhat.com>>,
"hliang@bupt.edu.cn<mailto:hliang@bupt.edu.cn>"
<hliang@bupt.edu.cn<mailto:hliang@bupt.edu.cn>>,
"changyao@bupt.edu.cn<mailto:changyao@bupt.edu.cn>"
<changyao@bupt.edu.cn<mailto:changyao@bupt.edu.cn>>
Subject: Re: [libvirt] [PATCH] Introduce Smack security driver for Libvirt
Daniel,
We have addressed the comments you had provided. The patch rebased to 1.3.4 is attached.
Appreciate you taking the time to review it.
raghuram
On Tue, May 10, 2016 at 4:15 AM, Daniel P. Berrange
<berrange@redhat.com<mailto:berrange@redhat.com>> wrote:
On Thu, Apr 14, 2016 at 07:47:23PM +0000, Randy Aybar (raybar) wrote:
First time RFC/mailing list/community submission/etc. so please
forgive if not in the appropriate format.
Thanks for taking the time to submit this, and sorry for not giving
feedback on it sooner. Next time feel free to send "ping" responses
if you've not had feedback on a patch after a week or so and you
want to remind people!
I. Introduction
Libvirt currently has support for two of the various Linux security modules
(LSM), AppArmor and SELinux. While these work well enough for most cases, there
are others in which a platform may require less complexity and overhead.
Smack LSM (
http://schaufler-ca.com/description_from_the_linux_source_tree)
intrinsically provides access control with much more simplicity while
remaining secure. A subject-object model is adapted with an access type
relationship to determine if permissions or granted or denied.
Yep, we're more than happy to accept patches to support any LSM module
that is in the mainline kernel tree, as we're aware not everyone uses
SELinux / AppArmor
Initial findings on the topic yielded us to a research paper worked
on by
students at Beijing University of Posts and Telecommunications. As part of the
paper's objective to create a lightweight approach to secure deployment of
virtual machines in the cloud, a Smack security driver was implemented for use
with QEMU-based virtual machines spawned by using the Libvirt API. After
contacting the authors of the papers, they were more than willing to share the
source code.
'sharing the source code' can mean many different things to different
people. Can you just confirm explicitly that they gave their permission
for their contributions being licensed under the "LGPLv2.1 or later"
which libvirt uses.
I can confirm that the intent of the authors from BUPT (who wrote an initial version of
the smack driver for 1.1.4) is to upstream the code. However, they did not do it for
various reasons. Their contributions are included in the copyright header of all files.
They are also ‘cced and can explicitly state their intent if required.
The Smack driver was initially derived from parts of the SELinux
and AppArmor drivers as noted by the authors and uses the Libsmack
library to
assign Smack labels when needed.
Ok, libsmack.so is under the LGPLv2.1 which should be ok.
Another thing to note is that the Smack security driver itself
depends on a security
interface when fully enforced with namespaces. This interface is brought in
by the Linux kernel in 4.3 but our team has backported and tested Libvirt with version
3.19 kernel. Details on why this was necessary found below in LXC container
changes. Link that references the change in the kernel:
https://lwn.net/Articles/660675/
Ok, we should probably document that security requirement, probably in the
docs/drvlxc.html.in<http://drvlxc.html.in> file.
Updated docs/drvlxc.html.in<http://drvlxc.html.in> with the above note
i. LXC Container (src/lxc/lxc_container.c)
a. Reordering of dropping capabilities and setting up security labeling
Upon forking into a new user namespace (lxcContainerSetID), the child process no
longer has the ability to override LSM and access folders that have been previously
assigned
Smack labels. This is important to note since after entering the namespace, the child
still needs to share mount devpts and pivot root however the process does not
take on the container's label until much after this setup. Thus a suggestion to
move the set process label (virSecurityManagerSetProcessLabel) after setting namespaces
is made.
Dropping capabilities was also moved after sending the continue signal to the
parent. We had come across an issue as well with setting up FDs and the
container would fail to start.
Yep that's fine - there's no particular reason for the current ordering - its
just historically chosen.
b. Adding a call to set the child's process label
(virSecurityManagerSetChildProcessLabel)
When the child process is spawned from lxcContainerStart, although it has full
capabilities in its own namespace (after SetUID), it is unable to change its own
security
context (label). Currently the only workaround is to incorporate an
upcoming patch to the Smack LSM (kernel base) that allows an unprivileged
process to change its context only if the label its trying to acquire exists in
a predefined list held by the parent.
With the patch in place, the LXC driver needs to ensure that the label makes it
to the list of the parent so that the child can continue to take on the context
which brings a change to lxcContainerStart.
Although the SetChildProcessLabel is a hook that is primarily used by QEMU, we
decided to use it as the name best fit the operation being performed.
A check is implemented to ensure that it only continues if Smack is the driver
being used since this does not need to occur in the other LSMs.
Within the Smack driver itself, the hook also performs a check to see if LXC is
used otherwise skip the block pertaining to LXC. In the LXC code, it checks
to see if the Smack relabel-self interface exists and if namespaces is being
used to continue. The label is written with a simple write call to the file. The
logic is allowed to flow into the QEMU portion since no command is passed in,
the function acts as a noop and safely exits.
Any comments for improvement on the logic handled in this change are highly
appreciated!
So you moved the cal to SetProcessLabel to quite early in the
lxcContainerChild() method, and then added a second call to
SetChildProcessLabel right before virCommandExec().
With SELinux there's no functional difference between the
SetProcessLabel and SetChildProcessLabel - both end up
calling setexeccon_raw() which tells SELinux to change the
label when execve() is called.
There might be a difference for AppArmor, but if there is,
I wouldn't be surprised if it doesn't matter.
IOW, I think we can probably just remove the SetProcessLabel
call entirely, and only ever call SetChildProcessLabel
for all drivers.
For SMACK, if we remove SetProcessLabel the init process of the container does not get
labelled and hence the container won’t stand up properly. So we had to leave that in.
ii. LXC Controller (src/lxc/lxc_controller.c)
a. Add logic to label the special devices created under
(/var/run/libvirt/lxc/container.XXX)
The following function calls setup the appropriate special devices such as
ttys, ptmx, null, etc. (/dev)
virLXCControllerSetupDev
virLXCControllerPopulateDevices
virLXCControllerSetupDevPTS
virLXCControllerSetupConsoles
It was decided to add the call to do a label operation in these functions due to
the fact that chown'ing also happened at these locations and wanted to provide
some uniformity in that sense. Since the security hook to label these are no-op
in all but the Smack driver it's just a straightforward call with the usual
check to see if it succeeded.
Yep, that makes sense.
iii. Security Drivers (src/security)
Changes to security driver model include an additional hook to apply a security
label by passing in a string. Although there exists functions made for applying
security labels, complications arose from using either.
The first of these is SetImageLabel which requires to pass in a virStorageSource
that holds the string. LXC does not make use of this data structure and
initializing one for the sake of a string did not seem feasible due to the
numerous and differing members the struct consisted of.
Agreed.
The second function major function to apply security labels is
SetImageFDLabel
which uses a file descriptor rather than a string text. While this approach
seemed more promising there were hurdles that came across while attempting to
label items. A file descriptor would be needed to be opened for each special
device available. However devices like tty could not be opened without being
issued as a controlling tty by the process. Note that a workaround was attempted
to change the open call to include the O_PATH flag and obtain the path by looking up
the
location the FD pointed to in the process's list of file descriptors within
/proc. While this change worked for the tty case, it was dismissed due to the
additional changes that may have been needed to the other security drivers as we
were targeting to minimize the changes. This solution may be revisited upon further
testing and review.
a. Update Definitions for DAC, Stack, AppArmor, SELinux, Smack,
driver base (security_driver.h), and driver manager (security_manager.c,h)
Changes here involve updated the driver's definitions to include the new hook,
virSecurityDomainSetImagePathLabel. All drivers except Smack implement this by
just returning 0 to not disrupt the flow in a non-Smack setup.
b. Updates to Smack driver to support namespaces with LXC
Already described include changes to implement the extra hook to label a file
using a path as well as SetChildProcessLabel wihthin the driver to
include the process of adding a label to the approved list via relabel-self.
The driver itself was cleaned up a bit and refactored to eliminate the use of
excessive amount of helper functions and rely on the API provided by the
libsmack library. Function names were refactored to match the style of the
SELinux driver (after the dropping of an extra "Security" in the
function's
name).
iv. Support for entering namespaces in Smack (src/libvirt-lxc.c)
A small addition was made to enable support for Smack using the
lxc-enter-namespace and was merely a mirror of the other security drivers
included in this file. Smack in this case uses libsmack API call to label the
process entering the namespace.
This patch has been created for patching Libvirt 1.3.1 base source
code.
Generally we like to have patches created against current GIT master
revision. Could you rebase to master when addressing feedback.
The patch rebased to 1.3.4 is pasted at the end of this thread. It is also attached for
better readability.
diff --git a/configure.ac<http://configure.ac>
b/configure.ac<http://configure.ac>
index 047ad3b..12d0bb8 100644
--- a/configure.ac<http://configure.ac>
+++ b/configure.ac<http://configure.ac>
@@ -253,6 +253,7 @@ LIBVIRT_CHECK_READLINE
LIBVIRT_CHECK_SANLOCK
LIBVIRT_CHECK_SASL
LIBVIRT_CHECK_SELINUX
+LIBVIRT_CHECK_SMACK
LIBVIRT_CHECK_SSH2
LIBVIRT_CHECK_SYSTEMD_DAEMON
LIBVIRT_CHECK_UDEV
@@ -1535,6 +1536,27 @@ if test "$with_apparmor" = "no"; then
fi
AM_CONDITIONAL([WITH_APPARMOR_PROFILES], [test "$with_apparmor_profiles" !=
"no"])
+AC_ARG_WITH([secdriver-smack],
+ [AS_HELP_STRING([--with-secdriver-smack],
+ [use Smack security driver @<:@default=check@:>@])],
+ [],
+ [with_secdriver_smack=check])
+
+if test "$with_smack" != "yes" ; then
+ if test "$with_secdriver_smack" = "check" ; then
+ with_secdriver_smack=no
+ fi
+ if test "$with_secdriver_smack" != "no" ; then
+ AC_MSG_ERROR([You must install the Smack development package in order to compile
libvirt])
+ fi
+elif test "with_secdriver_smack" != "no" ; then
+ with_secdriver_smack=yes
+ AC_DEFINE_UNQUOTED([WITH_SECDRIVER_SMACK], 1, [whether Smack security driver is
available])
+fi
+AM_CONDITIONAL([WITH_SECDRIVER_SMACK], [test "$with_secdriver_smack" !=
"no"])
I realize you just copied existing pattern for apparmor, but
could you ignore that existing pattern, and just move this
block of code into the LIBVIRT_CHECK_SMACK fnuction you
created too.
+AC_DEFUN([LIBVIRT_CHECK_SMACK],[
+ LIBVIRT_CHECK_LIB([SMACK], [smack],
+ [smack_set_label_for_self], [sys/smack.h])
+
+ AC_ARG_WITH([smack_mount],
+ [AS_HELP_STRING([--with-smack-mount],
+ [set Smack mount point @<:@default=check@:>@])],
+ [],
+ [with_smack_mount=check])
+
+ if test "$with_smack" = "yes"; then
+ AC_MSG_CHECKING([Smack mount point])
+ if test "$with_smack_mount" = "check" || test -z
"$with_smack_mount"; then
+ if test -d /sys/fs/smackfs ; then
+ SMACK_MOUNT=/sys/fs/smackfs
+ else
+ SMACK_MOUNT=/smack
+ fi
Do any distros exist which use /smack as a path - I know that
/selinux was used in Fedora/RHEL for a long time, but now
uses /sys/fs/selinux. If we don't need to support /smack
we should just fix /sys/fs/smackfs as the standard location
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index c5a70a1..71203aa 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -2206,6 +2209,10 @@ static int lxcContainerChild(void *data)
if (lxcContainerSetID(vmDef) < 0)
goto cleanup;
+ VIR_DEBUG("Setting up security labeling");
+ if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0)
+ goto cleanup;
+
As mentioned earlier, I think you can just drop this....
root = virDomainGetFilesystemForTarget(vmDef, "/");
if (argv->nttyPaths) {
@@ -2254,20 +2261,12 @@ static int lxcContainerChild(void *data)
goto cleanup;
}
- /* drop a set of root capabilities */
- if (lxcContainerDropCapabilities(vmDef, !!hasReboot) < 0)
- goto cleanup;
-
if (lxcContainerSendContinue(argv->handshakefd) < 0) {
virReportSystemError(errno, "%s",
_("Failed to send continue signal to
controller"));
goto cleanup;
}
- VIR_DEBUG("Setting up security labeling");
- if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0)
- goto cleanup;
-
VIR_DEBUG("Setting up inherited FDs");
VIR_FORCE_CLOSE(argv->handshakefd);
VIR_FORCE_CLOSE(argv->monitor);
@@ -2275,6 +2274,10 @@ static int lxcContainerChild(void *data)
argv->npassFDs, argv->passFDs) < 0)
goto cleanup;
+ /* drop a set of root capabilities */
+ if (lxcContainerDropCapabilities(vmDef, !!hasReboot) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
VIR_FREE(ttyPath);
@@ -2389,6 +2392,16 @@ int lxcContainerStart(virDomainDefPtr def,
if (userns_supported()) {
VIR_DEBUG("Enable user namespace");
cflags |= CLONE_NEWUSER;
+#ifdef WITH_SMACK
+ if(STREQ(virSecurityManagerGetModel(securityDriver),"smack")
&&
+ virSecurityManagerSetChildProcessLabel(securityDriver,
+ def,
+ NULL) < 0) {
And remove the check for GetModel() == "smack" - just let all drivers
use this codepath - though it would hae to be outside the userns_supported()
check
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to send label to relabel
interface."));
+ return -1;
+ }
+#endif
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Kernel doesn't support user namespace"));
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 438103a..37080b8 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1476,6 +1479,9 @@ static int
virLXCControllerSetupDev(virLXCControllerPtr ctrl)
if (lxcContainerChown(ctrl->def, dev) < 0)
goto cleanup;
+
+ if (virSecurityManagerSetImagePathLabel(ctrl->securityManager,ctrl->def,dev)
< 0)
+ goto cleanup;
BTW, there should always be a space after a ',' in an argument list.
If you run 'make syntax-check' it should warn you about style mistakes
like this.
ret = 0;
cleanup:
@@ -1525,6 +1531,11 @@ static int virLXCControllerPopulateDevices(virLXCControllerPtr
ctrl)
if (lxcContainerChown(ctrl->def, path) < 0)
goto cleanup;
+ if (virSecurityManagerSetImagePathLabel(ctrl->securityManager,
+ ctrl->def,
+ path) < 0)
+ goto cleanup;
+
VIR_FREE(path);
}
@@ -2183,6 +2194,14 @@ virLXCControllerSetupDevPTS(virLXCControllerPtr ctrl)
(lxcContainerChown(ctrl->def, devpts) < 0))
goto cleanup;
+ if ((virSecurityManagerSetImagePathLabel(ctrl->securityManager,
+ ctrl->def,
+ ctrl->devptmx)) < 0 ||
This has for whitespace at the end of lines - again just run
'make syntax-check' and fix any problems it reports. Generally
you want to align parameters on each line with the '('
diff --git a/src/security/security_smack.c
b/src/security/security_smack.c
new file mode 100644
index 0000000..50301ad
--- /dev/null
+++ b/src/security/security_smack.c
@@ -0,0 +1,1519 @@
+/*
+ * Copyright (C) 2015 Cisco Systems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Hongliang Liang <hliang@bupt.edu.cn<mailto:hliang@bupt.edu.cn>>
+ * Changyao Han <changyao@bupt.edu.cn<mailto:changyao@bupt.edu.cn>>
+ *
+ * Updated to libvirt v1.2.15: (Original was written for libvirt v1.1.4)
+ * Raghuram S. Sudhaakar <rsudhaak@cisco.com<mailto:rsudhaak@cisco.com>>
+ * Randy Aybar <raybar@cisco.com<mailto:raybar@cisco.com>>
+ *
+ * Based on security_selinux.c by James Morris
<jmorris@namei.org<mailto:jmorris@namei.org>>
+ * and security_apparmor.c by Jamie Strandboge
<jamie@canonical.com<mailto:jamie@canonical.com>>
+ *
+ * Smack scurity driver.
+ *
+ */
+static int
+virSecuritySmackGetPIDLabel(pid_t pid, char **label)
+{
+
+ char *result;
+ int fd;
+ int ret;
+ char *path;
+
+ result = calloc(SMACK_LABEL_LEN + 1, 1);
+ if (result == NULL)
+ return -1;
Use of 'calloc' / 'malloc' / 'free' etc is not allowed in
libvirt - use VIR_ALLOC, VIR_FREE, etc
http://libvirt.org/hacking.html#memalloc
Also, please only indent lines by 4 spaces at a time - not 8.
There's tips here on how to configure emacs or vim to indent
correctly for libvirt:
http://libvirt.org/hacking.html#indent
+ ret = virAsprintf(&path,
"/proc/%d/attr/current", pid);
+ if (ret < 0)
+ return -1;
+ fd = open(path, O_RDONLY);
+ VIR_FREE(path);
+ if (fd < 0) {
+ free(result);
+ return -1;
+ }
+ ret = read(fd, result, SMACK_LABEL_LEN);
+ VIR_FORCE_CLOSE(fd);
+ if (ret < 0) {
+ free(result);
+ return -1;
+ }
+ *label = result;
+ return ret;
+
+}
You could replace the open/read/close code here with a simple
virFileReadAll() call.
+int
+virSecuritySmackSockCreate(const char *label, const char *attr)
+{
+ int fd;
+ int ret = -1;
+ long int tid;
+ char *path;
+ tid = syscall(SYS_gettid);
+ VIR_DEBUG("/proc/self/task/%ld/attr/%s", tid, attr);
+ ret = virAsprintf(&path, "/proc/self/task/%ld/attr/%s", tid,
attr);
+ if (ret < 0)
+ return -1;
+
+ VIR_DEBUG("virSecuritySmackSockCreate pid is in %d", getpid());
+ VIR_DEBUG("real user ID is in %d", getuid());
+ VIR_DEBUG("effective user ID is in %d", geteuid());
+ VIR_DEBUG("label from self %s", label);
+ VIR_DEBUG("location /proc/self/attr/%s", attr);
+
+ if (label) {
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ VIR_DEBUG("open file %s", path);
+ VIR_FREE(path);
+ if (fd < 0) {
+ VIR_DEBUG("open fail");
+ return -1;
+ }
+ VIR_DEBUG("open success");
+ do {
+ ret = write(fd, label, strlen(label) + 1);
+ } while (ret < 0 && errno == EINTR);
You can use virFileWriteStr() to write a string to a file.
+ }
+ else {
+ fd = open(path, O_TRUNC);
+ VIR_FREE(path);
+ if (fd < 0)
+ return -1;
+ ret = 0;
+ }
+
+ close(fd);
Use VIR_CLOSE or VIR_FORCE_CLOSE
+
+ return (ret < 0) ? -1 : 0;
+
+}
+
Broadly speaking this looks like a reasonable design. Biggest thing todo
is rebase to current git master & run 'make syntax-check' to fix all
the problems it shows, as that'll make it nicer to review again.
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|
I+
+}
+
+static int
+virSecuritySmackRestoreDiskLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ virDomainDiskDefPtr disk)
+{
+ return virSecuritySmackRestoreImageLabelInt(mgr, def, disk->src, false);
+}
+
+static int
+virSecuritySmackSetImageLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ virStorageSourcePtr src)
+{
+ virSecurityLabelDefPtr seclabel;
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ if (src->type == VIR_STORAGE_TYPE_NETWORK)
+ return 0;
+
+ VIR_DEBUG("set disk image security label before");
+
+ if (setxattr(src->path, "security.SMACK64", seclabel->imagelabel,
+ strlen(seclabel->imagelabel) + 1, 0) < 0)
+ return -1;
+
+ VIR_DEBUG("disk image %s", src->path);
+ VIR_DEBUG("set disk image security label after");
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackRestoreImageLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ virStorageSourcePtr src)
+{
+ return virSecuritySmackRestoreImageLabelInt(mgr, def, src, false);
+
+}
+
+static int
+virSecuritySmackSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr vm)
+{
+
+ return 0;
+ virSecurityLabelDefPtr seclabel;
+ char *label = NULL;
+ int ret = -1;
+
+ seclabel = virDomainDefGetSecurityLabelDef(vm, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STREQ(SECURITY_SMACK_NAME, seclabel->model) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ if (smack_new_label_from_self(&label) == -1) {
+ virReportSystemError(errno,
+ _("unable to get current process context '%s'"),
seclabel->label);
+ goto done;
+ }
+
+ VIR_DEBUG("SmackSetSecurityDaemonSocketLabel is in %d", getpid());
+ VIR_DEBUG("label from self %s", label);
+
+
+ if (virSecuritySmackSockCreate(label, "sockincreate") == -1) {
+ virReportSystemError(errno,
+ _("unable to set socket smack label '%s'"),
seclabel->label);
+ goto done;
+ }
+
+ ret = 0;
+ done:
+
+ VIR_FREE(label);
+ return ret;
+
+}
+
+static int
+virSecuritySmackSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr vm)
+{
+
+ virSecurityLabelDefPtr seclabel;
+
+ return 0;
+ seclabel = virDomainDefGetSecurityLabelDef(vm, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STREQ(SECURITY_SMACK_NAME, seclabel->model) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ VIR_DEBUG("Setting VM %s socket label %s", vm->name,
seclabel->label);
+
+ if (virSecuritySmackSockCreate(seclabel->label, "sockoutcreate") == -1)
{
+ virReportSystemError(errno,
+ _("unable to set socket smack label '%s'"),
+ seclabel->label);
+ return -1;
+ }
+
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+
+ virSecurityLabelDefPtr seclabel;
+
+ return 0;
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STREQ(SECURITY_SMACK_NAME, seclabel->model) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ VIR_DEBUG("clear sock label");
+
+ if (virSecuritySmackSockCreate(NULL, "sockincreate") == -1 ||
+ virSecuritySmackSockCreate(NULL, "sockoutcreate") == -1) {
+ virReportSystemError(errno,
+ _("unable to clear socket smack label '%s'"),
+ seclabel->label);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+*Current called in qemuStartVMDaemon to setup a 'label'. We make the
+*label based on UUID.
+*this is called on 'start'with RestoreSecurityLabel being called on
+*shutdown
+ */
+static int
+virSecuritySmackGenLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def)
+{
+ int ret = -1;
+ char *label_name = NULL;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return ret;
+
+ VIR_DEBUG("label=%s", virSecurityManagerGetDriver(mgr));
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+ seclabel->label) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("security label already defined for VM"));
+ return ret;
+ }
+
+ if (seclabel->imagelabel) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("security image label already defined for VM"));
+ return ret;
+ }
+
+ if (seclabel->model &&
+ STRNEQ(seclabel->model, SECURITY_SMACK_NAME)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label model %s is not supported with
smack"),
+ seclabel->model);
+ return ret;
+ }
+
+ VIR_DEBUG("type=%d", seclabel->type);
+
+ if ((label_name = virSecuritySmackGetLabelName(def)) == NULL)
+ return ret;
+
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+
+ /*set process label*/
+ if (VIR_STRDUP(seclabel->label, label_name) < 0)
+ goto cleanup;
+ }
+
+ /*set imagelabel the same as label*/
+ if (VIR_STRDUP(seclabel->imagelabel, label_name) < 0)
+ goto cleanup;
+
+ if (!seclabel->model &&
+ VIR_STRDUP(seclabel->model, SECURITY_SMACK_NAME) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+
+ if (ret != 0) {
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
+ VIR_FREE(seclabel->label);
+ VIR_FREE(seclabel->imagelabel);
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+ !seclabel->baselabel)
+ VIR_FREE(seclabel->model);
+ }
+
+ VIR_FREE(label_name);
+
+ VIR_DEBUG("model=%s label=%s imagelabel=%s",
+ NULLSTR(seclabel->model),
+ NULLSTR(seclabel->label),
+ NULLSTR(seclabel->imagelabel));
+
+ return ret;
+
+}
+
+static int
+virSecuritySmackReserveLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ pid_t pid ATTRIBUTE_UNUSED)
+{
+ /*Security label is based UUID,*/
+ return 0;
+}
+
+/*
+*Called on VM shutdown and destroy.
+*/
+static int
+virSecuritySmackReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+ VIR_FREE(seclabel->label);
+ VIR_FREE(seclabel->model);
+ }
+ VIR_FREE(seclabel->imagelabel);
+
+ return 0;
+
+}
+
+/* Seen with 'virsh dominfo <vm>'. This function only called if the VM is
+* running.
+*/
+static int
+virSecuritySmackGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ pid_t pid,
+ virSecurityLabelPtr sec)
+{
+
+ char *label_name = NULL;
+
+ if (virSecuritySmackGetPIDLabel(pid, &label_name) == -1) {
+ virReportSystemError(errno,
+ _("unable to get PID %d security label"),
+ pid);
+ return -1;
+ }
+
+ if (strlen(label_name) >= VIR_SECURITY_LABEL_BUFLEN) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label exceeds "
+ "maximum length: %d"),
+ VIR_SECURITY_LABEL_BUFLEN - 1);
+ VIR_FREE(label_name);
+ return -1;
+ }
+
+ label_name = virStrcpy(sec->label, label_name, VIR_SECURITY_LABEL_BUFLEN);
+ VIR_FREE(label_name);
+ /*Smack default enforced*/
+ sec->enforcing = 1;
+
+ return label_name == NULL ? -1 : 0;
+}
+
+static int
+virSecuritySmackSetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STRNEQ(SECURITY_SMACK_NAME, seclabel->model)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "\'%s\' model configured for domain, but "
+ "hypervisor driver is \'%s\'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+
+ return -1;
+ }
+
+ if (smack_set_label_for_self(seclabel->label) < 0) {
+ virReportError(errno,
+ _("unable to set security label '%s'"),
+ seclabel->label);
+
+ return -1;
+ }
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackSetChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ virCommandPtr cmd)
+{
+ virSecurityLabelDefPtr seclabel;
+ int rlbl;
+ char *smackfs_path = NULL;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STRNEQ(SECURITY_SMACK_NAME, seclabel->model)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "\'%s\' model configured for domain, but "
+ "hypervisor driver is \'%s\'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+
+ return -1;
+ }
+
+ /*
+ * Send label to relabel-self interface to allow child to label
+ * its self once it finishes setting up. Apply only if interface is
+ * available and user namespace is enabled.
+ */
+
+ if (STREQ(virSecurityManagerGetDriver(mgr), "LXC")) {
+
+ if (!def->idmap.nuidmap)
+ return 0;
+
+ VIR_DEBUG("Applying label %s to relabel-self interface.",
seclabel->label);
+
+ if (virAsprintf(&smackfs_path, "%s/relabel-self",
smack_smackfs_path()) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to obtain path for smackfs. Is smack enabled?
"));
+ return -1;
+ }
+
+ rlbl = open(smackfs_path, O_WRONLY);
+
+ if (rlbl < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open relabel interface \'%s\' for
writing. Is it "
+ "enabled in the kernel?"),
+ smackfs_path);
+ return -1;
+ }
+
+ if (safewrite(rlbl, seclabel->label, strlen(seclabel->label)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not write to relabel interface
\'%s\'."),
+ smackfs_path);
+ return -1;
+ }
+
+ VIR_FORCE_CLOSE(rlbl);
+ }
+
+ /* save in cmd to be set after fork/before child process is exec'ed */
+ virCommandSetSmackLabel(cmd, seclabel->label);
+ VIR_DEBUG("save smack label in cmd %s", seclabel->label);
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackSetAllLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ const char *stdin_path)
+{
+
+ size_t i;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ VIR_DEBUG("set image security label before");
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (def->disks[i]->src->type == VIR_STORAGE_TYPE_DIR) {
+ VIR_WARN("Unable to relabel directory tree %s for disk %s",
+ def->disks[i]->src->path, def->disks[i]->dst);
+ continue;
+ }
+
+ VIR_DEBUG("set image security label");
+
+ if (virSecuritySmackSetImageLabel(mgr,
+ def, def->disks[i]->src) < 0)
+ return -1;
+ }
+
+ VIR_DEBUG("set image security label after");
+
+ for (i = 0; i< def->nhostdevs; i++) {
+ if (virSecuritySmackSetHostdevLabel(mgr,
+ def,
+ def->hostdevs[i],
+ NULL) < 0)
+ return -1;
+
+ }
+
+ if (stdin_path) {
+ if (setxattr(stdin_path, "security.SMACK64",
seclabel->imagelabel,
+ strlen(seclabel->imagelabel) + 1, 0)< 0 &&
+ virFileIsSharedFS(stdin_path) != 1)
+ return -1;
+ }
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackRestoreAllLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ bool migrated ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ virSecurityLabelDefPtr seclabel;
+
+ VIR_DEBUG("Restoring security label on %s", def->name);
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ for (i = 0; i < def->ndisks; i++) {
+
+ if (virSecuritySmackRestoreImageLabelInt(mgr,
+ def,
+ def->disks[i]->src,
+ migrated) < 0)
+
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+
+static int
+virSecuritySmackSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ const char *savefile)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ return virSecuritySmackSetPathLabel(savefile, seclabel->imagelabel);
+}
+
+static int
+virSecuritySmackRestoreSavedStateLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ const char *savefile)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ return virSecuritySmackRestoreFileLabel(mgr, savefile);
+}
+
+static int
+virSecuritySmackSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ int fd)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->imagelabel == NULL)
+ return 0;
+
+ return virSecuritySmackSetFileLabel(fd, seclabel->imagelabel);
+
+}
+
+static int
+virSecuritySmackSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ const char *path)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->imagelabel == NULL)
+ return 0;
+
+ if (virSecuritySmackSetPathLabel(path, seclabel->imagelabel) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+virSecuritySmackSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ int fd)
+{
+ struct stat buf;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+
+ if (fstat(fd, &buf) < 0) {
+ virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
+ return -1;
+ }
+
+ if ((buf.st_mode & S_IFMT) != S_IFCHR) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("tap fd %d is not character device"), fd);
+ return -1;
+ }
+
+ return virSecuritySmackSetFileLabel(fd, seclabel->label);
+
+}
+
+static char *
+virSecuritySmackGetSecurityMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ char *opts = NULL;
+ virSecurityLabelDefPtr seclabel;
+
+ if ((seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME))) {
+ if (!seclabel->imagelabel) {
+ if (!seclabel->label)
+ seclabel->imagelabel = virSecuritySmackGetLabelName(def);
+ else
+ seclabel->imagelabel = seclabel->label;
+ }
+ if (seclabel->imagelabel &&
+ virAsprintf(&opts,
+ ",smackfsdef=\"%s\"",
+ (const char*) seclabel->imagelabel) < 0)
+ return NULL;
+ }
+
+ if (!opts && VIR_STRDUP(opts, "") < 0)
+ return NULL;
+
+ return opts;
+
+}
+
+static const char *
+virSecuritySmackGetBaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ int virtType ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+virSecurityDriver virSecurityDriverSmack = {
+ .privateDataLen = 0,
+ .name = SECURITY_SMACK_NAME,
+ .probe = virSecuritySmackSecurityDriverProbe,
+ .open = virSecuritySmackSecurityDriverOpen,
+ .close = virSecuritySmackSecurityDriverClose,
+
+ .getModel = virSecuritySmackSecurityDriverGetModel,
+ .getDOI = virSecuritySmackSecurityDriverGetDOI,
+
+ .domainSecurityVerify = virSecuritySmackSecurityVerify,
+
+ .domainSetSecurityDiskLabel = virSecuritySmackSetDiskLabel,
+ .domainRestoreSecurityDiskLabel = virSecuritySmackRestoreDiskLabel,
+
+ .domainSetSecurityImageLabel = virSecuritySmackSetImageLabel,
+ .domainRestoreSecurityImageLabel = virSecuritySmackRestoreImageLabel,
+
+ .domainSetSecurityDaemonSocketLabel = virSecuritySmackSetDaemonSocketLabel,
+ .domainSetSecuritySocketLabel = virSecuritySmackSetSocketLabel,
+ .domainClearSecuritySocketLabel = virSecuritySmackClearSocketLabel,
+
+ .domainGenSecurityLabel = virSecuritySmackGenLabel,
+ .domainReserveSecurityLabel = virSecuritySmackReserveLabel,
+ .domainReleaseSecurityLabel = virSecuritySmackReleaseLabel,
+
+ .domainGetSecurityProcessLabel = virSecuritySmackGetProcessLabel,
+ .domainSetSecurityProcessLabel = virSecuritySmackSetProcessLabel,
+ .domainSetSecurityChildProcessLabel = virSecuritySmackSetChildProcessLabel,
+
+ .domainSetSecurityAllLabel = virSecuritySmackSetAllLabel,
+ .domainRestoreSecurityAllLabel = virSecuritySmackRestoreAllLabel,
+
+ .domainSetSecurityHostdevLabel = virSecuritySmackSetHostdevLabel,
+ .domainRestoreSecurityHostdevLabel = virSecuritySmackRestoreHostdevLabel,
+
+ .domainSetSavedStateLabel = virSecuritySmackSetSavedStateLabel,
+ .domainRestoreSavedStateLabel = virSecuritySmackRestoreSavedStateLabel,
+
+ .domainSetSecurityImageFDLabel = virSecuritySmackSetImageFDLabel,
+ .domainSetSecurityImagePathLabel = virSecuritySmackSetImagePathLabel,
+ .domainSetSecurityTapFDLabel = virSecuritySmackSetTapFDLabel,
+
+ .domainGetSecurityMountOptions = virSecuritySmackGetSecurityMountOptions,
+
+ .getBaseLabel = virSecuritySmackGetBaseLabel,
+
+};
diff --git a/src/security/security_smack.h b/src/security/security_smack.h
new file mode 100644
index 0000000..3d9fad9
--- /dev/null
+++ b/src/security/security_smack.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Cisco Systems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Hongliang Liang <hliang@bupt.edu<mailto:hliang@bupt.edu>,cn>
+ * Changyao Han <changyao@bupt.edu.cn<mailto:changyao@bupt.edu.cn>>
+ * Raghuram S. Sudhaakar
<rssudhaakar@gmail.com<mailto:rssudhaakar@gmail.com>>
+ * Randy Aybar <raybar@cisco.com<mailto:raybar@cisco.com>>
+ */
+
+#ifndef __VIR_SECURITY_SMACK_H__
+# define __VIR_SECURITY_SMACK_H__
+
+# include "security_driver.h"
+
+int virSecuritySmackSockCreate(const char *label, const char *attr);
+
+
+extern virSecurityDriver virSecurityDriverSmack;
+
+# define SMACK_PREFIX "smack-"
+
+#endif /* __VIR_SECURITY_SMACK_H__ */
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index 3ea2751..e30f003 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -495,6 +495,14 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr,
}
static int
+virSecurityStackSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr vm ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int
virSecurityStackSetTapFDLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
int fd)
@@ -659,6 +667,7 @@ virSecurityDriver virSecurityDriverStack = {
.domainRestoreSavedStateLabel = virSecurityStackRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = virSecurityStackSetImageFDLabel,
+ .domainSetSecurityImagePathLabel = virSecurityStackSetImagePathLabel,
.domainSetSecurityTapFDLabel = virSecurityStackSetTapFDLabel,
.domainGetSecurityMountOptions = virSecurityStackGetMountOptions,
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 027cb64..cdcb3a2 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -41,6 +41,9 @@
#if defined(WITH_SECDRIVER_APPARMOR)
# include <sys/apparmor.h>
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+# include <sys/smack.h>
+#endif
#define __VIR_COMMAND_PRIV_H_ALLOW__
#include "vircommandpriv.h"
@@ -134,6 +137,10 @@ struct _virCommand {
#if defined(WITH_SECDRIVER_APPARMOR)
char *appArmorProfile;
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+ char *smackLabel;
+#endif
+
int mask;
};
@@ -722,6 +729,30 @@ virExec(virCommandPtr cmd)
}
# endif
+# if defined(WITH_SECDRIVER_SMACK)
+ if (cmd->smackLabel) {
+ VIR_DEBUG("Setting child security label to %s", cmd->smackLabel);
+
+ if (smack_set_label_for_self(cmd->smackLabel) < 0) {
+ virReportSystemError(errno,
+ _("unable to set Smack label '%s' "
+ "for '%s'"),
+ cmd->smackLabel, cmd->args[0]);
+ goto fork_error;
+ }
+ }
+# endif
+
+/*
+ * if (smack_new_label_from_self(&label) == -1)
+ * {
+ * goto fork_error;
+ * }
+ * VIR_DEBUG("smack label is %s",label);
+ * free(label);
+ *
+ *
+ */
/* The steps above may need to do something privileged, so we delay
* setuid and clearing capabilities until the last minute.
*/
@@ -1197,6 +1228,35 @@ virCommandSetAppArmorProfile(virCommandPtr cmd,
}
+
+/**
+ * virCommandSetSmackLabel:
+ * @cmd: the command to modify
+ * @label: the Smack label to use for the child process
+ *
+ * Saves a copy of @label to use when setting the Smack context
+ * label (write to /proc/self/attr/current ) after the child process has
+ * been started. If Smack isn't compiled into libvirt, or if label is
+ * NULL, nothing will be done.
+ */
+void
+virCommandSetSmackLabel(virCommandPtr cmd,
+ const char *label ATTRIBUTE_UNUSED)
+
+{
+ if (!cmd || cmd->has_error)
+ return;
+
+#if defined(WITH_SECDRIVER_SMACK)
+ VIR_FREE(cmd->smackLabel);
+ if (VIR_STRDUP_QUIET(cmd->smackLabel, label) < 0)
+ cmd->has_error = ENOMEM;
+#endif
+ return;
+
+}
+
+
/**
* virCommandDaemonize:
* @cmd: the command to modify
@@ -2796,6 +2856,9 @@ virCommandFree(virCommandPtr cmd)
#if defined(WITH_SECDRIVER_APPARMOR)
VIR_FREE(cmd->appArmorProfile);
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+ VIR_FREE(cmd->smackLabel);
+#endif
VIR_FREE(cmd);
}
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index 198da2f..dfc8a65 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -88,6 +88,9 @@ void virCommandSetSELinuxLabel(virCommandPtr cmd,
void virCommandSetAppArmorProfile(virCommandPtr cmd,
const char *profile);
+void virCommandSetSmackLabel(virCommandPtr cmd,
+ const char *label);
+
void virCommandDaemonize(virCommandPtr cmd);
void virCommandNonblockingFDs(virCommandPtr cmd);