[libvirt] build failure on 32-bit
by Eric Blake
I hit an interesting failure on my 32-bit F24 machine:
In file included from ../../src/util/virconf.c:32:0:
../../src/util/virconf.c: In function 'virConfGetValueSSizeT':
../../src/util/virconf.c:1269:26: error: format '%zd' expects argument
of type 'signed size_t', but argument 9 has type 'long int'
[-Werror=format=]
_("%s: value for '%s' parameter must be in range
%zd:%zd"),
In context, it is because we are using SSIZE_MAX as the argument paired
to %zd.
Technically, the standards documents do NOT require ssize_t to have any
relation to size_t, and thus there is NO portable way to pass ssize_t
values to printf() without a cast; but in practice, most systems are
sane enough that 'ssize_t' is the same type as 'signed size_t', as
requested by gcc. This includes 32-bit glibc (where size_t is unsigned
int, and ssize_t is int).
But it turns out it is a glibc bug:
https://sourceware.org/bugzilla/show_bug.cgi?id=13575 - SSIZE_MAX must
have type ssize_t, and glibc is at fault for defining it as a 'long'
value even when ssize_t is an 'int'.
Once gnulib works around it, I'll update libvirt's gnulib submodule to
fix the libvirt build on 32-bit Linux again.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
8 years, 5 months
[libvirt] [PATCH] virConfGetValueSSizeT: Fix build on 32 bits
by Michal Privoznik
This function tries to get a ssize_t value from a config file.
But before returning it, it checks whether the value would fit in
ssize_t and if not an error is printed out among with the range
for the ssize_t type. However, on some platforms SSIZE_MAX may
actually be a signed long type:
util/virconf.c: In function 'virConfGetValueSSizeT':
util/virconf.c:1268:9: error: format '%zd' expects argument of type 'signed size_t', but argument 9 has type 'long int' [-Werror=format=]
virReportError(VIR_ERR_INTERNAL_ERROR,
^
$ grep -r SSIZE_MAX /usr/include/
/usr/include/bits/posix1_lim.h:#ifndef SSIZE_MAX
/usr/include/bits/posix1_lim.h:# define SSIZE_MAX LONG_MAX
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/util/virconf.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/util/virconf.c b/src/util/virconf.c
index 5085768..4dc82ec 100644
--- a/src/util/virconf.c
+++ b/src/util/virconf.c
@@ -1267,7 +1267,8 @@ int virConfGetValueSSizeT(virConfPtr conf,
if (cval->l > SSIZE_MAX || cval->l < (-SSIZE_MAX - 1)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: value for '%s' parameter must be in range %zd:%zd"),
- conf->filename, setting, -SSIZE_MAX - 1, SSIZE_MAX);
+ conf->filename, setting,
+ (ssize_t) -SSIZE_MAX - 1, (ssize_t) SSIZE_MAX);
return -1;
}
--
2.8.4
8 years, 5 months
[libvirt] [PATCH] virconf: skip some range checks if SSIZE_MAX >= LLONG_MAX
by Daniel P. Berrange
If size_t is the same size as long long, then we can skip
some of the range checks. This avoids triggering some
bogus compiler warning messages.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/util/virconf.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/util/virconf.c b/src/util/virconf.c
index f82d114..4813419 100644
--- a/src/util/virconf.c
+++ b/src/util/virconf.c
@@ -1216,12 +1216,14 @@ int virConfGetValueSizeT(virConfPtr conf,
return -1;
}
} else if (cval->type == VIR_CONF_ULONG) {
+#if ULLONG_MAX > SIZE_MAX
if (((unsigned long long)cval->l) > SIZE_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: value for '%s' parameter must be in range 0:%zu"),
conf->filename, setting, SIZE_MAX);
return -1;
}
+#endif
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: expected an unsigned integer for '%s' parameter"),
@@ -1271,12 +1273,14 @@ int virConfGetValueSSizeT(virConfPtr conf,
return -1;
}
} else if (cval->type == VIR_CONF_LONG) {
+#if SSIZE_MAX < LLONG_MAX
if (cval->l < (-SSIZE_MAX - 1) || cval->l > SSIZE_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: value for '%s' parameter must be in range %zd:%zd"),
conf->filename, setting, -SSIZE_MAX - 1, SSIZE_MAX);
return -1;
}
+#endif
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("%s: expected a signed integer for '%s' parameter"),
--
2.7.4
8 years, 5 months
[libvirt] [PATCH] conf: Revert changes to add new secret type "passphrase"
by John Ferlan
Revert the remainder of commit id 'c84380106'
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
This "replaces" patch 3 of my other series - essentially removing all
traces of the 'passphrase' changes - as requested via code review.
docs/aclpolkit.html.in | 4 ----
docs/schemas/secret.rng | 10 ----------
include/libvirt/libvirt-secret.h | 1 -
src/access/viraccessdriverpolkit.c | 13 -------------
src/conf/secret_conf.c | 22 +---------------------
src/conf/secret_conf.h | 1 -
src/conf/virsecretobj.c | 5 -----
tests/secretxml2xmlin/usage-passphrase.xml | 7 -------
tests/secretxml2xmltest.c | 1 -
9 files changed, 1 insertion(+), 63 deletions(-)
delete mode 100644 tests/secretxml2xmlin/usage-passphrase.xml
diff --git a/docs/aclpolkit.html.in b/docs/aclpolkit.html.in
index 4d0307d..dae0814 100644
--- a/docs/aclpolkit.html.in
+++ b/docs/aclpolkit.html.in
@@ -224,10 +224,6 @@
<td>secret_usage_target</td>
<td>Name of the associated iSCSI target, if any</td>
</tr>
- <tr>
- <td>secret_usage_name</td>
- <td>Name of be associated passphrase secret, if any</td>
- </tr>
</tbody>
</table>
diff --git a/docs/schemas/secret.rng b/docs/schemas/secret.rng
index cac8560..e21e700 100644
--- a/docs/schemas/secret.rng
+++ b/docs/schemas/secret.rng
@@ -36,7 +36,6 @@
<ref name='usagevolume'/>
<ref name='usageceph'/>
<ref name='usageiscsi'/>
- <ref name='usagepassphrase'/>
<!-- More choices later -->
</choice>
</element>
@@ -72,13 +71,4 @@
</element>
</define>
- <define name='usagepassphrase'>
- <attribute name='type'>
- <value>passphrase</value>
- </attribute>
- <element name='name'>
- <ref name='genericName'/>
- </element>
- </define>
-
</grammar>
diff --git a/include/libvirt/libvirt-secret.h b/include/libvirt/libvirt-secret.h
index 55b11e0..02728ba 100644
--- a/include/libvirt/libvirt-secret.h
+++ b/include/libvirt/libvirt-secret.h
@@ -43,7 +43,6 @@ typedef enum {
VIR_SECRET_USAGE_TYPE_VOLUME = 1,
VIR_SECRET_USAGE_TYPE_CEPH = 2,
VIR_SECRET_USAGE_TYPE_ISCSI = 3,
- VIR_SECRET_USAGE_TYPE_PASSPHRASE = 4,
# ifdef VIR_ENUM_SENTINELS
VIR_SECRET_USAGE_TYPE_LAST
diff --git a/src/access/viraccessdriverpolkit.c b/src/access/viraccessdriverpolkit.c
index 99b867f..89bc890 100644
--- a/src/access/viraccessdriverpolkit.c
+++ b/src/access/viraccessdriverpolkit.c
@@ -338,19 +338,6 @@ virAccessDriverPolkitCheckSecret(virAccessManagerPtr manager,
virAccessPermSecretTypeToString(perm),
attrs);
} break;
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE: {
- const char *attrs[] = {
- "connect_driver", driverName,
- "secret_uuid", uuidstr,
- "secret_usage_name", secret->usage.name,
- NULL,
- };
-
- return virAccessDriverPolkitCheck(manager,
- "secret",
- virAccessPermSecretTypeToString(perm),
- attrs);
- } break;
}
}
diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c
index a973aa9..d510645 100644
--- a/src/conf/secret_conf.c
+++ b/src/conf/secret_conf.c
@@ -29,7 +29,6 @@
#include "viralloc.h"
#include "secret_conf.h"
#include "virsecretobj.h"
-#include "virstring.h"
#include "virerror.h"
#include "virxml.h"
#include "viruuid.h"
@@ -39,7 +38,7 @@
VIR_LOG_INIT("conf.secret_conf");
VIR_ENUM_IMPL(virSecretUsage, VIR_SECRET_USAGE_TYPE_LAST,
- "none", "volume", "ceph", "iscsi", "passphrase")
+ "none", "volume", "ceph", "iscsi")
const char *
virSecretUsageIDForDef(virSecretDefPtr def)
@@ -57,9 +56,6 @@ virSecretUsageIDForDef(virSecretDefPtr def)
case VIR_SECRET_USAGE_TYPE_ISCSI:
return def->usage.target;
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE:
- return def->usage.name;
-
default:
return NULL;
}
@@ -89,10 +85,6 @@ virSecretDefFree(virSecretDefPtr def)
VIR_FREE(def->usage.target);
break;
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE:
- VIR_FREE(def->usage.name);
- break;
-
default:
VIR_ERROR(_("unexpected secret usage type %d"), def->usage_type);
break;
@@ -153,14 +145,6 @@ virSecretDefParseUsage(xmlXPathContextPtr ctxt,
}
break;
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE:
- if (!(def->usage.name = virXPathString("string(./usage/name)", ctxt))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("passphrase usage specified, but name is missing"));
- return -1;
- }
- break;
-
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected secret usage type %d"),
@@ -313,10 +297,6 @@ virSecretDefFormatUsage(virBufferPtr buf,
virBufferEscapeString(buf, "<target>%s</target>\n", def->usage.target);
break;
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE:
- virBufferEscapeString(buf, "<name>%s</name>\n", def->usage.name);
- break;
-
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected secret usage type %d"),
diff --git a/src/conf/secret_conf.h b/src/conf/secret_conf.h
index c34880f..4584403 100644
--- a/src/conf/secret_conf.h
+++ b/src/conf/secret_conf.h
@@ -40,7 +40,6 @@ struct _virSecretDef {
char *volume; /* May be NULL */
char *ceph;
char *target;
- char *name;
} usage;
};
diff --git a/src/conf/virsecretobj.c b/src/conf/virsecretobj.c
index 6714a00..30a5e80 100644
--- a/src/conf/virsecretobj.c
+++ b/src/conf/virsecretobj.c
@@ -237,11 +237,6 @@ virSecretObjSearchName(const void *payload,
if (STREQ(secret->def->usage.target, data->usageID))
found = 1;
break;
-
- case VIR_SECRET_USAGE_TYPE_PASSPHRASE:
- if (STREQ(secret->def->usage.name, data->usageID))
- found = 1;
- break;
}
cleanup:
diff --git a/tests/secretxml2xmlin/usage-passphrase.xml b/tests/secretxml2xmlin/usage-passphrase.xml
deleted file mode 100644
index 2b94b80..0000000
--- a/tests/secretxml2xmlin/usage-passphrase.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<secret ephemeral='no' private='no'>
- <uuid>f52a81b2-424e-490c-823d-6bd4235bc572</uuid>
- <description>Sample Passphrase Secret</description>
- <usage type='passphrase'>
- <name>mumblyfratz</name>
- </usage>
-</secret>
diff --git a/tests/secretxml2xmltest.c b/tests/secretxml2xmltest.c
index c444e4d..8dcbb40 100644
--- a/tests/secretxml2xmltest.c
+++ b/tests/secretxml2xmltest.c
@@ -80,7 +80,6 @@ mymain(void)
DO_TEST("usage-volume");
DO_TEST("usage-ceph");
DO_TEST("usage-iscsi");
- DO_TEST("usage-passphrase");
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
2.5.5
8 years, 5 months
[libvirt] [PATCH] config: Add listen address setter
by Visarion Alexandru
Learn to set the address the domain is listening on.
---
.../libvirt-gconfig-domain-graphics-spice.c | 18 ++++++++++++++++++
.../libvirt-gconfig-domain-graphics-spice.h | 3 +++
libvirt-gconfig/libvirt-gconfig.sym | 1 +
3 files changed, 22 insertions(+)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
index 079ea27..a773084 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.c
@@ -165,3 +165,21 @@ void gvir_config_domain_graphics_spice_set_gl(GVirConfigDomainGraphicsSpice *gra
gvir_config_object_replace_child_with_attribute_enum
(GVIR_CONFIG_OBJECT(graphics), "gl", "enable", G_TYPE_BOOLEAN, gl);
}
+
+void gvir_config_domain_graphics_spice_set_listen_address(GVirConfigDomainGraphicsSpice *graphics,
+ const char *address)
+{
+ g_return_if_fail(GVIR_CONFIG_IS_DOMAIN_GRAPHICS_SPICE(graphics));
+
+ gvir_config_object_set_attribute(GVIR_CONFIG_OBJECT(graphics), "listen", address, NULL);
+
+ gvir_config_object_add_child_with_attribute(GVIR_CONFIG_OBJECT(graphics),
+ "listen",
+ "address",
+ address);
+
+ gvir_config_object_add_child_with_attribute(GVIR_CONFIG_OBJECT(graphics),
+ "listen",
+ "type",
+ "address");
+}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.h b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.h
index 25c132e..4bca850 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.h
+++ b/libvirt-gconfig/libvirt-gconfig-domain-graphics-spice.h
@@ -95,6 +95,9 @@ gvir_config_domain_graphics_spice_get_image_compression
void gvir_config_domain_graphics_spice_set_gl(GVirConfigDomainGraphicsSpice *graphics,
gboolean gl);
+void gvir_config_domain_graphics_spice_set_listen_address(GVirConfigDomainGraphicsSpice *graphics,
+ const char *address);
+
G_END_DECLS
#endif /* __LIBVIRT_GCONFIG_DOMAIN_GRAPHICS_SPICE_H__ */
diff --git a/libvirt-gconfig/libvirt-gconfig.sym b/libvirt-gconfig/libvirt-gconfig.sym
index f11f97a..86768ae 100644
--- a/libvirt-gconfig/libvirt-gconfig.sym
+++ b/libvirt-gconfig/libvirt-gconfig.sym
@@ -736,6 +736,7 @@ global:
LIBVIRT_GCONFIG_0.2.4 {
gvir_config_domain_graphics_spice_set_gl;
gvir_config_domain_video_set_accel3d;
+ gvir_config_domain_graphics_spice_set_listen_address;
} LIBVIRT_GCONFIG_0.2.2;
# .... define new API here using predicted next version number ....
--
2.5.5
8 years, 5 months
[libvirt] [PATCH 00/16] Add typedef accessors for virConf
by Daniel P. Berrange
Every caller of virConfGetValue is doing the same kind of
dance to ensure the returned value is set and has the
right kind of type. This is a clear sign we should have
typesafe APIs for accessor virConf values.
This series introduces such APIs and converts much of
the code. What is not converted is src/lxc/lxc_native.c,
src/vmx/vmx.c, src/xenconfig/xen_common.c and
src/xenconfig/xen_xl.c. These are left as an exercise
for someone else.
Daniel P. Berrange (16):
tests: remove pointless virconftest.sh wrapper
virconf: fix off-by-1 when appending \n to config file
virconf: add typed value accessor methods
libvirtd: convert to typesafe virConf accessors
qemu: convert to typesafe virConf accessors
libvirt: convert to typesafe virConf accessors
virtlockd: convert to typesafe virConf accessors
virtlogd: convert to typedef virConf accessors
lxc: convert to typesafe virConf accessors
libxl: convert to typesafe virConf accessors
uri: convert to typesafe virConf accessors
virt-login-shell: convert to typesafe virConf accessors
selinux: convert to typesafe virConf accessors
lockd: convert to typesafe virConf accessors
sanlock: convert to typesafe virConf accessors
remote: convert to typesafe virConf accessors
daemon/libvirtd-config.c | 306 ++++++++---------------
daemon/libvirtd-config.h | 42 ++--
po/POTFILES.in | 2 -
src/libvirt-admin.c | 66 ++---
src/libvirt.c | 70 +++---
src/libvirt_private.syms | 10 +
src/libxl/libxl_conf.c | 53 +---
src/locking/lock_daemon_config.c | 90 +------
src/locking/lock_daemon_config.h | 9 +-
src/locking/lock_driver_lockd.c | 61 ++---
src/locking/lock_driver_sanlock.c | 97 +++-----
src/logging/log_daemon_config.c | 96 +-------
src/logging/log_daemon_config.h | 7 +-
src/lxc/lxc_conf.c | 49 ++--
src/lxc/lxc_conf.h | 2 +-
src/qemu/qemu_conf.c | 395 ++++++++++++------------------
src/qemu/qemu_conf.h | 20 +-
src/remote/remote_driver.c | 15 +-
src/security/security_selinux.c | 42 ++--
src/util/virconf.c | 502 +++++++++++++++++++++++++++++++++++++-
src/util/virconf.h | 34 ++-
src/util/viruri.c | 48 ++--
tests/Makefile.am | 19 +-
tests/libvirtdconftest.c | 245 -------------------
tests/virconftest.c | 411 ++++++++++++++++++++++++++++++-
tests/virconftest.sh | 26 --
tools/virt-login-shell.c | 141 +++--------
27 files changed, 1488 insertions(+), 1370 deletions(-)
delete mode 100644 tests/libvirtdconftest.c
delete mode 100755 tests/virconftest.sh
--
2.7.4
8 years, 5 months
[libvirt] [PATCH] qemu: don't set fake reboot if it will not be used
by Nikolay Shirokovskiy
The use case is similar to e2b86f580. First call shutdown with
reboot semantics in agent mode. As a result fake reboot flag is set.
Next issue shutdown from guest and you will get reboot due to fake
reboot flag set.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
src/qemu/qemu_driver.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 61d184b..f9562bd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1997,8 +1997,6 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
useAgent = false;
}
- qemuDomainSetFakeReboot(driver, vm, isReboot);
-
if (useAgent) {
qemuDomainObjEnterAgent(vm);
ret = qemuAgentShutdown(priv->agent, agentFlag);
@@ -2018,6 +2016,7 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
goto endjob;
}
+ qemuDomainSetFakeReboot(driver, vm, isReboot);
qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorSystemPowerdown(priv->mon);
if (qemuDomainObjExitMonitor(driver, vm) < 0)
--
1.8.3.1
8 years, 5 months
[libvirt] [PATCH] tests: command: Fix build on ppc64/aarch64
by Andrea Bolognani
Commit ca10bb040fcf introduced a new test that fails to build
on at least some architectures:
commandtest.c: In function 'test25':
commandtest.c:1121:5: error: comparison is always true due to
limited range of data type [-Werror=type-limits]
if (rv >= 0) {
^
Change the type of 'rv' from char to int, which is the proper
return type for virCommandExec() anyway.
---
Posting this to the list so that Michal/others can chime in.
Using int instead of char seems completely safe here, and in
fact should probably have been the right choice from the start.
On the other hand, I would expect this kind of error if we were
using unsigned char, not plain char... By the way, changing it
to signed char is another way to get the code to compile again
on ppc64/aarch64.
tests/commandtest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/commandtest.c b/tests/commandtest.c
index 2b77b9b..7bf5447 100644
--- a/tests/commandtest.c
+++ b/tests/commandtest.c
@@ -1068,7 +1068,7 @@ static int test25(const void *unused ATTRIBUTE_UNUSED)
{
int ret = -1;
int pipeFD[2] = { -1, -1};
- char rv = 0;
+ int rv = 0;
ssize_t tries = 100;
pid_t pid;
--
2.7.4
8 years, 5 months
[libvirt] Disconnected from qemu, keepalive timeout
by Nir Levy
Hello Guys,
Thanks for reading this,
I have compiled libvirt and qemu over fedora 22 for using debug information and no opt ("-g3 -O0").
I am investigating the xml feature
<qemu:commandline>
<qemu:arg value='-trace'/>
<qemu:arg value='events=/home/qemu_traced_symbols'/>
</qemu:commandline>
qemu_traced_symbols includes all qemu traced symbols.
I have used:
catch syscall clone
set follow-fork-mode child
set detach-on-fork off
and debugged the child
so after libvirt start VM2 wanted to debug the parameters (cmd->args, which indeed includes -trace and events=/home/qemu_traced_symbols
I have debugged the the child after spawning.
And returned for the parent (using gdb inferior 1)
for debugging the virCommandHandshakeWait (with the args)
but I keep getting
error: Disconnected from qemu:///system due to keepalive timeout
grep @ libvirt-1.2.21/ shows no code only change log.
Can you please help me resolve this issue?
How do those args are passed, is it via JSON?
Kind regards,
Nir Levy
SW Engineer
Web: www.asocstech.com<http://www.asocstech.com/> |
[cid:image001.jpg@01D1B599.5A2C9530]
8 years, 5 months
[libvirt] [PATCH v2] Introduce Smack security driver for Libvirt
by Randy Aybar (raybar)
Thanks Daniel and Laine for the feedback so far. Below is a brief list of changes since v1 as well as the patch which should be complete this time.
For others, introduction and background can be found here along with latest response:
https://www.redhat.com/archives/libvir-list/2016-May/msg00628.html
Changes since v1:
Security requirements involving kernel patching to bring in a new
Smack interface are now documented in "docs/drvlxc.html.in”
Fixed the syntax and spacing as requested and recommended by the
“make check-syntax” script
Moved Smack related block in configure.ac to the dedicated m4 file
(m4/virt-smack.m4)
Removed the check for Smack-specific driver before calling
SetChildProcessLabel in lxc_container.c and moved the function call
outside of the namespaces conditional.
Replaced calloc/malloc and open/read/close calls with Libvirt specific
macros in the Smack driver.
Modified src/Makefile to include security driver libraries when
compiling libvirt_nss and dependencies
configure.ac | 4 +
docs/drvlxc.html.in | 14 +-
m4/virt-smack.m4 | 69 ++
po/POTFILES.in | 1 +
src/Makefile.am | 14 +-
src/lxc/lxc_container.c | 24 +-
src/lxc/lxc_controller.c | 21 +
src/security/security_apparmor.c | 9 +
src/security/security_dac.c | 9 +
src/security/security_driver.c | 7 +
src/security/security_driver.h | 4 +
src/security/security_manager.c | 17 +
src/security/security_manager.h | 3 +
src/security/security_nop.c | 8 +
src/security/security_selinux.c | 9 +
src/security/security_smack.c | 1484 ++++++++++++++++++++++++++++++++++++++
src/security/security_smack.h | 37 +
src/security/security_stack.c | 9 +
src/util/vircommand.c | 63 ++
src/util/vircommand.h | 3 +
20 files changed, 1798 insertions(+), 11 deletions(-)
create mode 100644 m4/virt-smack.m4
create mode 100644 src/security/security_smack.c
create mode 100644 src/security/security_smack.h
Signed-off-by: Randy Aybar <raybar(a)cisco.com>
---
diff --git a/configure.ac b/configure.ac
index 378069d..c785914 100644
--- a/configure.ac
+++ b/configure.ac
@@ -255,6 +255,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
@@ -1459,6 +1460,7 @@ if test "$with_apparmor" = "no"; then
fi
AM_CONDITIONAL([WITH_APPARMOR_PROFILES], [test "$with_apparmor_profiles" != "no"])
+
dnl DTrace static probes
AC_ARG_WITH([dtrace],
[AS_HELP_STRING([--with-dtrace],
@@ -2754,6 +2756,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([])
@@ -2784,6 +2787,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/docs/drvlxc.html.in b/docs/drvlxc.html.in
index 3dc9d59..f96c9ba 100644
--- a/docs/drvlxc.html.in
+++ b/docs/drvlxc.html.in
@@ -157,8 +157,7 @@ to all containers are
<li><code>/dev/console</code> symlinked to <code>/dev/pts/0</code></li>
</ul>
-<p>
-In addition, for every console defined in the guest configuration,
+<p> In addition, for every console defined in the guest configuration,
a symlink will be created from <code>/dev/ttyN</code> symlinked to
the corresponding <code>/dev/pts/M</code> pseudo TTY device. The
first console will be <code>/dev/tty1</code>, with further consoles
@@ -190,6 +189,17 @@ isolation between a container and the host must ensure that they are
writing a suitable configuration.
</p>
+<p>
+NOTE: The SMACK security driver depends on a security interface provided
+by the SMACK LSM to fully enforced with namespaces. This interface is
+brought in by the Linux kernel version 4.3. It is recommended to use the
+appropriate kernel version or backport the below changes to ensure proper
+opertaion of the SMACK driver with namespaces.
+
+Link that references the change in the kernel:
+<a href="https://lwn.net/Articles/660675/">https://lwn.net/Articles/660675/</a>
+</p>
+
<h3><a name="securenetworking">Network isolation</a></h3>
<p>
diff --git a/m4/virt-smack.m4 b/m4/virt-smack.m4
new file mode 100644
index 0000000..b555733
--- /dev/null
+++ b/m4/virt-smack.m4
@@ -0,0 +1,69 @@
+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([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"])
+
+
+
+ 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/po/POTFILES.in b/po/POTFILES.in
index 506d535..99e6d6e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -159,6 +159,7 @@ src/security/security_dac.c
src/security/security_driver.c
src/security/security_manager.c
src/security/security_selinux.c
+src/security/security_smack.c
src/security/virt-aa-helper.c
src/storage/parthelper.c
src/storage/storage_backend.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 314f6df..9e53ed9 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)
@@ -1017,6 +1021,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 \
@@ -1765,6 +1772,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)
@@ -1896,6 +1907,7 @@ EXTRA_DIST += \
$(NWFILTER_DRIVER_SOURCES) \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
+ $(SECURITY_DRIVER_SMACK_SOURCES) \
$(SECRET_DRIVER_SOURCES) \
$(SECRET_UTIL_SOURCES) \
$(VBOX_DRIVER_EXTRA_DIST) \
@@ -3030,12 +3042,12 @@ libvirt_nss_la_SOURCES = \
libvirt_nss_la_CFLAGS = \
-DLIBVIRT_NSS \
$(AM_CFLAGS) \
+ $(SECDRIVER_LIBS) \
$(YAJL_CFLAGS) \
$(NULL)
libvirt_nss_la_LDFLAGS = \
$(AM_LDFLAGS) \
$(NULL)
-
libvirt_nss_la_LIBADD = \
$(YAJL_LIBS) \
$(NULL)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index a909b66..ff0e461 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -2206,6 +2206,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 +2258,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 +2271,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);
@@ -2396,6 +2396,14 @@ int lxcContainerStart(virDomainDefPtr def,
return -1;
}
}
+
+ VIR_DEBUG("Setting up security labeling");
+ if (virSecurityManagerSetChildProcessLabel(securityDriver, def, NULL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Failed to send label to relabel interface."));
+ return -1;
+ }
+
if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHARENET] == -1) {
if (lxcNeedNetworkNamespace(def)) {
VIR_DEBUG("Enable network namespaces");
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 0304354..026762e 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1484,6 +1484,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:
VIR_FREE(opts);
@@ -1532,6 +1535,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);
}
@@ -2190,6 +2198,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:
@@ -2234,6 +2250,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 af2b639..bffcf83 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 df3ed47..0ada728 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 7cb62f0..97c0c30 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -104,6 +104,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 +168,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 ecb4a40..507c41e 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -916,6 +916,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 4cbc2d8..886d00a 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -143,6 +143,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 b33d54a..56e07ca 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2467,6 +2467,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)
@@ -2647,6 +2655,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..6f43db4
--- /dev/null
+++ b/src/security/security_smack.c
@@ -0,0 +1,1484 @@
+/*
+ * 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 <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, *path;
+ int ret;
+
+ ret = VIR_ALLOC_N(result, SMACK_LABEL_LEN + 1);
+ if (ret < 0 || result == NULL)
+ return -1;
+ ret = virAsprintf(&path, "/proc/%d/attr/current", pid);
+ if (ret < 0)
+ return -1;
+
+ ret = virFileReadAll(path, SMACK_LABEL_LEN, label);
+
+ VIR_FREE(path);
+ return ret;
+}
+
+int
+virSecuritySmackSockCreate(const char *label, const char *attr)
+{
+ int ret = -1;
+ long int tid;
+ char *path;
+
+ tid = syscall(SYS_gettid);
+
+ VIR_DEBUG("/proc/self/task/%ld/attr/%s", tid, attr);
+
+ if (virAsprintf(&path, "/proc/self/task/%ld/attr/%s", tid, attr) < 0)
+ return -1;
+
+ VIR_DEBUG("setSockCreate 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);
+
+ ret = virFileWriteStr(path, label != NULL ? label : "", 0);
+
+ VIR_FREE(path);
+ return ret;
+}
+
+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) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ if (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) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ if (smack_new_label_from_self(&label) == -1) {
+ virReportSystemError(errno,
+ _("unable to get current process context '%s'"), seclabel->label);
+ goto done;
+ }
+
+ VIR_DEBUG("SmackSetSecurityDaemonSocketLabel is in %d", getpid());
+ VIR_DEBUG("label from self %s", label);
+
+
+ if (virSecuritySmackSockCreate(label, "sockincreate") == -1) {
+ virReportSystemError(errno,
+ _("unable to set socket smack label '%s'"), seclabel->label);
+ goto done;
+ }
+
+ ret = 0;
+ done:
+
+ VIR_FREE(label);
+ return ret;
+
+}
+
+static int
+virSecuritySmackSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr vm)
+{
+
+ virSecurityLabelDefPtr seclabel;
+
+ return 0;
+ seclabel = virDomainDefGetSecurityLabelDef(vm, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STREQ(SECURITY_SMACK_NAME, seclabel->model) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ VIR_DEBUG("Setting VM %s socket label %s", vm->name, seclabel->label);
+
+ if (virSecuritySmackSockCreate(seclabel->label, "sockoutcreate") == -1) {
+ virReportSystemError(errno,
+ _("unable to set socket smack label '%s'"),
+ seclabel->label);
+ return -1;
+ }
+
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+
+ virSecurityLabelDefPtr seclabel;
+
+ return 0;
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STREQ(SECURITY_SMACK_NAME, seclabel->model) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "'%s' model configured for domain, but "
+ "hypervisor driver is '%s'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+ return -1;
+ }
+
+ VIR_DEBUG("clear sock label");
+
+ if (virSecuritySmackSockCreate(NULL, "sockincreate") == -1 ||
+ virSecuritySmackSockCreate(NULL, "sockoutcreate") == -1) {
+ virReportSystemError(errno,
+ _("unable to clear socket smack label '%s'"),
+ seclabel->label);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+*Current called in qemuStartVMDaemon to setup a 'label'. We make the
+*label based on UUID.
+*this is called on 'start'with RestoreSecurityLabel being called on
+*shutdown
+ */
+static int
+virSecuritySmackGenLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def)
+{
+ int ret = -1;
+ char *label_name = NULL;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return ret;
+
+ VIR_DEBUG("label=%s", virSecurityManagerGetDriver(mgr));
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+ seclabel->label) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("security label already defined for VM"));
+ return ret;
+ }
+
+ if (seclabel->imagelabel) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("security image label already defined for VM"));
+ return ret;
+ }
+
+ if (seclabel->model &&
+ STRNEQ(seclabel->model, SECURITY_SMACK_NAME)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label model %s is not supported with smack"),
+ seclabel->model);
+ return ret;
+ }
+
+ VIR_DEBUG("type=%d", seclabel->type);
+
+ if ((label_name = virSecuritySmackGetLabelName(def)) == NULL)
+ return ret;
+
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+
+ /*set process label*/
+ if (VIR_STRDUP(seclabel->label, label_name) < 0)
+ goto cleanup;
+ }
+
+ /*set imagelabel the same as label*/
+ if (VIR_STRDUP(seclabel->imagelabel, label_name) < 0)
+ goto cleanup;
+
+ if (!seclabel->model &&
+ VIR_STRDUP(seclabel->model, SECURITY_SMACK_NAME) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+
+ if (ret != 0) {
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
+ VIR_FREE(seclabel->label);
+ VIR_FREE(seclabel->imagelabel);
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+ !seclabel->baselabel)
+ VIR_FREE(seclabel->model);
+ }
+
+ VIR_FREE(label_name);
+
+ VIR_DEBUG("model=%s label=%s imagelabel=%s",
+ NULLSTR(seclabel->model),
+ NULLSTR(seclabel->label),
+ NULLSTR(seclabel->imagelabel));
+
+ return ret;
+
+}
+
+static int
+virSecuritySmackReserveLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ pid_t pid ATTRIBUTE_UNUSED)
+{
+ /*Security label is based UUID,*/
+ return 0;
+}
+
+/*
+*Called on VM shutdown and destroy.
+*/
+static int
+virSecuritySmackReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+ VIR_FREE(seclabel->label);
+ VIR_FREE(seclabel->model);
+ }
+ VIR_FREE(seclabel->imagelabel);
+
+ return 0;
+
+}
+
+/* Seen with 'virsh dominfo <vm>'. This function only called if the VM is
+* running.
+*/
+static int
+virSecuritySmackGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ pid_t pid,
+ virSecurityLabelPtr sec)
+{
+
+ char *label_name = NULL;
+
+ if (virSecuritySmackGetPIDLabel(pid, &label_name) == -1) {
+ virReportSystemError(errno,
+ _("unable to get PID %d security label"),
+ pid);
+ return -1;
+ }
+
+ if (strlen(label_name) >= VIR_SECURITY_LABEL_BUFLEN) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label exceeds "
+ "maximum length: %d"),
+ VIR_SECURITY_LABEL_BUFLEN - 1);
+ VIR_FREE(label_name);
+ return -1;
+ }
+
+ label_name = virStrcpy(sec->label, label_name, VIR_SECURITY_LABEL_BUFLEN);
+ VIR_FREE(label_name);
+ /*Smack default enforced*/
+ sec->enforcing = 1;
+
+ return label_name == NULL ? -1 : 0;
+}
+
+static int
+virSecuritySmackSetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STRNEQ(SECURITY_SMACK_NAME, seclabel->model)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "\'%s\' model configured for domain, but "
+ "hypervisor driver is \'%s\'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+
+ return -1;
+ }
+
+ if (smack_set_label_for_self(seclabel->label) < 0) {
+ virReportError(errno,
+ _("unable to set security label '%s'"),
+ seclabel->label);
+
+ return -1;
+ }
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackSetChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ virCommandPtr cmd)
+{
+ virSecurityLabelDefPtr seclabel;
+ int rlbl;
+ char *smackfs_path = NULL;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+ if (STRNEQ(SECURITY_SMACK_NAME, seclabel->model)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("security label driver mismatch: "
+ "\'%s\' model configured for domain, but "
+ "hypervisor driver is \'%s\'."),
+ seclabel->model, SECURITY_SMACK_NAME);
+
+ return -1;
+ }
+
+ /*
+ * Send label to relabel-self interface to allow child to label
+ * its self once it finishes setting up. Apply only if interface is
+ * available and user namespace is enabled.
+ */
+
+ if (STREQ(virSecurityManagerGetDriver(mgr), "LXC")) {
+
+ if (!def->idmap.nuidmap)
+ return 0;
+
+ VIR_DEBUG("Applying label %s to relabel-self interface.", seclabel->label);
+
+ if (virAsprintf(&smackfs_path, "%s/relabel-self", smack_smackfs_path()) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to obtain path for smackfs. Is smack enabled? "));
+ return -1;
+ }
+
+ rlbl = open(smackfs_path, O_WRONLY);
+
+ if (rlbl < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open relabel interface \'%s\' for writing. Is it "
+ "enabled in the kernel?"),
+ smackfs_path);
+ return -1;
+ }
+
+ if (safewrite(rlbl, seclabel->label, strlen(seclabel->label)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not write to relabel interface \'%s\'."),
+ smackfs_path);
+ return -1;
+ }
+
+ VIR_FORCE_CLOSE(rlbl);
+ }
+
+ /* save in cmd to be set after fork/before child process is exec'ed */
+ virCommandSetSmackLabel(cmd, seclabel->label);
+ VIR_DEBUG("save smack label in cmd %s", seclabel->label);
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackSetAllLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ const char *stdin_path)
+{
+
+ size_t i;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ VIR_DEBUG("set image security label before");
+
+ for (i = 0; i < def->ndisks; i++) {
+ if (def->disks[i]->src->type == VIR_STORAGE_TYPE_DIR) {
+ VIR_WARN("Unable to relabel directory tree %s for disk %s",
+ def->disks[i]->src->path, def->disks[i]->dst);
+ continue;
+ }
+
+ VIR_DEBUG("set image security label");
+
+ if (virSecuritySmackSetImageLabel(mgr,
+ def, def->disks[i]->src) < 0)
+ return -1;
+ }
+
+ VIR_DEBUG("set image security label after");
+
+ for (i = 0; i< def->nhostdevs; i++) {
+ if (virSecuritySmackSetHostdevLabel(mgr,
+ def,
+ def->hostdevs[i],
+ NULL) < 0)
+ return -1;
+
+ }
+
+ if (stdin_path) {
+ if (setxattr(stdin_path, "security.SMACK64", seclabel->imagelabel,
+ strlen(seclabel->imagelabel) + 1, 0)< 0 &&
+ virFileIsSharedFS(stdin_path) != 1)
+ return -1;
+ }
+
+ return 0;
+
+}
+
+static int
+virSecuritySmackRestoreAllLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ bool migrated ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ virSecurityLabelDefPtr seclabel;
+
+ VIR_DEBUG("Restoring security label on %s", def->name);
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ for (i = 0; i < def->ndisks; i++) {
+
+ if (virSecuritySmackRestoreImageLabelInt(mgr,
+ def,
+ def->disks[i]->src,
+ migrated) < 0)
+
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+
+static int
+virSecuritySmackSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ const char *savefile)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ return virSecuritySmackSetPathLabel(savefile, seclabel->imagelabel);
+}
+
+static int
+virSecuritySmackRestoreSavedStateLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ const char *savefile)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (!seclabel->relabel)
+ return 0;
+
+ return virSecuritySmackRestoreFileLabel(mgr, savefile);
+}
+
+static int
+virSecuritySmackSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ int fd)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->imagelabel == NULL)
+ return 0;
+
+ return virSecuritySmackSetFileLabel(fd, seclabel->imagelabel);
+
+}
+
+static int
+virSecuritySmackSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ const char *path)
+{
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->imagelabel == NULL)
+ return 0;
+
+ if (virSecuritySmackSetPathLabel(path, seclabel->imagelabel) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+virSecuritySmackSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ int fd)
+{
+ struct stat buf;
+ virSecurityLabelDefPtr seclabel;
+
+ seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME);
+ if (seclabel == NULL)
+ return -1;
+
+ if (seclabel->label == NULL)
+ return 0;
+
+
+ if (fstat(fd, &buf) < 0) {
+ virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
+ return -1;
+ }
+
+ if ((buf.st_mode & S_IFMT) != S_IFCHR) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("tap fd %d is not character device"), fd);
+ return -1;
+ }
+
+ return virSecuritySmackSetFileLabel(fd, seclabel->label);
+
+}
+
+static char *
+virSecuritySmackGetSecurityMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ char *opts = NULL;
+ virSecurityLabelDefPtr seclabel;
+
+ if ((seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SMACK_NAME))) {
+ if (!seclabel->imagelabel) {
+ if (!seclabel->label)
+ seclabel->imagelabel = virSecuritySmackGetLabelName(def);
+ else
+ seclabel->imagelabel = seclabel->label;
+ }
+ if (seclabel->imagelabel &&
+ virAsprintf(&opts,
+ ",smackfsdef=\"%s\"",
+ (const char*) seclabel->imagelabel) < 0)
+ return NULL;
+ }
+
+ if (!opts && VIR_STRDUP(opts, "") < 0)
+ return NULL;
+
+ return opts;
+
+}
+
+static const char *
+virSecuritySmackGetBaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ int virtType ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+virSecurityDriver virSecurityDriverSmack = {
+ .privateDataLen = 0,
+ .name = SECURITY_SMACK_NAME,
+ .probe = virSecuritySmackSecurityDriverProbe,
+ .open = virSecuritySmackSecurityDriverOpen,
+ .close = virSecuritySmackSecurityDriverClose,
+
+ .getModel = virSecuritySmackSecurityDriverGetModel,
+ .getDOI = virSecuritySmackSecurityDriverGetDOI,
+
+ .domainSecurityVerify = virSecuritySmackSecurityVerify,
+
+ .domainSetSecurityDiskLabel = virSecuritySmackSetDiskLabel,
+ .domainRestoreSecurityDiskLabel = virSecuritySmackRestoreDiskLabel,
+
+ .domainSetSecurityImageLabel = virSecuritySmackSetImageLabel,
+ .domainRestoreSecurityImageLabel = virSecuritySmackRestoreImageLabel,
+
+ .domainSetSecurityDaemonSocketLabel = virSecuritySmackSetDaemonSocketLabel,
+ .domainSetSecuritySocketLabel = virSecuritySmackSetSocketLabel,
+ .domainClearSecuritySocketLabel = virSecuritySmackClearSocketLabel,
+
+ .domainGenSecurityLabel = virSecuritySmackGenLabel,
+ .domainReserveSecurityLabel = virSecuritySmackReserveLabel,
+ .domainReleaseSecurityLabel = virSecuritySmackReleaseLabel,
+
+ .domainGetSecurityProcessLabel = virSecuritySmackGetProcessLabel,
+ .domainSetSecurityProcessLabel = virSecuritySmackSetProcessLabel,
+ .domainSetSecurityChildProcessLabel = virSecuritySmackSetChildProcessLabel,
+
+ .domainSetSecurityAllLabel = virSecuritySmackSetAllLabel,
+ .domainRestoreSecurityAllLabel = virSecuritySmackRestoreAllLabel,
+
+ .domainSetSecurityHostdevLabel = virSecuritySmackSetHostdevLabel,
+ .domainRestoreSecurityHostdevLabel = virSecuritySmackRestoreHostdevLabel,
+
+ .domainSetSavedStateLabel = virSecuritySmackSetSavedStateLabel,
+ .domainRestoreSavedStateLabel = virSecuritySmackRestoreSavedStateLabel,
+
+ .domainSetSecurityImageFDLabel = virSecuritySmackSetImageFDLabel,
+ .domainSetSecurityImagePathLabel = virSecuritySmackSetImagePathLabel,
+ .domainSetSecurityTapFDLabel = virSecuritySmackSetTapFDLabel,
+
+ .domainGetSecurityMountOptions = virSecuritySmackGetSecurityMountOptions,
+
+ .getBaseLabel = virSecuritySmackGetBaseLabel,
+
+};
diff --git a/src/security/security_smack.h b/src/security/security_smack.h
new file mode 100644
index 0000000..3d9fad9
--- /dev/null
+++ b/src/security/security_smack.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 Cisco Systems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Hongliang Liang <hliang(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 3ea2751..e30f003 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -495,6 +495,14 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr,
}
static int
+virSecurityStackSetImagePathLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr vm ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int
virSecurityStackSetTapFDLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
int fd)
@@ -659,6 +667,7 @@ virSecurityDriver virSecurityDriverStack = {
.domainRestoreSavedStateLabel = virSecurityStackRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = virSecurityStackSetImageFDLabel,
+ .domainSetSecurityImagePathLabel = virSecurityStackSetImagePathLabel,
.domainSetSecurityTapFDLabel = virSecurityStackSetTapFDLabel,
.domainGetSecurityMountOptions = virSecurityStackGetMountOptions,
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 027cb64..cdcb3a2 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -41,6 +41,9 @@
#if defined(WITH_SECDRIVER_APPARMOR)
# include <sys/apparmor.h>
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+# include <sys/smack.h>
+#endif
#define __VIR_COMMAND_PRIV_H_ALLOW__
#include "vircommandpriv.h"
@@ -134,6 +137,10 @@ struct _virCommand {
#if defined(WITH_SECDRIVER_APPARMOR)
char *appArmorProfile;
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+ char *smackLabel;
+#endif
+
int mask;
};
@@ -722,6 +729,30 @@ virExec(virCommandPtr cmd)
}
# endif
+# if defined(WITH_SECDRIVER_SMACK)
+ if (cmd->smackLabel) {
+ VIR_DEBUG("Setting child security label to %s", cmd->smackLabel);
+
+ if (smack_set_label_for_self(cmd->smackLabel) < 0) {
+ virReportSystemError(errno,
+ _("unable to set Smack label '%s' "
+ "for '%s'"),
+ cmd->smackLabel, cmd->args[0]);
+ goto fork_error;
+ }
+ }
+# endif
+
+/*
+ * if (smack_new_label_from_self(&label) == -1)
+ * {
+ * goto fork_error;
+ * }
+ * VIR_DEBUG("smack label is %s",label);
+ * free(label);
+ *
+ *
+ */
/* The steps above may need to do something privileged, so we delay
* setuid and clearing capabilities until the last minute.
*/
@@ -1197,6 +1228,35 @@ virCommandSetAppArmorProfile(virCommandPtr cmd,
}
+
+/**
+ * virCommandSetSmackLabel:
+ * @cmd: the command to modify
+ * @label: the Smack label to use for the child process
+ *
+ * Saves a copy of @label to use when setting the Smack context
+ * label (write to /proc/self/attr/current ) after the child process has
+ * been started. If Smack isn't compiled into libvirt, or if label is
+ * NULL, nothing will be done.
+ */
+void
+virCommandSetSmackLabel(virCommandPtr cmd,
+ const char *label ATTRIBUTE_UNUSED)
+
+{
+ if (!cmd || cmd->has_error)
+ return;
+
+#if defined(WITH_SECDRIVER_SMACK)
+ VIR_FREE(cmd->smackLabel);
+ if (VIR_STRDUP_QUIET(cmd->smackLabel, label) < 0)
+ cmd->has_error = ENOMEM;
+#endif
+ return;
+
+}
+
+
/**
* virCommandDaemonize:
* @cmd: the command to modify
@@ -2796,6 +2856,9 @@ virCommandFree(virCommandPtr cmd)
#if defined(WITH_SECDRIVER_APPARMOR)
VIR_FREE(cmd->appArmorProfile);
#endif
+#if defined(WITH_SECDRIVER_SMACK)
+ VIR_FREE(cmd->smackLabel);
+#endif
VIR_FREE(cmd);
}
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index 198da2f..dfc8a65 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -88,6 +88,9 @@ void virCommandSetSELinuxLabel(virCommandPtr cmd,
void virCommandSetAppArmorProfile(virCommandPtr cmd,
const char *profile);
+void virCommandSetSmackLabel(virCommandPtr cmd,
+ const char *label);
+
void virCommandDaemonize(virCommandPtr cmd);
void virCommandNonblockingFDs(virCommandPtr cmd);
--
1.9.1
8 years, 5 months