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> 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 file.

Updated docs/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 b/configure.ac
> index 047ad3b..12d0bb8 100644
> --- a/configure.ac
> +++ b/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>
> + *   Changyao Han <changyao@bupt.edu.cn>
> + *
> + * Updated to libvirt v1.2.15: (Original was written for libvirt v1.1.4)
> + *   Raghuram S. Sudhaakar <rsudhaak@cisco.com>
> + *   Randy Aybar <raybar@cisco.com>
> + *
> + *   Based on security_selinux.c by James Morris <jmorris@namei.org>
> + *   and security_apparmor.c by Jamie Strandboge <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
+ *
+ * Author:
+ *   Hongliang Liang <hliang@bupt.edu,cn>
+ *   Changyao Han <changyao@bupt.edu.cn>
+ *   Raghuram S. Sudhaakar <rssudhaakar@gmail.com>
+ *   Randy Aybar <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);