First time RFC/mailing list/community submission/etc. so please forgive if not in the appropriate format. -Randy --- Incorporate changes that enable native support for Smack within Libvirt. -------------------------------------------------------------------------------- Table of Contents i. Contributions I. Introduction II. Implementations & Changes III. Patch -------------------------------------------------------------------------------- i. Contributions Below is a list of contributors of the patch described in this document: -Raghuram S. Sudhaakar rsudhaak@xxxxxxxxx, Cisco Systems, Inc. San Jose, California, USA -Randy Aybar raybar@xxxxxxxxx, Cisco Systems, Inc. San Jose, California, USA -Hongliang Liang hliang@xxxxxxxxxxx, Beijing University of Posts and Telecommunications (BUPT), Beijing, China -Changyao Han changyao@xxxxxxxxxxx, Beijing University of Posts and Telecommunications (BUPT), Beijing, China Portion of changes are based on existing security drivers within Libvirt: -James Morris <jmorris@xxxxxxxxx> (SELinux security driver) -Jamie Strandboge <jamie@xxxxxxxxxxxxx> (AppArmor security driver) -------------------------------------------------------------------------------- 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. Brief history of code authorship We [folks at Cisco] started work on implementing a Libvirt security driver that would allow enable Smack support. The goal was to ensure that Libvirt would be able to enforce security policies using this lightweight module in order secure our Linux containers running on platforms. 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. Since the initial driver acquired from the university lacked support for LXC-style VMs, our role was to implement that portion. This patch includes the collaborative efforts in order to bring a more complete Smack driver to Libvirt. -------------------------------------------------------------------------------- II. Implementation & Changes Detailed changes described in this section will be limited to those made by Cisco engineers. The implementation made by researchers at BUPT can be read in their research paper and is based on libvirt v1.1.4. Publication information: A Lightweight Security Isolation Approach for Virtual Machines Deployment by Hongliang Liang, Changyao Han, Daijie Zhang, and Dongyang Wu Information Security and Cryptology 10th International Conference, Inscrypt 2014, Beijing, China, December 13-15, 2014, Revised Selected Papers Editors: Lin, Dongdai, Young, Moti, Zhou, Jianying (Eds.) Initial code changes made by BUPT can be located at the following GitHub repository as patches labeled for Libvirt 1.1.4: https://github.com/rssudhaakar/libvirt-smack 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. Changes made by authors Raghuram S Sudhaakar and Randy Aybar are two major parts - 1) Firstly, the code was updated to accommodate the various interface changes made in libvirt v1.2+. 2) Secondly, make the SMACK security driver work with LXC driver The following is the details on the changes made for #2 above – A major changes involves modifying the security driver interface to include an additional hook/function. This decision was made after encountering several issues while applying labels to certain components of a container as well as consideration for minimizing the impact of the other security drivers. Details can be found under security driver changes. 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/ 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. 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! 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. 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. 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. -------------------------------------------------------------------------------- III. Patch This patch has been created for patching Libvirt 1.3.1 base source code. 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"]) + + + dnl DTrace static probes AC_ARG_WITH([dtrace], [AS_HELP_STRING([--with-dtrace], @@ -2867,6 +2889,7 @@ AC_MSG_NOTICE([Security Drivers]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ SELinux: $with_secdriver_selinux ($SELINUX_MOUNT)]) AC_MSG_NOTICE([AppArmor: $with_secdriver_apparmor (install profiles: $with_apparmor_profiles)]) +AC_MSG_NOTICE([Smack: $with_secdriver_smack]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Driver Loadable Modules]) AC_MSG_NOTICE([]) @@ -2897,6 +2920,7 @@ LIBVIRT_RESULT_READLINE LIBVIRT_RESULT_SANLOCK LIBVIRT_RESULT_SASL LIBVIRT_RESULT_SELINUX +LIBVIRT_RESULT_SMACK LIBVIRT_RESULT_SSH2 LIBVIRT_RESULT_SYSTEMD_DAEMON LIBVIRT_RESULT_UDEV diff --git a/m4/virt-smack.m4 b/m4/virt-smack.m4 new file mode 100644 index 0000000..f23ffdc --- /dev/null +++ b/m4/virt-smack.m4 @@ -0,0 +1,48 @@ +dnl The libsmack.so library +dnl +dnl Copyright (C) 2013 changyaoh. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +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 + else + SMACK_MOUNT=$with_smack_mount + fi + AC_MSG_RESULT([$SMACK_MOUNT]) + AC_DEFINE_UNQUOTED([SMACK_MOUNT], ["$SMACK_MOUNT"], [Smack mount point]) + fi +]) + +AC_DEFUN([LIBVIRT_RESULT_SMACK],[ + LIBVIRT_RESULT_LIB([SMACK]) +]) diff --git a/src/Makefile.am b/src/Makefile.am index aa5ab69..d367954 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,6 +68,10 @@ if WITH_SECDRIVER_APPARMOR SECDRIVER_CFLAGS += $(APPARMOR_CFLAGS) SECDRIVER_LIBS += $(APPARMOR_LIBS) endif WITH_SECDRIVER_APPARMOR +if WITH_SECDRIVER_SMACK +SECDRIVER_CFLAGS += $(SMACK_CFLAGS) +SECDRIVER_LIBS += $(SMACK_LIBS) +endif WITH_SECDRIVER_SMACK if WITH_NETWORK UUID=$(shell uuidgen 2>/dev/null) @@ -1005,6 +1009,9 @@ SECURITY_DRIVER_SELINUX_SOURCES = \ SECURITY_DRIVER_APPARMOR_SOURCES = \ security/security_apparmor.h security/security_apparmor.c +SECURITY_DRIVER_SMACK_SOURCES = \ + security/security_smack.h security/security_smack.c + ACCESS_DRIVER_GENERATED = \ access/viraccessapicheck.h \ access/viraccessapicheck.c \ @@ -1734,6 +1741,10 @@ if WITH_SECDRIVER_APPARMOR libvirt_security_manager_la_SOURCES += $(SECURITY_DRIVER_APPARMOR_SOURCES) libvirt_security_manager_la_CFLAGS += $(APPARMOR_CFLAGS) endif WITH_SECDRIVER_APPARMOR +if WITH_SECDRIVER_SMACK +libvirt_security_manager_la_SOURCES += $(SECURITY_DRIVER_SMACK_SOURCES) +libvirt_security_manager_la_CFLAGS += $(SMACK_CFLAGS) +endif WITH_SECDRIVER_SMACK libvirt_driver_access_la_SOURCES = \ $(ACCESS_DRIVER_SOURCES) $(ACCESS_DRIVER_GENERATED) @@ -1865,6 +1876,7 @@ EXTRA_DIST += \ $(NWFILTER_DRIVER_SOURCES) \ $(SECURITY_DRIVER_SELINUX_SOURCES) \ $(SECURITY_DRIVER_APPARMOR_SOURCES) \ + $(SECURITY_DRIVER_SMACK_SOURCES) \ $(SECRET_DRIVER_SOURCES) \ $(VBOX_DRIVER_EXTRA_DIST) \ $(VMWARE_DRIVER_SOURCES) \ diff --git a/src/libvirt-lxc.c b/src/libvirt-lxc.c index 8553570..4a26e80 100644 --- a/src/libvirt-lxc.c +++ b/src/libvirt-lxc.c @@ -3,6 +3,7 @@ * APIs. * * Copyright (C) 2012-2014 Red Hat, Inc. + * 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 @@ -18,7 +19,9 @@ * License along with this library. If not, see * <http://www.gnu.org/licenses/>. * - * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + * Authors: Daniel P. Berrange <berrange@xxxxxxxxxx> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> */ #include <config.h> @@ -36,6 +39,9 @@ #ifdef WITH_APPARMOR # include <sys/apparmor.h> #endif +#ifdef WITH_SMACK +# include <sys/smack.h> +#endif #define VIR_FROM_THIS VIR_FROM_NONE @@ -256,6 +262,20 @@ virDomainLxcEnterSecurityLabel(virSecurityModelPtr model, _("Support for AppArmor is not enabled")); goto error; #endif + } else if (STREQ(model->model, "smack")) { +#ifdef WITH_SMACK + if (smack_set_label_for_self(label->label) < 0) { + virReportError(errno, + _("unable to set security label '%s'"), + label->label); + + goto error; + } +#else + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Support for Smack is not enabled")); + goto error; +#endif } else { virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Security model %s cannot be entered"), 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 @@ -1,13 +1,16 @@ /* * Copyright (C) 2008-2015 Red Hat, Inc. * Copyright (C) 2008 IBM Corp. - * Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. + * Copyright (C) 2015 Cisco Systems, Inc. * * lxc_container.c: file description * * Authors: * David L. Leskovec <dlesko at linux.vnet.ibm.com> * Daniel P. Berrange <berrange@xxxxxxxxxx> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -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; + 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) { + 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 @@ -1,11 +1,14 @@ /* * Copyright (C) 2010-2015 Red Hat, Inc. - * Copyright IBM Corp. 2008 - * + * Copyright (C) 2008 IBM Corp. + * Copyright (C) 2015 Cisco Systems, Inc. + * * lxc_controller.c: linux container process controller * * Authors: * David L. Leskovec <dlesko at linux.vnet.ibm.com> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -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; 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 || + (virSecurityManagerSetImagePathLabel(ctrl->securityManager, + ctrl->def, + devpts) < 0)) + goto cleanup; + ret = 0; cleanup: @@ -2227,6 +2246,11 @@ virLXCControllerSetupConsoles(virLXCControllerPtr ctrl, if (lxcContainerChown(ctrl->def, ttyHostPath) < 0) goto cleanup; + if (virSecurityManagerSetImagePathLabel(ctrl->securityManager, + ctrl->def, + ttyHostPath) < 0) + goto cleanup; + VIR_FREE(ttyHostPath); } diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 2cf333d..c013443 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -986,6 +986,14 @@ AppArmorSetFDLabel(virSecurityManagerPtr mgr, return reload_profile(mgr, def, fd_path, true); } +static int +AppArmorSetPathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) +{ + return 0; +} + static char * AppArmorGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr vm ATTRIBUTE_UNUSED) @@ -1043,6 +1051,7 @@ virSecurityDriver virAppArmorSecurityDriver = { .domainRestoreSavedStateLabel = AppArmorRestoreSavedStateLabel, .domainSetSecurityImageFDLabel = AppArmorSetFDLabel, + .domainSetSecurityImagePathLabel = AppArmorSetPathLabel, .domainSetSecurityTapFDLabel = AppArmorSetFDLabel, .domainGetSecurityMountOptions = AppArmorGetMountOptions, diff --git a/src/security/security_dac.c b/src/security/security_dac.c index a09aba5..1af5175 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -1519,6 +1519,14 @@ virSecurityDACSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, } static int +virSecurityDACSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int virSecurityDACSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainDefPtr def ATTRIBUTE_UNUSED, int fd ATTRIBUTE_UNUSED) @@ -1601,6 +1609,7 @@ virSecurityDriver virSecurityDriverDAC = { .domainRestoreSavedStateLabel = virSecurityDACRestoreSavedStateLabel, .domainSetSecurityImageFDLabel = virSecurityDACSetImageFDLabel, + .domainSetSecurityImagePathLabel = virSecurityDACSetImagePathLabel, .domainSetSecurityTapFDLabel = virSecurityDACSetTapFDLabel, .domainGetSecurityMountOptions = virSecurityDACGetMountOptions, diff --git a/src/security/security_driver.c b/src/security/security_driver.c index 4800d52..3ca3766 100644 --- a/src/security/security_driver.c +++ b/src/security/security_driver.c @@ -35,6 +35,10 @@ # include "security_apparmor.h" #endif +#ifdef WITH_SECDRIVER_SMACK +# include "security_smack.h" +#endif + #include "security_nop.h" #define VIR_FROM_THIS VIR_FROM_SECURITY @@ -48,6 +52,9 @@ static virSecurityDriverPtr security_drivers[] = { #ifdef WITH_SECDRIVER_APPARMOR &virAppArmorSecurityDriver, #endif +#ifdef WITH_SECDRIVER_SMACK + &virSecurityDriverSmack, +#endif &virSecurityDriverNop, /* Must always be last, since it will always probe */ }; diff --git a/src/security/security_driver.h b/src/security/security_driver.h index 784b0de..c477f93 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2008, 2010-2013 Red Hat, Inc. - * + * Copyright (C) 2015 Cisco System, 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 @@ -17,7 +18,8 @@ * * Authors: * James Morris <jmorris@xxxxxxxxx> - * + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> */ #ifndef __VIR_SECURITY_H__ # define __VIR_SECURITY_H__ @@ -104,6 +106,9 @@ typedef int (*virSecurityDomainSecurityVerify) (virSecurityManagerPtr mgr, typedef int (*virSecurityDomainSetImageFDLabel) (virSecurityManagerPtr mgr, virDomainDefPtr def, int fd); +typedef int (*virSecurityDomainSetImagePathLabel) (virSecurityManagerPtr mgr, + virDomainDefPtr def, + const char *path); typedef int (*virSecurityDomainSetTapFDLabel) (virSecurityManagerPtr mgr, virDomainDefPtr def, int fd); @@ -165,6 +170,7 @@ struct _virSecurityDriver { virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel; virSecurityDomainSetImageFDLabel domainSetSecurityImageFDLabel; + virSecurityDomainSetImagePathLabel domainSetSecurityImagePathLabel; virSecurityDomainSetTapFDLabel domainSetSecurityTapFDLabel; virSecurityDomainGetMountOptions domainGetSecurityMountOptions; diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 07a0522..b782eab 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -2,6 +2,7 @@ * security_manager.c: Internal security manager API * * Copyright (C) 2010-2014 Red Hat, Inc. + * 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 @@ -17,7 +18,9 @@ * License along with this library. If not, see * <http://www.gnu.org/licenses/>. * - * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + * Authors: Daniel P. Berrange <berrange@xxxxxxxxxx> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> */ #include <config.h> @@ -916,6 +919,23 @@ virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr, return -1; } +int +virSecurityManagerSetImagePathLabel(virSecurityManagerPtr mgr, + virDomainDefPtr vm, + const char* path) +{ + if (mgr->drv->domainSetSecurityImagePathLabel) { + int ret; + virObjectLock(mgr); + ret = mgr->drv->domainSetSecurityImagePathLabel(mgr,vm,path); + virObjectUnlock(mgr); + return ret; + } + + virReportUnsupportedError(); + return -1; +} + int virSecurityManagerSetTapFDLabel(virSecurityManagerPtr mgr, diff --git a/src/security/security_manager.h b/src/security/security_manager.h index e534e31..35e8a3b 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -2,7 +2,8 @@ * security_manager.h: Internal security manager API * * Copyright (C) 2010-2013 Red Hat, Inc. - * + * 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 @@ -18,6 +19,8 @@ * <http://www.gnu.org/licenses/>. * * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> */ #ifndef VIR_SECURITY_MANAGER_H__ @@ -143,6 +146,9 @@ int virSecurityManagerVerify(virSecurityManagerPtr mgr, int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, int fd); +int virSecurityManagerSetImagePathLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, + const char *path); int virSecurityManagerSetTapFDLabel(virSecurityManagerPtr mgr, virDomainDefPtr vm, int fd); diff --git a/src/security/security_nop.c b/src/security/security_nop.c index 951125d..3d4d47a 100644 --- a/src/security/security_nop.c +++ b/src/security/security_nop.c @@ -236,6 +236,13 @@ virSecurityDomainSetImageLabelNop(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, return 0; } +static int +virSecurityDomainSetPathLabelNop(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def ATTRIBUTE_UNUSED, + const char* path ATTRIBUTE_UNUSED) +{ + return 0; +} virSecurityDriver virSecurityDriverNop = { .privateDataLen = 0, @@ -277,6 +284,7 @@ virSecurityDriver virSecurityDriverNop = { .domainRestoreSavedStateLabel = virSecurityDomainRestoreSavedStateLabelNop, .domainSetSecurityImageFDLabel = virSecurityDomainSetFDLabelNop, + .domainSetSecurityImagePathLabel = virSecurityDomainSetPathLabelNop, .domainSetSecurityTapFDLabel = virSecurityDomainSetFDLabelNop, .domainGetSecurityMountOptions = virSecurityDomainGetMountOptionsNop, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 9e98635..4b510e1 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -2459,6 +2459,14 @@ virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, } static int +virSecuritySELinuxSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr, virDomainDefPtr def, int fd) @@ -2639,6 +2647,7 @@ virSecurityDriver virSecurityDriverSELinux = { .domainRestoreSavedStateLabel = virSecuritySELinuxRestoreSavedStateLabel, .domainSetSecurityImageFDLabel = virSecuritySELinuxSetImageFDLabel, + .domainSetSecurityImagePathLabel = virSecuritySELinuxSetImagePathLabel, .domainSetSecurityTapFDLabel = virSecuritySELinuxSetTapFDLabel, .domainGetSecurityMountOptions = virSecuritySELinuxGetSecurityMountOptions, 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@xxxxxxxxxxx> + * Changyao Han <changyao@xxxxxxxxxxx> + * + * Updated to libvirt v1.2.15: (Original was written for libvirt v1.1.4) + * Raghuram S. Sudhaakar <rsudhaak@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> + * + * Based on security_selinux.c by James Morris <jmorris@xxxxxxxxx> + * and security_apparmor.c by Jamie Strandboge <jamie@xxxxxxxxxxxxx> + * + * Smack scurity driver. + * + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/xattr.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <fcntl.h> +#include <sys/smack.h> +#include <errno.h> +#include <unistd.h> +#include <wait.h> +#include <dirent.h> +#include <stdlib.h> + + +#include "security_smack.h" +#include "virerror.h" +#include "viralloc.h" +#include "datatypes.h" +#include "viruuid.h" +#include "virlog.h" +#include "virpci.h" +#include "virusb.h" +#include "virscsi.h" +#include "virstoragefile.h" +#include "virfile.h" +#include "configmake.h" +#include "vircommand.h" +#include "virhash.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_SECURITY +VIR_LOG_INIT("security.security_smack"); + +#define SECURITY_SMACK_VOID_DOI "0" +#define SECURITY_SMACK_NAME "smack" + +typedef struct _SmackCallbackData SmackCallbackData; +typedef SmackCallbackData *SmackCallbackDataPtr; + +struct _SmackCallbackData { + virSecurityManagerPtr manager; + virSecurityLabelDefPtr secdef; +}; + +static char * +virSecuritySmackGetLabelName(virDomainDefPtr def) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char *name = NULL; + + virUUIDFormat(def->uuid, uuidstr); + if (virAsprintf(&name, "%s%s", SMACK_PREFIX, uuidstr) < 0) + return NULL; + + return name; +} + +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; + 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; + +} + +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); + } + else { + fd = open(path, O_TRUNC); + VIR_FREE(path); + if (fd < 0) + return -1; + ret = 0; + } + + close(fd); + + return (ret < 0) ? -1 : 0; + +} + +static int +virSecuritySmackSetPathLabel(const char *path, const char *tlabel) +{ + char * elabel = NULL; + + VIR_INFO("Setting Smack label on '%s' to '%s'", path, tlabel); + + if (smack_set_label_for_path(path, "security.SMACK64", 0, tlabel) < 0) { + int setfilelabel_errno = errno; + + if (smack_new_label_from_path(path, "security.SMACK64", 0, &elabel) >= 0) { + if (STREQ(tlabel, elabel)) { + VIR_FREE(elabel); + /* It's alright, there's nothing to change anyway. */ + return 0; + } + VIR_FREE(elabel); + } + + /* if the error complaint is related to an image hosted on + * an nfs mount, or a usbfs/sysfs filesystem not supporting + * labelling, then just ignore it & hope for the best. + */ + + if (setfilelabel_errno != EOPNOTSUPP && setfilelabel_errno != ENOTSUP) { + virReportSystemError(setfilelabel_errno, + _("unable to set security context '%s' on '%s'"), + tlabel, path); + return -1; + + } else { + const char *msg; + if ((virFileIsSharedFS(path) == 1)) { + msg = _("Setting security context '%s' on '%s' not supported. "); + VIR_WARN(msg, tlabel, path); + } else { + VIR_INFO("Setting security context '%s' on '%s' not supported", + tlabel, path); + + } + + } + + } + return 0; + +} + +static int +virSecuritySmackSetHostdevLabelHelper(const char *file, void *opaque) +{ + virSecurityLabelDefPtr seclabel; + virDomainDefPtr def = opaque; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + if (seclabel == NULL) + return -1; + return virSecuritySmackSetPathLabel(file, seclabel->imagelabel); +} + +static int +virSecuritySmackSetUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, void *opaque) +{ + return virSecuritySmackSetHostdevLabelHelper(file, opaque); +} + + +static int +virSecuritySmackSetPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, void *opaque) +{ + return virSecuritySmackSetHostdevLabelHelper(file, opaque); +} + +static int +virSecuritySmackSetSCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, void *opaque) +{ + return virSecuritySmackSetHostdevLabelHelper(file, opaque); +} + + +static int +virSecuritySmackRestoreFileLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + const char *path) +{ + struct stat buf; + int ret = -1; + char *newpath = NULL; + char ebuf[1024]; + + VIR_INFO("Restoring Smack label on '%s'", path); + + if (virFileResolveLink(path, &newpath) < 0) { + VIR_WARN("cannot resolve symlink %s: %s", path, + virStrerror(errno, ebuf, sizeof(ebuf))); + goto err; + } + + if (stat(newpath, &buf) != 0) { + VIR_WARN("cannot stat %s: %s", newpath, + virStrerror(errno, ebuf, sizeof(ebuf))); + goto err; + } + + ret = virSecuritySmackSetPathLabel(newpath, "smack-unused"); + +err: + VIR_FREE(newpath); + return ret; +} + + +static int +virSecuritySmackRestoreUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + virSecurityManagerPtr mgr = opaque; + + return virSecuritySmackRestoreFileLabel(mgr, file); +} + +static int +virSecuritySmackRestorePCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + virSecurityManagerPtr mgr = opaque; + + return virSecuritySmackRestoreFileLabel(mgr, file); +} + +static int +virSecuritySmackRestoreSCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED, + const char *file, + void *opaque) +{ + virSecurityManagerPtr mgr = opaque; + + return virSecuritySmackRestoreFileLabel(mgr, file); +} + +static int +virSecuritySmackRestoreImageLabelInt(virSecurityManagerPtr mgr, + virDomainDefPtr def, + virStorageSourcePtr src, + bool migrated) +{ + virSecurityLabelDefPtr seclabel; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + + if (seclabel == NULL) + return -1; + + if (!seclabel->relabel) + return 0; + + if (src->readonly || src->shared) + return 0; + + if (!src || src->type == VIR_STORAGE_TYPE_NETWORK) + return 0; + + if (migrated) { + int ret = virFileIsSharedFS(src->path); + if (ret < 0) + return -1; + if (ret == 1) { + VIR_DEBUG("Skipping image label restore on %s because FS is shared", src->path); + return 0; + } + + } + + return virSecuritySmackRestoreFileLabel(mgr, src->path); + +} + +static int +virSecuritySmackSetFileLabel(int fd, char *tlabel) +{ + char *elabel = NULL; + + VIR_INFO("Setting Smack label on fd %d to '%s'", fd, tlabel); + + if (smack_set_label_for_file(fd, "security.SMACK64", tlabel) < 0) { + int fsetfilelabel_errno = errno; + + if (smack_new_label_from_file(fd, "security.SMACK64", &elabel) >= 0) { + if (STREQ(tlabel, elabel)) { + VIR_FREE(elabel); + /* It's alright, there's nothing to change anyway. */ + + return 0; + } + + VIR_FREE(elabel); + } + /* if the error complaint is related to an image hosted on + * an nfs mount, or a usbfs/sysfs filesystem not supporting + * labelling, then just ignore it & hope for the best. + */ + if (fsetfilelabel_errno != EOPNOTSUPP) { + virReportSystemError(fsetfilelabel_errno, + _("unable to set security context '%s' on fd %d"), tlabel, fd); + return -1; + } else { + VIR_INFO("Setting security label '%s' on fd %d not supported", + tlabel, fd); + } + } + return 0; +} + + +static int +virSecuritySmackSetHostdevSubsysLabel(virDomainDefPtr def, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + int ret = -1; + + switch (dev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + { + virUSBDevicePtr usb; + + if (dev->missing) + return 0; + + usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus, + dev->source.subsys.u.usb.device, + vroot); + if (!usb) + goto done; + + ret = virUSBDeviceFileIterate(usb, virSecuritySmackSetUSBLabel, def); + virUSBDeviceFree(usb); + + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + { + virPCIDevicePtr pci = + virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain, + dev->source.subsys.u.pci.addr.bus, + dev->source.subsys.u.pci.addr.slot, + dev->source.subsys.u.pci.addr.function); + + if (!pci) + goto done; + + if (dev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) { + virPCIDeviceFree(pci); + goto done; + } + ret = virSecuritySmackRestorePCILabel(pci, vfioGroupDev, def); + VIR_FREE(vfioGroupDev); + } else { + ret = virPCIDeviceFileIterate(pci, virSecuritySmackSetPCILabel, def); + } + virPCIDeviceFree(pci); + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + { + virDomainHostdevSubsysSCSIHostPtr scsihostsrc = + &(dev->source.subsys.u.scsi.u.host); + virSCSIDevicePtr scsi = + virSCSIDeviceNew(NULL, + scsihostsrc->adapter, scsihostsrc->bus, + scsihostsrc->target, scsihostsrc->unit, + dev->readonly, dev->shareable); + + if (!scsi) + goto done; + + ret = virSCSIDeviceFileIterate(scsi, virSecuritySmackSetSCSILabel, def); + virSCSIDeviceFree(scsi); + + break; + } + + default: + ret = 0; + break; + } + +done: + return ret; +} + +static int +virSecuritySmackSetHostdevCapsLabel(virDomainDefPtr def, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + int ret = -1; + virSecurityLabelDefPtr seclabel; + char *path; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + if (seclabel == NULL) + return -1; + + switch (dev->source.caps.type) { + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: + { + if (vroot) { + if (virAsprintf(&path, "%s/%s", vroot, + dev->source.caps.u.storage.block) < 0) + return -1; + } else { + if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0) + return -1; + } + ret = virSecuritySmackSetPathLabel(path, seclabel->imagelabel); + VIR_FREE(path); + break; + } + + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: + { + if (vroot) { + if (virAsprintf(&path, "%s/%s", vroot, + dev->source.caps.u.misc.chardev) < 0) + return -1; + } else { + if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0) + return -1; + } + ret = virSecuritySmackSetPathLabel(path, seclabel->imagelabel); + VIR_FREE(path); + break; + } + + default: + { + ret = 0; + break; + } + } + + return ret; + +} + +static int +virSecuritySmackSetHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + virSecurityLabelDefPtr seclabel; + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + if (seclabel == NULL) + return -1; + + if (!seclabel->relabel) + return 0; + + switch (dev->mode) { + case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: + return virSecuritySmackSetHostdevSubsysLabel(def, dev, vroot); + + case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES: + return virSecuritySmackSetHostdevCapsLabel(def, dev, vroot); + + default: + return 0; + + } +} + +static int +virSecuritySmackRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + int ret = -1; + + switch (dev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + { + virUSBDevicePtr usb; + + if (dev->missing) + return 0; + + usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus, + dev->source.subsys.u.usb.device, + vroot); + if (!usb) + goto done; + + ret = virUSBDeviceFileIterate(usb, virSecuritySmackRestoreUSBLabel, mgr); + virUSBDeviceFree(usb); + + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + { + virPCIDevicePtr pci = + virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain, + dev->source.subsys.u.pci.addr.bus, + dev->source.subsys.u.pci.addr.slot, + dev->source.subsys.u.pci.addr.function); + + if (!pci) + goto done; + + if (dev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci); + + if (!vfioGroupDev) { + virPCIDeviceFree(pci); + goto done; + } + ret = virSecuritySmackRestorePCILabel(pci, vfioGroupDev, mgr); + VIR_FREE(vfioGroupDev); + } else { + ret = virPCIDeviceFileIterate(pci, virSecuritySmackRestorePCILabel, mgr); + } + virPCIDeviceFree(pci); + break; + } + + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: + { + virDomainHostdevSubsysSCSIHostPtr scsihostsrc = + &(dev->source.subsys.u.scsi.u.host); + virSCSIDevicePtr scsi = + virSCSIDeviceNew(NULL, + scsihostsrc->adapter, scsihostsrc->bus, + scsihostsrc->target, scsihostsrc->unit, + dev->readonly, dev->shareable); + + if (!scsi) + goto done; + + ret = virSCSIDeviceFileIterate(scsi, virSecuritySmackRestoreSCSILabel, mgr); + virSCSIDeviceFree(scsi); + + break; + } + + default: + { + ret = 0; + break; + } + } + +done: + return ret; + +} + +static int +virSecuritySmackRestoreHostdevCapsLabel(virSecurityManagerPtr mgr, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + int ret = -1; + char *path; + + switch (dev->source.caps.type) { + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: + { + if (vroot) { + if (virAsprintf(&path, "%s/%s", vroot, + dev->source.caps.u.storage.block) < 0) + return -1; + } else { + if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0) + return -1; + } + ret = virSecuritySmackRestoreFileLabel(mgr, path); + VIR_FREE(path); + break; + } + + case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: + { + if (vroot) { + if (virAsprintf(&path, "%s/%s", vroot, + dev->source.caps.u.misc.chardev) < 0) + return -1; + } else { + if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0) + return -1; + } + ret = virSecuritySmackRestoreFileLabel(mgr, path); + VIR_FREE(path); + break; + } + + default: + ret = 0; + break; + } + + return ret; +} + +static int +virSecuritySmackRestoreHostdevLabel(virSecurityManagerPtr mgr, + virDomainDefPtr def, + virDomainHostdevDefPtr dev, + const char *vroot) +{ + virSecurityLabelDefPtr seclabel; + + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + if (seclabel == NULL) + return -1; + + if (!seclabel->relabel) + return 0; + + switch (dev->mode) { + case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS: + return virSecuritySmackRestoreHostdevSubsysLabel(mgr, dev, vroot); + + case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES: + return virSecuritySmackRestoreHostdevCapsLabel(mgr, dev, vroot); + + default: + return 0; + } +} + +/*Called on libvirtd startup to see if Smack is available*/ +static int +virSecuritySmackSecurityDriverProbe(const char *virtDriver) +{ + if (!smack_smackfs_path() || NULL == virtDriver) + return SECURITY_DRIVER_DISABLE; + + return SECURITY_DRIVER_ENABLE; + +} + +/*Security dirver initialization .*/ +static int +virSecuritySmackSecurityDriverOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +virSecuritySmackSecurityDriverClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) +{ + return 0; +} + +static const char * +virSecuritySmackSecurityDriverGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) +{ + return SECURITY_SMACK_NAME; +} + +static const char * +virSecuritySmackSecurityDriverGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED) +{ + return SECURITY_SMACK_VOID_DOI; +} + +static int +virSecuritySmackSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + virSecurityLabelDefPtr seclabel; + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + if (seclabel == NULL) + return -1; + + if (!STREQ(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 (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC){ + if (smack_label_length(seclabel->label) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid security label %s"), seclabel->label); + return -1; + } + } + + return 0; + +} + +static int +virSecuritySmackSetDiskLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainDefPtr def, + virDomainDiskDefPtr disk) +{ + virSecurityLabelDefPtr seclabel; + seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME); + + if (seclabel == NULL) + return -1; + + if (!seclabel->relabel) + return 0; + + if (disk->src->type == VIR_STORAGE_TYPE_NETWORK) + return 0; + + VIR_DEBUG("set disk image security label before"); + + if (setxattr(disk->src->path, "security.SMACK64", seclabel->imagelabel, + strlen(seclabel->imagelabel) + 1, 0) < 0) + return -1; + + VIR_DEBUG("disk image %s", disk->src->path); + VIR_DEBUG("set disk image security label after"); + + return 0; + +} + +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)) { + 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: + + 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)) { + 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)) { + 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); + free(label_name); + return -1; + } + + strcpy(sec->label, label_name); + free(label_name); + /*Smack default enforced*/ + sec->enforcing = 1; + + return 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, + _("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(write(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..9a865cb --- /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@xxxxxxxx,cn> + * Changyao Han <changyao@xxxxxxxxxxx> + * Raghuram S. Sudhaakar <rssudhaakar@xxxxxxxxx> + * Randy Aybar <raybar@xxxxxxxxx> + */ + +#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 00d1fa7..38551ca 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 fe7bf34..7094e89 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); -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list