1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-22 17:34:18 +03:00

selinux: enhance test to cover nfs label failure

Daniel Berrange (correctly) pointed out that we should do a better
job of testing selinux labeling fallbacks on NFS disks that lack
labeling support.

* tests/securityselinuxhelper.c (includes): Makefile already
guaranteed xattr support.  Add additional headers.
(init_syms): New function, borrowing from vircgroupmock.c.
(setfilecon_raw, getfilecon_raw): Fake NFS failure.
(statfs): Fake an NFS mount point.
(security_getenforce, security_get_boolean_active): Don't let host
environment affect test.
* tests/securityselinuxlabeldata/nfs.data: New file.
* tests/securityselinuxlabeldata/nfs.xml: New file.
* tests/securityselinuxlabeltest.c (testSELinuxCreateDisks)
(testSELinuxDeleteDisks): Setup and cleanup for fake NFS mount.
(testSELinuxCheckLabels): Test handling of SELinux NFS denial.
Fix memory leak.
(testSELinuxLabeling): Avoid infinite loop on dirty tree.
(mymain): Add new test.
This commit is contained in:
Eric Blake 2013-08-13 14:19:14 -06:00
parent 0f082e699e
commit 95577af442
4 changed files with 117 additions and 11 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2012 Red Hat, Inc.
* Copyright (C) 2011-2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -19,22 +19,53 @@
#include <config.h>
/* This file is only compiled on Linux, and only if xattr support was
* detected. */
#include <dlfcn.h>
#include <errno.h>
#include <linux/magic.h>
#include <selinux/selinux.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <errno.h>
#if WITH_ATTR
# include <attr/xattr.h>
#endif
#include <attr/xattr.h>
#include "virstring.h"
static int (*realstatfs)(const char *path, struct statfs *buf);
static int (*realsecurity_get_boolean_active)(const char *name);
static void init_syms(void)
{
if (realstatfs)
return;
#define LOAD_SYM(name) \
do { \
if (!(real ## name = dlsym(RTLD_NEXT, #name))) { \
fprintf(stderr, "Cannot find real '%s' symbol\n", #name); \
abort(); \
} \
} while (0)
LOAD_SYM(statfs);
LOAD_SYM(security_get_boolean_active);
#undef LOAD_SYM
}
/*
* The kernel policy will not allow us to arbitrarily change
* test process context. This helper is used as an LD_PRELOAD
* so that the libvirt code /thinks/ it is changing/reading
* the process context, where as in fact we're faking it all
* the process context, whereas in fact we're faking it all.
* Furthermore, we fake out that we are using an nfs subdirectory,
* where we control whether selinux is enforcing and whether
* the virt_use_nfs bool is set.
*/
int getcon_raw(security_context_t *context)
@ -83,10 +114,13 @@ int setcon(security_context_t context)
}
#if WITH_ATTR
int setfilecon_raw(const char *path, security_context_t con)
{
const char *constr = con;
if (STRPREFIX(path, abs_builddir "/securityselinuxlabeldata/nfs/")) {
errno = EOPNOTSUPP;
return -1;
}
return setxattr(path, "user.libvirt.selinux",
constr, strlen(constr), 0);
}
@ -101,6 +135,10 @@ int getfilecon_raw(const char *path, security_context_t *con)
char *constr = NULL;
ssize_t len = getxattr(path, "user.libvirt.selinux",
NULL, 0);
if (STRPREFIX(path, abs_builddir "/securityselinuxlabeldata/nfs/")) {
errno = EOPNOTSUPP;
return -1;
}
if (len < 0)
return -1;
if (!(constr = malloc(len+1)))
@ -114,8 +152,40 @@ int getfilecon_raw(const char *path, security_context_t *con)
constr[len] = '\0';
return 0;
}
int getfilecon(const char *path, security_context_t *con)
{
return getfilecon_raw(path, con);
}
#endif
int statfs(const char *path, struct statfs *buf)
{
int ret;
init_syms();
ret = realstatfs(path, buf);
if (!ret && STREQ(path, abs_builddir "/securityselinuxlabeldata/nfs"))
buf->f_type = NFS_SUPER_MAGIC;
return ret;
}
int security_getenforce(void)
{
/* For the purpose of our test, we are enforcing. */
return 1;
}
int security_get_boolean_active(const char *name)
{
/* For the purpose of our test, nfs is not permitted. */
if (STREQ(name, "virt_use_nfs"))
return 0;
init_syms();
return realsecurity_get_boolean_active(name);
}

View File

@ -0,0 +1 @@
/nfs/plain.raw;EOPNOTSUPP

View File

@ -0,0 +1,24 @@
<domain type='kvm'>
<name>vm1</name>
<uuid>c7b3edbd-edaf-9455-926a-d65c16db1800</uuid>
<memory unit='KiB'>219200</memory>
<os>
<type arch='i686' machine='pc-1.0'>hvm</type>
<boot dev='cdrom'/>
</os>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/nfs/plain.raw'/>
<target dev='vda' bus='virtio'/>
</disk>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
</devices>
<seclabel model="selinux" type="dynamic" relabel="yes">
<label>system_u:system_r:svirt_t:s0:c41,c264</label>
<imagelabel>system_u:object_r:svirt_image_t:s0:c41,c264</imagelabel>
</seclabel>
</domain>

View File

@ -209,7 +209,7 @@ testSELinuxCreateDisks(testSELinuxFile *files, size_t nfiles)
{
size_t i;
if (virFileMakePath(abs_builddir "/securityselinuxlabeldata") < 0)
if (virFileMakePath(abs_builddir "/securityselinuxlabeldata/nfs") < 0)
return -1;
for (i = 0; i < nfiles; i++) {
@ -228,6 +228,10 @@ testSELinuxDeleteDisks(testSELinuxFile *files, size_t nfiles)
if (unlink(files[i].file) < 0)
return -1;
}
if (rmdir(abs_builddir "/securityselinuxlabeldata/nfs") < 0)
return -1;
/* Ignore failure to remove non-empty directory with in-tree build */
rmdir(abs_builddir "/securityselinuxlabeldata");
return 0;
}
@ -238,9 +242,13 @@ testSELinuxCheckLabels(testSELinuxFile *files, size_t nfiles)
security_context_t ctx;
for (i = 0; i < nfiles; i++) {
ctx = NULL;
if (getfilecon(files[i].file, &ctx) < 0) {
if (errno == ENODATA) {
ctx = NULL;
/* nothing to do */
} else if (errno == EOPNOTSUPP) {
if (VIR_STRDUP(ctx, "EOPNOTSUPP") < 0)
return -1;
} else {
virReportSystemError(errno,
"Cannot read label on %s",
@ -252,8 +260,10 @@ testSELinuxCheckLabels(testSELinuxFile *files, size_t nfiles)
virReportError(VIR_ERR_INTERNAL_ERROR,
"File %s context '%s' did not match epected '%s'",
files[i].file, ctx, files[i].context);
VIR_FREE(ctx);
return -1;
}
VIR_FREE(ctx);
}
return 0;
}
@ -287,7 +297,7 @@ testSELinuxLabeling(const void *opaque)
cleanup:
if (testSELinuxDeleteDisks(files, nfiles) < 0)
goto cleanup;
VIR_WARN("unable to fully clean up");
virDomainDefFree(def);
for (i = 0; i < nfiles; i++) {
@ -334,6 +344,7 @@ mymain(void)
DO_TEST_LABELING("disks");
DO_TEST_LABELING("kernel");
DO_TEST_LABELING("chardev");
DO_TEST_LABELING("nfs");
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}