[libvirt] gconfig: Add hostdev support v4
by Zeeshan Ali (Khattak)
Finally I got the time to clean-up and fix the patches. It's been a while last i looked into them already and I got a bit confused at some point so I appologize if I didn't address some of the review comments.
8 years, 5 months
[libvirt] [PATCH REPOST 00/38] Introduce APIs to change daemon's logging settings
by Erik Skultety
Basically the same series as
https://www.redhat.com/archives/libvir-list/2016-March/msg01534.html, just
rebased onto the current HEAD.
Daniel pointed out in 31/38 maybe we do not want to expose an API to set
logging level. Despite the truth being that the functionality of logging levels
can be replaced by logging filters completely, I think that it still provides
us with more convenience than having to specify a big bunch of filters.
Erik Skultety (38):
virlog: Return void instead of int in virLogReset<Foo> methods
virlog: Convert virLogOutputs to a list of pointers to outputs
virlog: Convert virLogFilters to a list of pointers to filters
virlog: Export virLogOutputPtr through header
virlog: Export virLogFilterPtr through header
virlog: Introduce virLogSetFilters
virlog: Introduce virLogSetOutputs
daemon: Replace virLogParseOutputs with virLogSetOutputs in callers
daemon: Replace virLogParseFilters with virLogSetFilters in callers
virlog: Introduce virLogDefineOutputs
virlog: Introduce virLogDefineFilters
virlog: Rename virLogAddOutputTo to virLogNewOutput
virlog: Rename virLogDefineOutput to virLogOutputNew
virlog: Rename virLogDefineFilter to virLogFilterNew
virlog: Introduce virLogOutputFree
virlog: Introduce virLogOutputListFree
virlog: Introduce virLogFilterFree
virlog: Introduce virLogFilterListFree
virlog: Make virLogReset methods use of virLog(Output|Filter)ListFree
virlog: Split output parsing and output defining to separate
operations
virlog: Split filter parsing and filter defining to separate
operations
virlog: Split parsing and setting priority
virlog: Introduce virLogOutputExists
virlog: Make use of virLogOutputExists
virlog: Take a special care of syslog when setting new set of log
outputs
virlog: Swap the new copy of outputs with the global existing one
virlog: Rename virLogFiltersSerial to virLogSerial
virlog: Make virLogSetDefaultPriority trigger source update as well
virlog: Introduce an API mutex that serializes all setters
virlog: Acquire virLogAPILock in each setter API
admin: Introduce virAdmConnectGetLoggingLevel
admin: Introduce virAdmConnectGetLoggingFilters
admin: Introduce virAdmConnectGetLoggingOutputs
admin: Introduce virAdmConnectSetLoggingLevel
admin: Introduce virAdmConnectSetLoggingFilters
admin: Introduce virAdmConnectSetLoggingOutputs
admin: Export logging level constants via libvirt-admin.h
virt-admin: Wire-up the logging APIs
daemon/admin.c | 126 ++++++++
daemon/libvirtd.c | 8 +-
include/libvirt/libvirt-admin.h | 37 +++
src/admin/admin_protocol.x | 74 ++++-
src/admin/admin_remote.c | 86 +++++
src/admin_protocol-structs | 39 +++
src/libvirt-admin.c | 220 +++++++++++++
src/libvirt_admin_private.syms | 9 +
src/libvirt_admin_public.syms | 6 +
src/libvirt_private.syms | 14 +-
src/locking/lock_daemon.c | 8 +-
src/logging/log_daemon.c | 8 +-
src/util/virlog.c | 698 +++++++++++++++++++++++++++-------------
src/util/virlog.h | 50 +--
tests/eventtest.c | 3 +-
tests/testutils.c | 19 +-
tests/virlogtest.c | 12 +-
tools/virt-admin.c | 204 ++++++++++++
18 files changed, 1361 insertions(+), 260 deletions(-)
--
2.4.11
8 years, 5 months
[libvirt] [PATCH] Introduce Smack security driver for Libvirt
by Randy Aybar (raybar)
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(a)cisco.com, Cisco Systems, Inc.
San Jose, California, USA
-Randy Aybar raybar(a)cisco.com, Cisco Systems, Inc.
San Jose, California, USA
-Hongliang Liang hliang(a)bupt.edu.cn, Beijing University of Posts and
Telecommunications (BUPT), Beijing, China
-Changyao Han changyao(a)bupt.edu.cn, Beijing University of Posts and
Telecommunications (BUPT), Beijing, China
Portion of changes are based on existing security drivers within Libvirt:
-James Morris <jmorris(a)namei.org> (SELinux security driver)
-Jamie Strandboge <jamie(a)canonical.org> (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(a)redhat.com>
+ * Authors: Daniel P. Berrange <berrange(a)redhat.com>
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*/
#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(a)redhat.com>
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*
* 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(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*
* 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(a)namei.org>
- *
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*/
#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(a)redhat.com>
+ * Authors: Daniel P. Berrange <berrange(a)redhat.com>
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*/
#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(a)redhat.com>
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)cisco.com>
*/
#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(a)bupt.edu.cn>
+ * Changyao Han <changyao(a)bupt.edu.cn>
+ *
+ * Updated to libvirt v1.2.15: (Original was written for libvirt v1.1.4)
+ * Raghuram S. Sudhaakar <rsudhaak(a)cisco.com>
+ * Randy Aybar <raybar(a)cisco.com>
+ *
+ * Based on security_selinux.c by James Morris <jmorris(a)namei.org>
+ * and security_apparmor.c by Jamie Strandboge <jamie(a)canonical.com>
+ *
+ * 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(a)bupt.edu,cn>
+ * Changyao Han <changyao(a)bupt.edu.cn>
+ * Raghuram S. Sudhaakar <rssudhaakar(a)gmail.com>
+ * Randy Aybar <raybar(a)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 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);
8 years, 6 months
[libvirt] [PATCH rfc 0/2] devices: filesystem: type volume
by Olga Krishtal
In-Reply-To:
Patches introduce the new type of filesystem device.
The first patch adds the possibility to use storage pool volumes
as a backend for filesystem, that is accesed from the guest.
Such possibility allows to use volumes for container as a source of
root directory.
Usage:
<devices>
<filesystem type='volume'>
<source pool='pool_name' volume='volume_name'/>
...
<filesystem/>
The second patch adds the support of filesystem type volume
to virtuozzo containers. There is special type of volume for
virtuozzo containers, that can be manipulated via storage api.
Now, the volume of this type can be added to ct.xml description as
filesystem source.
However, there is a small issue with the pool/volume to path translation.
Usuallyi, in storage pools, virStorageTranslateDiskSourcePool is used,
but in the case of filesystem we do not have virDomainDiskDefPtr and
and code deduplication in every driver,that uses this possibility, is unavoidable.
eg. virStorageTranslatePoolLocal. Now I am looking for the way to avoid it somehow.
8 years, 6 months
[libvirt] Fixing libvirt's libxl driver breakage -- where to define LIBXL_API_VERSION?
by Wei Liu
Hi libvirt maintainers,
Xen's control library libxenlight (libxl) requires application
(libvirt in this case) to explictily define LIBXL_API_VERSION. This is
lacking at the moment so libvirt's libxl driver always gets the latest
APIs. We changed one of the APIs in libxl so libvirt's libxl driver
can't build at the moment.
I want to submit a patch for libvirt to define LIBXL_API_VERSION, but
I'm not sure where I should add that to. Can you give me some
pointers? Or even better -- a specific file that I should edit?
src/Makefile.am and src/Makfile.in are good candicate to me as far as
I can tell.
Thanks
Wei.
8 years, 6 months
[libvirt] [PATCH 00/18] vz: support disk/net/graphics devices updates
by Nikolay Shirokovskiy
It makes sense to support other devices too as update can be
on persistent config only which is always possible, but as AFAIK
the main purpose of this API is to change live config the set
of devices is just set of devices supported by qemu for live updates.
Nikolay Shirokovskiy (18):
vz: remove disk cache mode hunk
vz: make prlsdkGetDisk more generic
vz: reuse edit config frame in for attach/detach functions
vz: add device updates
vz: leverage disks parameters check on disks updates too
vz: move disks checks to device post parse
vz: fix memory leaks in attach/detach functions
vz: give nice report if network device not found
vz: dump ip addresses to domain xml
vz: dump route info in domain xml
vz: fix updating to no gateways
vz: fix minor type safey issues with net union usage
vz: trustGuestRxFilters fixes
vz: move getting container video devices out from vnc code
vz: support attach/detach/update/ of graphics device
vz: remove exlicitly setting zeros in dumping graphics
vz: support vnc password
vz: always pass graphics address to sdk
src/conf/networkcommon_conf.c | 2 +-
src/conf/networkcommon_conf.h | 2 +-
src/libvirt_private.syms | 1 +
src/vz/vz_driver.c | 115 +++---
src/vz/vz_sdk.c | 897 +++++++++++++++++++++++-------------------
src/vz/vz_sdk.h | 10 +-
src/vz/vz_utils.c | 204 ++++++++--
src/vz/vz_utils.h | 7 +-
8 files changed, 740 insertions(+), 498 deletions(-)
--
1.8.3.1
8 years, 6 months
[libvirt] [PATCH 1/1] perf: add more perf events support
by Qiaowei Ren
With current perf framework, this patch adds support to more perf
events, including cache missing, cache peference, cpu cycles,
instrction, etc..
Signed-off-by: Qiaowei Ren <qiaowei.ren(a)intel.com>
---
include/libvirt/libvirt-domain.h | 39 ++++++++++++++++++++++++
src/libvirt-domain.c | 8 +++++
src/qemu/qemu_driver.c | 23 +++++++-------
src/util/virperf.c | 65 +++++++++++++++++++++++++++++++++++++++-
src/util/virperf.h | 4 +++
5 files changed, 126 insertions(+), 13 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index cba4fa5..99c4c48 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -1928,6 +1928,45 @@ void virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats);
*/
# define VIR_PERF_PARAM_MBML "mbml"
+/**
+ * VIR_PERF_PARAM_CACHE_MISSES:
+ *
+ * Macro for typed parameter name that represents cache_misses perf
+ * event which can be used to measure the amount of cache missing by
+ * applications running on the platform. It corresponds to the
+ * "perf.cache_misses" field in the *Stats APIs.
+ */
+# define VIR_PERF_PARAM_CACHE_MISSES "cache_misses"
+
+/**
+ * VIR_PERF_PARAM_CACHE_REFERENCES:
+ *
+ * Macro for typed parameter name that represents cache_peferences
+ * perf event which can be used to measure the amount of cache hit
+ * by applications running on the platform. It corresponds to the
+ * "perf.cache_peferences" field in the *Stats APIs.
+ */
+# define VIR_PERF_PARAM_CACHE_REFERENCES "cache_peferences"
+
+/**
+ * VIR_PERF_PARAM_INSTRUCTIONS:
+ *
+ * Macro for typed parameter name that represents instructions perf
+ * event which can be used to measure the amount of instructions
+ * by applications running on the platform. It corresponds to the
+ * "perf.instructions" field in the *Stats APIs.
+ */
+# define VIR_PERF_PARAM_INSTRUCTIONS "instructions"
+
+/**
+ * VIR_PERF_PARAM_CPU_CYCLES:
+ *
+ * Macro for typed parameter name that represents cpu_cycles perf event
+ * which can be used to measure how many cycles one instruction needs.
+ * It corresponds to the "perf.cpu_cycles" field in the *Stats APIs.
+ */
+# define VIR_PERF_PARAM_CPU_CYCLES "cpu_cycles"
+
int virDomainGetPerfEvents(virDomainPtr dom,
virTypedParameterPtr *params,
int *nparams,
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 73ae369..ef71b31 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -11452,6 +11452,14 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
* "perf.mbml" - the amount of data (bytes/s) sent through the memory controller
* on the socket as unsigned long long. It is produced by mbml
* perf event.
+ * "perf.cache_misses" - the amount of cache missing as unsigned long long.
+ * It is produced by cache_misses perf event.
+ * "perf.cache_peferences" - the amount of cache hit as unsigned long long.
+ * It is produced by cache_peferences perf event.
+ * "perf.instructions" - the amount of instructions as unsigned long long.
+ * It is produced by instructions perf event.
+ * "perf.cpu_cycles" - the amount of cycles one instruction needs as unsigned
+ * long long. It is produced by cpu_cycles perf event.
*
* Note that entire stats groups or individual stat fields may be missing from
* the output in case they are not supported by the given hypervisor, are not
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 10d3e3d..d465ec5 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9756,6 +9756,10 @@ qemuDomainSetPerfEvents(virDomainPtr dom,
VIR_PERF_PARAM_CMT, VIR_TYPED_PARAM_BOOLEAN,
VIR_PERF_PARAM_MBMT, VIR_TYPED_PARAM_BOOLEAN,
VIR_PERF_PARAM_MBML, VIR_TYPED_PARAM_BOOLEAN,
+ VIR_PERF_PARAM_CACHE_MISSES, VIR_TYPED_PARAM_BOOLEAN,
+ VIR_PERF_PARAM_CACHE_REFERENCES, VIR_TYPED_PARAM_BOOLEAN,
+ VIR_PERF_PARAM_INSTRUCTIONS, VIR_TYPED_PARAM_BOOLEAN,
+ VIR_PERF_PARAM_CPU_CYCLES, VIR_TYPED_PARAM_BOOLEAN,
NULL) < 0)
return -1;
@@ -19071,10 +19075,10 @@ qemuDomainGetStatsBlock(virQEMUDriverPtr driver,
#undef QEMU_ADD_COUNT_PARAM
static int
-qemuDomainGetStatsPerfRdt(virPerfPtr perf,
- virPerfEventType type,
- virDomainStatsRecordPtr record,
- int *maxparams)
+qemuDomainGetStatsPerfOneEvent(virPerfPtr perf,
+ virPerfEventType type,
+ virDomainStatsRecordPtr record,
+ int *maxparams)
{
char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
uint64_t value = 0;
@@ -19110,14 +19114,9 @@ qemuDomainGetStatsPerf(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
if (!virPerfEventIsEnabled(priv->perf, i))
continue;
- switch (i) {
- case VIR_PERF_EVENT_CMT:
- case VIR_PERF_EVENT_MBMT:
- case VIR_PERF_EVENT_MBML:
- if (qemuDomainGetStatsPerfRdt(priv->perf, i, record, maxparams) < 0)
- goto cleanup;
- break;
- }
+ if (qemuDomainGetStatsPerfOneEvent(priv->perf, i,
+ record, maxparams) < 0)
+ goto cleanup;
}
ret = 0;
diff --git a/src/util/virperf.c b/src/util/virperf.c
index 450b3ba..38f2158 100644
--- a/src/util/virperf.c
+++ b/src/util/virperf.c
@@ -38,7 +38,9 @@ VIR_LOG_INIT("util.perf");
#define VIR_FROM_THIS VIR_FROM_PERF
VIR_ENUM_IMPL(virPerfEvent, VIR_PERF_EVENT_LAST,
- "cmt", "mbmt", "mbml");
+ "cmt", "mbmt", "mbml",
+ "cache_misses", "cache_peferences",
+ "instructions", "cpu_cycles");
struct virPerfEvent {
int type;
@@ -186,6 +188,60 @@ virPerfRdtEnable(virPerfEventPtr event,
return -1;
}
+static int
+virPerfGeneralEnable(virPerfEventPtr event,
+ pid_t pid)
+{
+ struct perf_event_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.size = sizeof(attr);
+ attr.inherit = 1;
+ attr.disabled = 1;
+ attr.enable_on_exec = 0;
+
+ switch (event->type) {
+ case VIR_PERF_EVENT_CACHE_MISSES:
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CACHE_MISSES;
+ break;
+ case VIR_PERF_EVENT_CACHE_REFERENCES:
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CACHE_REFERENCES;
+ break;
+ case VIR_PERF_EVENT_INSTRUCTIONS:
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_INSTRUCTIONS;
+ break;
+ case VIR_PERF_EVENT_CPU_CYCLES:
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CPU_CYCLES;
+ break;
+ }
+
+ event->fd = syscall(__NR_perf_event_open, &attr, pid, -1, -1, 0);
+ if (event->fd < 0) {
+ virReportSystemError(errno,
+ _("Unable to open perf event for %s"),
+ virPerfEventTypeToString(event->type));
+ goto error;
+ }
+
+ if (ioctl(event->fd, PERF_EVENT_IOC_ENABLE) < 0) {
+ virReportSystemError(errno,
+ _("Unable to enable perf event for %s"),
+ virPerfEventTypeToString(event->type));
+ goto error;
+ }
+
+ event->enabled = true;
+ return 0;
+
+ error:
+ VIR_FORCE_CLOSE(event->fd);
+ return -1;
+}
+
int
virPerfEventEnable(virPerfPtr perf,
virPerfEventType type,
@@ -202,6 +258,13 @@ virPerfEventEnable(virPerfPtr perf,
if (virPerfRdtEnable(event, pid) < 0)
return -1;
break;
+ case VIR_PERF_EVENT_CACHE_MISSES:
+ case VIR_PERF_EVENT_CACHE_REFERENCES:
+ case VIR_PERF_EVENT_INSTRUCTIONS:
+ case VIR_PERF_EVENT_CPU_CYCLES:
+ if (virPerfGeneralEnable(event, pid) < 0)
+ return -1;
+ break;
case VIR_PERF_EVENT_LAST:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected perf event type=%d"), type);
diff --git a/src/util/virperf.h b/src/util/virperf.h
index 769e85a..2cab339 100644
--- a/src/util/virperf.h
+++ b/src/util/virperf.h
@@ -28,6 +28,10 @@ typedef enum {
VIR_PERF_EVENT_CMT,
VIR_PERF_EVENT_MBMT,
VIR_PERF_EVENT_MBML,
+ VIR_PERF_EVENT_CACHE_MISSES,
+ VIR_PERF_EVENT_CACHE_REFERENCES,
+ VIR_PERF_EVENT_INSTRUCTIONS,
+ VIR_PERF_EVENT_CPU_CYCLES,
VIR_PERF_EVENT_LAST
} virPerfEventType;
--
1.9.1
8 years, 6 months
[libvirt] [PATCH] storage: dir: adapts .wipeVol for ploop volumes
by Olga Krishtal
The modification of .volWipe callback wipes ploop volume using one of
given wiping algorithm: dod, nnsa, etc.
However, in case of ploop volume we need to reinitialize root.hds and DiskDescriptor.xml.
Signed-off-by: Olga Krishtal <okrishtal(a)virtuozzo.com>
---
src/storage/storage_backend.c | 58 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 52 insertions(+), 6 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index d47a76a..367a887 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -2295,6 +2295,45 @@ virStorageBackendWipeLocal(virStorageVolDefPtr vol,
return ret;
}
+static int
+virStorageBackendVolWipePloop(virStorageVolDefPtr vol)
+{
+ virCommandPtr cmd = NULL;
+ char *target_path = NULL;
+ char *disk_desc = NULL;
+ int ret = -1;
+
+ if (virAsprintf(&target_path, "%s/root.hds", vol->target.path) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&disk_desc, "%s/DiskDescriptor.xml", vol->target.path) < 0)
+ goto cleanup;
+
+ if (virFileRemove(disk_desc, 0, 0) < 0) {
+ virReportError(errno, _("Failed to delete DiskDescriptor.xml of volume '%s'"),
+ vol->target.path);
+ goto cleanup;
+ }
+ if (virFileRemove(target_path, 0, 0) < 0) {
+ virReportError(errno, _("failed to delete root.hds of volume '%s'"),
+ vol->target.path);
+ goto cleanup;
+ }
+
+ cmd = virCommandNewArgList("ploop", "init", "-s", NULL);
+
+ virCommandAddArgFormat(cmd, "%lluM", VIR_DIV_UP(vol->target.capacity,
+ (1024 * 1024)));
+ virCommandAddArgList(cmd, "-t", "ext4", NULL);
+ virCommandAddArgFormat(cmd, "%s/root.hds", vol->target.path);
+ ret = virCommandRun(cmd, NULL);
+
+ cleanup:
+ VIR_FREE(disk_desc);
+ VIR_FREE(target_path);
+ virCommandFree(cmd);
+ return ret;
+}
int
virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -2307,6 +2346,8 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *alg_char = NULL;
struct stat st;
virCommandPtr cmd = NULL;
+ char *path = NULL;
+ char *target_path = vol->target.path;
virCheckFlags(0, -1);
@@ -2314,12 +2355,12 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
vol->target.path, algorithm);
if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("wiping for ploop volumes is not supported"));
- goto cleanup;
+ if (virAsprintf(&path, "%s/root.hds", vol->target.path) < 0)
+ goto cleanup;
+ target_path = path;
}
- fd = open(vol->target.path, O_RDWR);
+ fd = open(target_path, O_RDWR);
if (fd == -1) {
virReportSystemError(errno,
_("Failed to open storage volume with path '%s'"),
@@ -2376,13 +2417,12 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
if (algorithm != VIR_STORAGE_VOL_WIPE_ALG_ZERO) {
cmd = virCommandNew(SCRUB);
virCommandAddArgList(cmd, "-f", "-p", alg_char,
- vol->target.path, NULL);
+ target_path, NULL);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
ret = 0;
- goto cleanup;
} else {
if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
ret = virStorageBackendVolZeroSparseFileLocal(vol, st.st_size, fd);
@@ -2392,10 +2432,16 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
vol->target.allocation,
st.st_blksize);
}
+ if (ret < 0)
+ goto cleanup;
}
+ if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
+ ret = virStorageBackendVolWipePloop(vol);
+
cleanup:
virCommandFree(cmd);
+ VIR_FREE(path);
VIR_FORCE_CLOSE(fd);
return ret;
}
--
1.8.3.1
8 years, 6 months
[libvirt] [PATCH] logging: remove concept of default log priority
by Daniel P. Berrange
The logging framework has categories which can be selectively
enabled/disabled by setting a suitable LIBVIRT_LOG_FILTERS
environment variable or config file setting.
Along side that we also have the LIBVIRT_DEBUG environment
variable which unconditionally enables every single category
at DEBUG level. With the amount of logging produced by libvirt
these days, the signal/noise ratio in the output from setting
LIBVIRT_DEBUG is to poor for it to be useful.
Originally the LIBVIRT_DEBUG env variable had a very specific
use case - it resulted in logging of anything in our public
API entrypoints. eg it turned on src/libvirt.c debugging and
nothing else. Additionally it would always result in log
messages being sent to stderr.
When applied to any of the daemons, the log output no longers
gets sent to stderr, but rather to whatever default log output
has been configured by the daemon. If no log_outputs setting
or LIBVIRT_LOG_OUTPUTS env is set, then messages will often
go to the systemd journal or a /var/log/libvirt/libvirtd.log
file rather than stderr.
These factors have conspired to make the LIBVIRT_DEBUG env
and/or default log priority to be pretty useless in the real
world.
This change attempts to take us back towards the original
semantics of the LIBVIRT_DEBUG env variable as follows.
If LIBVIRT_DEBUG is set to a plain integer, or log level
string, then it will turn on logging for the "libvirt" log
category at that level. Any other string will be parsed in
the same way as LIBVIRT_LOG_FILTERS would be. In all cases
use of LIBVIRT_DEBUG will result in an explicit output being
added for stderr. This ensures that messages always go to
stderr, even if other outputs are already configured.
IOW, LIBVIRT_DEBUG=1 virsh or LIBVIRT_DEBUG=1 libvirtd
will both result in printing logs of libvirt public API
calls to stderr. Meanwhile setting LIBVIRT_DEBUG="1:qemu"
is equivalent to setting LIBVIRT_LOG_FILTERS="1:qemu" and
LIBVIRT_LOG_OUTPUTS="1:stderr"
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
daemon/libvirtd.c | 27 ++++++------
src/libvirt_private.syms | 1 +
src/libxl/libxl_conf.c | 3 +-
src/locking/lock_daemon.c | 29 ++++++-------
src/logging/log_daemon.c | 29 ++++++-------
src/lxc/lxc_process.c | 7 ----
src/util/vircommand.c | 4 --
src/util/virlog.c | 104 +++++++++++++++++++---------------------------
src/util/virlog.h | 11 ++---
tests/eventtest.c | 6 +--
10 files changed, 97 insertions(+), 124 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index cc5190f..e88a982 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -668,6 +668,8 @@ daemonSetupLogging(struct daemonConfig *config,
bool verbose,
bool godaemon)
{
+ int level = VIR_LOG_WARN;
+
virLogReset();
/*
@@ -684,9 +686,6 @@ daemonSetupLogging(struct daemonConfig *config,
* level has been set, we must process variables in the opposite
* order, each one overriding the previous.
*/
- if (config->log_level != 0)
- virLogSetDefaultPriority(config->log_level);
-
virLogSetFromEnv();
if (virLogGetNbFilters() == 0)
@@ -695,11 +694,14 @@ daemonSetupLogging(struct daemonConfig *config,
if (virLogGetNbOutputs() == 0)
virLogParseOutputs(config->log_outputs);
- /*
- * Command line override for --verbose
- */
- if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
- virLogSetDefaultPriority(VIR_LOG_INFO);
+ if (config->log_level != 0 || verbose) {
+ level = config->log_level;
+ if (verbose && level > VIR_LOG_INFO)
+ level = VIR_LOG_INFO;
+ virLogDefineFilter("libvirt", level, 0);
+ if (virLogGetNbOutputs() == 0)
+ virLogParseOutputs("1:stderr");
+ }
/*
* If no defined outputs, and either running
@@ -711,7 +713,7 @@ daemonSetupLogging(struct daemonConfig *config,
(godaemon || !isatty(STDIN_FILENO))) {
char *tmp;
if (access("/run/systemd/journal/socket", W_OK) >= 0) {
- virLogPriority priority = virLogGetDefaultPriority();
+ virLogPriority priority = level;
/* By default we don't want to log too much stuff into journald as
* it may employ rate limiting and thus block libvirt execution. */
@@ -735,8 +737,7 @@ daemonSetupLogging(struct daemonConfig *config,
if (godaemon) {
if (privileged) {
if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/libvirtd.log",
- virLogGetDefaultPriority(),
- LOCALSTATEDIR) == -1)
+ level, LOCALSTATEDIR) == -1)
goto error;
} else {
char *logdir = virGetUserCacheDirectory();
@@ -753,14 +754,14 @@ daemonSetupLogging(struct daemonConfig *config,
umask(old_umask);
if (virAsprintf(&tmp, "%d:file:%s/libvirtd.log",
- virLogGetDefaultPriority(), logdir) == -1) {
+ level, logdir) == -1) {
VIR_FREE(logdir);
goto error;
}
VIR_FREE(logdir);
}
} else {
- if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
+ if (virAsprintf(&tmp, "%d:stderr", level) < 0)
goto error;
}
virLogParseOutputs(tmp);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a980a32..5586d8b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1801,6 +1801,7 @@ virLogProbablyLogMessage;
virLogReset;
virLogSetDefaultPriority;
virLogSetFromEnv;
+virLogSourceGetPriority;
virLogUnlock;
virLogVMessage;
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
index d927b37..51d6037 100644
--- a/src/libxl/libxl_conf.c
+++ b/src/libxl/libxl_conf.c
@@ -52,6 +52,7 @@
#define VIR_FROM_THIS VIR_FROM_LIBXL
VIR_LOG_INIT("libxl.libxl_conf");
+VIR_LOG_INIT_FULL("libxl.libxl_context", virLogLibXL);
/* see xen-unstable.hg/xen/include/asm-x86/cpufeature.h */
#define LIBXL_X86_FEATURE_PAE_MASK 0x40
@@ -1724,7 +1725,7 @@ libxlDriverConfigNew(void)
}
VIR_FREE(log_file);
- switch (virLogGetDefaultPriority()) {
+ switch (virLogSourceGetPriority(&virLogLibXL)) {
case VIR_LOG_DEBUG:
log_level = XTL_DEBUG;
break;
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
index f889a34..426fe6b 100644
--- a/src/locking/lock_daemon.c
+++ b/src/locking/lock_daemon.c
@@ -454,6 +454,8 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
bool verbose,
bool godaemon)
{
+ int level = VIR_LOG_WARN;
+
virLogReset();
/*
@@ -470,9 +472,6 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
* level has been set, we must process variables in the opposite
* order, each one overriding the previous.
*/
- if (config->log_level != 0)
- virLogSetDefaultPriority(config->log_level);
-
virLogSetFromEnv();
if (virLogGetNbFilters() == 0)
@@ -481,6 +480,15 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
if (virLogGetNbOutputs() == 0)
virLogParseOutputs(config->log_outputs);
+ if (config->log_level != 0 || verbose) {
+ level = config->log_level;
+ if (verbose && level > VIR_LOG_INFO)
+ level = VIR_LOG_INFO;
+ virLogDefineFilter("libvirt", level, 0);
+ if (virLogGetNbOutputs() == 0)
+ virLogParseOutputs("1:stderr");
+ }
+
/*
* If no defined outputs, and either running
* as daemon or not on a tty, then first try
@@ -491,7 +499,7 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
(godaemon || !isatty(STDIN_FILENO))) {
char *tmp;
if (access("/run/systemd/journal/socket", W_OK) >= 0) {
- if (virAsprintf(&tmp, "%d:journald", virLogGetDefaultPriority()) < 0)
+ if (virAsprintf(&tmp, "%d:journald", level) < 0)
goto error;
virLogParseOutputs(tmp);
VIR_FREE(tmp);
@@ -508,8 +516,7 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
if (godaemon) {
if (privileged) {
if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/virtlockd.log",
- virLogGetDefaultPriority(),
- LOCALSTATEDIR) == -1)
+ level, LOCALSTATEDIR) == -1)
goto error;
} else {
char *logdir = virGetUserCacheDirectory();
@@ -527,26 +534,20 @@ virLockDaemonSetupLogging(virLockDaemonConfigPtr config,
umask(old_umask);
if (virAsprintf(&tmp, "%d:file:%s/virtlockd.log",
- virLogGetDefaultPriority(), logdir) == -1) {
+ level, logdir) == -1) {
VIR_FREE(logdir);
goto error;
}
VIR_FREE(logdir);
}
} else {
- if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
+ if (virAsprintf(&tmp, "%d:stderr", level) < 0)
goto error;
}
virLogParseOutputs(tmp);
VIR_FREE(tmp);
}
- /*
- * Command line override for --verbose
- */
- if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
- virLogSetDefaultPriority(VIR_LOG_INFO);
-
return 0;
error:
diff --git a/src/logging/log_daemon.c b/src/logging/log_daemon.c
index 90f8427..f344ba2 100644
--- a/src/logging/log_daemon.c
+++ b/src/logging/log_daemon.c
@@ -377,6 +377,8 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
bool verbose,
bool godaemon)
{
+ int level = VIR_LOG_WARN;
+
virLogReset();
/*
@@ -393,9 +395,6 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
* level has been set, we must process variables in the opposite
* order, each one overriding the previous.
*/
- if (config->log_level != 0)
- virLogSetDefaultPriority(config->log_level);
-
virLogSetFromEnv();
if (virLogGetNbFilters() == 0)
@@ -404,6 +403,15 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
if (virLogGetNbOutputs() == 0)
virLogParseOutputs(config->log_outputs);
+ if (config->log_level != 0 || verbose) {
+ level = config->log_level;
+ if (verbose && level > VIR_LOG_INFO)
+ level = VIR_LOG_INFO;
+ virLogDefineFilter("libvirt", level, 0);
+ if (virLogGetNbOutputs() == 0)
+ virLogParseOutputs("1:stderr");
+ }
+
/*
* If no defined outputs, and either running
* as daemon or not on a tty, then first try
@@ -414,7 +422,7 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
(godaemon || !isatty(STDIN_FILENO))) {
char *tmp;
if (access("/run/systemd/journal/socket", W_OK) >= 0) {
- if (virAsprintf(&tmp, "%d:journald", virLogGetDefaultPriority()) < 0)
+ if (virAsprintf(&tmp, "%d:journald", level) < 0)
goto error;
virLogParseOutputs(tmp);
VIR_FREE(tmp);
@@ -431,8 +439,7 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
if (godaemon) {
if (privileged) {
if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/virtlogd.log",
- virLogGetDefaultPriority(),
- LOCALSTATEDIR) == -1)
+ level, LOCALSTATEDIR) == -1)
goto error;
} else {
char *logdir = virGetUserCacheDirectory();
@@ -450,26 +457,20 @@ virLogDaemonSetupLogging(virLogDaemonConfigPtr config,
umask(old_umask);
if (virAsprintf(&tmp, "%d:file:%s/virtlogd.log",
- virLogGetDefaultPriority(), logdir) == -1) {
+ level, logdir) == -1) {
VIR_FREE(logdir);
goto error;
}
VIR_FREE(logdir);
}
} else {
- if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
+ if (virAsprintf(&tmp, "%d:stderr", level) < 0)
goto error;
}
virLogParseOutputs(tmp);
VIR_FREE(tmp);
}
- /*
- * Command line override for --verbose
- */
- if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
- virLogSetDefaultPriority(VIR_LOG_INFO);
-
return 0;
error:
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c
index 8981d9a..9fca007 100644
--- a/src/lxc/lxc_process.c
+++ b/src/lxc/lxc_process.c
@@ -918,9 +918,6 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
/* The controller may call ip command, so we have to retain PATH. */
virCommandAddEnvPassBlockSUID(cmd, "PATH", "/bin:/usr/bin");
- virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d",
- virLogGetDefaultPriority());
-
if (virLogGetNbFilters() > 0) {
filterstr = virLogGetFilters();
if (!filterstr) {
@@ -943,10 +940,6 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver,
virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr);
VIR_FREE(outputstr);
}
- } else {
- virCommandAddEnvFormat(cmd,
- "LIBVIRT_LOG_OUTPUTS=%d:stderr",
- virLogGetDefaultPriority());
}
virCommandAddArgList(cmd, "--name", vm->def->name, NULL);
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 027cb64..07cd005 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -342,8 +342,6 @@ virFork(void)
} else {
/* child process */
-
- int logprio;
size_t i;
/* Remove any error callback so errors in child now get sent
@@ -354,9 +352,7 @@ virFork(void)
/* Make sure any hook logging is sent to stderr, since child
* process may close the logfile FDs */
- logprio = virLogGetDefaultPriority();
virLogReset();
- virLogSetDefaultPriority(logprio);
/* Clear out all signal handlers from parent so nothing
* unexpected can happen in our child once we unblock
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 738eaac..82fb4dc 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -112,11 +112,6 @@ typedef virLogOutput *virLogOutputPtr;
static virLogOutputPtr virLogOutputs;
static int virLogNbOutputs;
-/*
- * Default priorities
- */
-static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
-
static int virLogResetFilters(void);
static int virLogResetOutputs(void);
static void virLogOutputToFd(virLogSourcePtr src,
@@ -175,7 +170,6 @@ virLogOnceInit(void)
return -1;
virLogLock();
- virLogDefaultPriority = VIR_LOG_DEFAULT;
if (VIR_ALLOC_QUIET(virLogRegex) >= 0) {
if (regcomp(virLogRegex, VIR_LOG_REGEX, REG_EXTENDED) != 0)
@@ -205,35 +199,10 @@ virLogReset(void)
virLogLock();
virLogResetFilters();
virLogResetOutputs();
- virLogDefaultPriority = VIR_LOG_DEFAULT;
virLogUnlock();
return 0;
}
-/**
- * virLogSetDefaultPriority:
- * @priority: the default priority level
- *
- * Set the default priority level, i.e. any logged data of a priority
- * equal or superior to this level will be logged, unless a specific rule
- * was defined for the log category of the message.
- *
- * Returns 0 if successful, -1 in case of error.
- */
-int
-virLogSetDefaultPriority(virLogPriority priority)
-{
- if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
- VIR_WARN("Ignoring invalid log level setting.");
- return -1;
- }
- if (virLogInitialize() < 0)
- return -1;
-
- virLogDefaultPriority = priority;
- return 0;
-}
-
/**
* virLogResetFilters:
@@ -472,7 +441,7 @@ virLogSourceUpdate(virLogSourcePtr source)
{
virLogLock();
if (source->serial < virLogFiltersSerial) {
- unsigned int priority = virLogDefaultPriority;
+ unsigned int priority = VIR_LOG_DEFAULT;
unsigned int flags = 0;
size_t i;
@@ -1310,18 +1279,6 @@ virLogParseFilters(const char *filters)
/**
- * virLogGetDefaultPriority:
- *
- * Returns the current logging priority level.
- */
-virLogPriority
-virLogGetDefaultPriority(void)
-{
- return virLogDefaultPriority;
-}
-
-
-/**
* virLogGetFilters:
*
* Returns a string listing the current filters, in the format originally
@@ -1423,35 +1380,53 @@ virLogGetNbOutputs(void)
/**
- * virLogParseDefaultPriority:
+ * virLogParseDebug:
* @priority: string defining the desired logging level
*
- * Parses and sets the default log priority level. It can take a string or
- * number corresponding to the following levels:
+ * This method is a shortcut for setting a filter
+ * along with output to stderr.
+ *
+ * It can take one of the following strings or numbers:
+ *
* 1: DEBUG
* 2: INFO
* 3: WARNING
* 4: ERROR
*
+ * in which case it will set the priority level on the
+ * "libvirt" log source filter. If it does not match any
+ * of these standard strings it will be treated as a full
+ * filter string.
+ *
+ * In all cases an output to stderr will be defined.
+ *
* Returns 0 if successful, -1 in case of error.
*/
int
-virLogParseDefaultPriority(const char *priority)
+virLogParseDebug(const char *debug)
{
- int ret = -1;
+ unsigned int priority = VIR_LOG_DEFAULT;
+ if (STREQ(debug, "1") || STREQ(debug, "debug"))
+ priority = VIR_LOG_DEBUG;
+ else if (STREQ(debug, "2") || STREQ(debug, "info"))
+ priority = VIR_LOG_INFO;
+ else if (STREQ(debug, "3") || STREQ(debug, "warning"))
+ priority = VIR_LOG_WARN;
+ else if (STREQ(debug, "4") || STREQ(debug, "error"))
+ priority = VIR_LOG_ERROR;
+
+ if (priority == VIR_LOG_DEFAULT) {
+ if (virLogParseFilters(debug) < 0)
+ return -1;
+ } else {
+ if (virLogDefineFilter("libvirt", priority, 0) < 0)
+ return -1;
+ }
- if (STREQ(priority, "1") || STREQ(priority, "debug"))
- ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
- else if (STREQ(priority, "2") || STREQ(priority, "info"))
- ret = virLogSetDefaultPriority(VIR_LOG_INFO);
- else if (STREQ(priority, "3") || STREQ(priority, "warning"))
- ret = virLogSetDefaultPriority(VIR_LOG_WARN);
- else if (STREQ(priority, "4") || STREQ(priority, "error"))
- ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
- else
- VIR_WARN("Ignoring invalid log level setting");
+ if (virLogParseOutputs("1:stderr") < 0)
+ return -1;
- return ret;
+ return 0;
}
@@ -1471,7 +1446,7 @@ virLogSetFromEnv(void)
debugEnv = virGetEnvAllowSUID("LIBVIRT_DEBUG");
if (debugEnv && *debugEnv)
- virLogParseDefaultPriority(debugEnv);
+ virLogParseDebug(debugEnv);
debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_FILTERS");
if (debugEnv && *debugEnv)
virLogParseFilters(debugEnv);
@@ -1495,3 +1470,10 @@ bool virLogProbablyLogMessage(const char *str)
ret = true;
return ret;
}
+
+
+int virLogSourceGetPriority(virLogSourcePtr source)
+{
+ virLogSourceUpdate(source);
+ return source->priority;
+}
diff --git a/src/util/virlog.h b/src/util/virlog.h
index 3ad00d4..aace409 100644
--- a/src/util/virlog.h
+++ b/src/util/virlog.h
@@ -73,13 +73,14 @@ struct _virLogSource {
* log statements in a file are conditionally disabled
* at compile time due to configure options.
*/
-# define VIR_LOG_INIT(n) \
- static ATTRIBUTE_UNUSED virLogSource virLogSelf = { \
+# define VIR_LOG_INIT_FULL(n, _var) \
+ static ATTRIBUTE_UNUSED virLogSource _var = { \
.name = "" n "", \
.priority = VIR_LOG_ERROR, \
.serial = 0, \
.flags = 0, \
};
+# define VIR_LOG_INIT(n) VIR_LOG_INIT_FULL(n, virLogSelf)
/*
* If configured with --enable-debug=yes then library calls
@@ -174,8 +175,6 @@ int virLogGetNbFilters(void);
int virLogGetNbOutputs(void);
char *virLogGetFilters(void);
char *virLogGetOutputs(void);
-virLogPriority virLogGetDefaultPriority(void);
-int virLogSetDefaultPriority(virLogPriority priority);
void virLogSetFromEnv(void);
int virLogDefineFilter(const char *match,
virLogPriority priority,
@@ -195,7 +194,7 @@ int virLogDefineOutput(virLogOutputFunc f,
void virLogLock(void);
void virLogUnlock(void);
int virLogReset(void);
-int virLogParseDefaultPriority(const char *priority);
+int virLogParseDebug(const char *debug);
int virLogParseFilters(const char *filters);
int virLogParseOutputs(const char *output);
int virLogPriorityFromSyslog(int priority);
@@ -217,4 +216,6 @@ void virLogVMessage(virLogSourcePtr source,
bool virLogProbablyLogMessage(const char *str);
+int virLogSourceGetPriority(virLogSourcePtr source);
+
#endif
diff --git a/tests/eventtest.c b/tests/eventtest.c
index c4be606..0a31672 100644
--- a/tests/eventtest.c
+++ b/tests/eventtest.c
@@ -310,11 +310,7 @@ mymain(void)
if (virThreadInitialize() < 0)
return EXIT_FAILURE;
- char *debugEnv = getenv("LIBVIRT_DEBUG");
- if (debugEnv && *debugEnv && (virLogParseDefaultPriority(debugEnv) == -1)) {
- fprintf(stderr, "Invalid log level setting.\n");
- return EXIT_FAILURE;
- }
+ virLogSetFromEnv();
virEventPollInit();
--
2.5.5
8 years, 6 months