43fe83
From 6deaf5a18aa0c03952cdcaa5ea95f53aebcf995f Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <6deaf5a18aa0c03952cdcaa5ea95f53aebcf995f.1378475168.git.jdenemar@redhat.com>
43fe83
From: Eric Blake <eblake@redhat.com>
43fe83
Date: Tue, 20 Aug 2013 11:08:55 -0600
43fe83
Subject: [PATCH] selinux: enhance test to cover nfs label failure
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=924153
43fe83
43fe83
Daniel Berrange (correctly) pointed out that we should do a better
43fe83
job of testing selinux labeling fallbacks on NFS disks that lack
43fe83
labeling support.
43fe83
43fe83
* tests/securityselinuxhelper.c (includes): Makefile already
43fe83
guaranteed xattr support.  Add additional headers.
43fe83
(init_syms): New function, borrowing from vircgroupmock.c.
43fe83
(setfilecon_raw, getfilecon_raw): Fake NFS failure.
43fe83
(statfs): Fake an NFS mount point.
43fe83
(security_getenforce, security_get_boolean_active): Don't let host
43fe83
environment affect test.
43fe83
* tests/securityselinuxlabeldata/nfs.data: New file.
43fe83
* tests/securityselinuxlabeldata/nfs.xml: New file.
43fe83
* tests/securityselinuxlabeltest.c (testSELinuxCreateDisks)
43fe83
(testSELinuxDeleteDisks): Setup and cleanup for fake NFS mount.
43fe83
(testSELinuxCheckLabels): Test handling of SELinux NFS denial.
43fe83
Fix memory leak.
43fe83
(testSELinuxLabeling): Avoid infinite loop on dirty tree.
43fe83
(mymain): Add new test.
43fe83
43fe83
(cherry picked from commit 95577af442e503bb209808b04b6482c895c9f561)
43fe83
---
43fe83
 tests/securityselinuxhelper.c          | 86 ++++++++++++++++++++++++++++++----
43fe83
 tests/securityselinuxlabeldata/nfs.txt |  1 +
43fe83
 tests/securityselinuxlabeldata/nfs.xml | 24 ++++++++++
43fe83
 tests/securityselinuxlabeltest.c       | 17 +++++--
43fe83
 4 files changed, 117 insertions(+), 11 deletions(-)
43fe83
 create mode 100644 tests/securityselinuxlabeldata/nfs.txt
43fe83
 create mode 100644 tests/securityselinuxlabeldata/nfs.xml
43fe83
43fe83
diff --git a/tests/securityselinuxhelper.c b/tests/securityselinuxhelper.c
43fe83
index a82ca6d..89cba3a 100644
43fe83
--- a/tests/securityselinuxhelper.c
43fe83
+++ b/tests/securityselinuxhelper.c
43fe83
@@ -1,5 +1,5 @@
43fe83
 /*
43fe83
- * Copyright (C) 2011-2012 Red Hat, Inc.
43fe83
+ * Copyright (C) 2011-2013 Red Hat, Inc.
43fe83
  *
43fe83
  * This library is free software; you can redistribute it and/or
43fe83
  * modify it under the terms of the GNU Lesser General Public
43fe83
@@ -19,22 +19,53 @@
43fe83
 
43fe83
 #include <config.h>
43fe83
 
43fe83
+/* This file is only compiled on Linux, and only if xattr support was
43fe83
+ * detected. */
43fe83
+
43fe83
+#include <dlfcn.h>
43fe83
+#include <errno.h>
43fe83
+#include <linux/magic.h>
43fe83
 #include <selinux/selinux.h>
43fe83
+#include <stdio.h>
43fe83
 #include <stdlib.h>
43fe83
 #include <string.h>
43fe83
+#include <sys/vfs.h>
43fe83
 #include <unistd.h>
43fe83
-#include <errno.h>
43fe83
-#if WITH_ATTR
43fe83
-# include <attr/xattr.h>
43fe83
-#endif
43fe83
+#include <attr/xattr.h>
43fe83
 
43fe83
 #include "virstring.h"
43fe83
 
43fe83
+static int (*realstatfs)(const char *path, struct statfs *buf);
43fe83
+static int (*realsecurity_get_boolean_active)(const char *name);
43fe83
+
43fe83
+static void init_syms(void)
43fe83
+{
43fe83
+    if (realstatfs)
43fe83
+        return;
43fe83
+
43fe83
+#define LOAD_SYM(name)                                                  \
43fe83
+    do {                                                                \
43fe83
+        if (!(real ## name = dlsym(RTLD_NEXT, #name))) {                \
43fe83
+            fprintf(stderr, "Cannot find real '%s' symbol\n", #name);   \
43fe83
+            abort();                                                    \
43fe83
+        }                                                               \
43fe83
+    } while (0)
43fe83
+
43fe83
+    LOAD_SYM(statfs);
43fe83
+    LOAD_SYM(security_get_boolean_active);
43fe83
+
43fe83
+#undef LOAD_SYM
43fe83
+}
43fe83
+
43fe83
+
43fe83
 /*
43fe83
  * The kernel policy will not allow us to arbitrarily change
43fe83
  * test process context. This helper is used as an LD_PRELOAD
43fe83
  * so that the libvirt code /thinks/ it is changing/reading
43fe83
- * the process context, where as in fact we're faking it all
43fe83
+ * the process context, whereas in fact we're faking it all.
43fe83
+ * Furthermore, we fake out that we are using an nfs subdirectory,
43fe83
+ * where we control whether selinux is enforcing and whether
43fe83
+ * the virt_use_nfs bool is set.
43fe83
  */
43fe83
 
43fe83
 int getcon_raw(security_context_t *context)
43fe83
@@ -83,10 +114,13 @@ int setcon(security_context_t context)
43fe83
 }
43fe83
 
43fe83
 
43fe83
-#if WITH_ATTR
43fe83
 int setfilecon_raw(const char *path, security_context_t con)
43fe83
 {
43fe83
     const char *constr = con;
43fe83
+    if (STRPREFIX(path, abs_builddir "/securityselinuxlabeldata/nfs/")) {
43fe83
+        errno = EOPNOTSUPP;
43fe83
+        return -1;
43fe83
+    }
43fe83
     return setxattr(path, "user.libvirt.selinux",
43fe83
                     constr, strlen(constr), 0);
43fe83
 }
43fe83
@@ -101,6 +135,10 @@ int getfilecon_raw(const char *path, security_context_t *con)
43fe83
     char *constr = NULL;
43fe83
     ssize_t len = getxattr(path, "user.libvirt.selinux",
43fe83
                            NULL, 0);
43fe83
+    if (STRPREFIX(path, abs_builddir "/securityselinuxlabeldata/nfs/")) {
43fe83
+        errno = EOPNOTSUPP;
43fe83
+        return -1;
43fe83
+    }
43fe83
     if (len < 0)
43fe83
         return -1;
43fe83
     if (!(constr = malloc(len+1)))
43fe83
@@ -114,8 +152,40 @@ int getfilecon_raw(const char *path, security_context_t *con)
43fe83
     constr[len] = '\0';
43fe83
     return 0;
43fe83
 }
43fe83
+
43fe83
+
43fe83
 int getfilecon(const char *path, security_context_t *con)
43fe83
 {
43fe83
     return getfilecon_raw(path, con);
43fe83
 }
43fe83
-#endif
43fe83
+
43fe83
+
43fe83
+int statfs(const char *path, struct statfs *buf)
43fe83
+{
43fe83
+    int ret;
43fe83
+
43fe83
+    init_syms();
43fe83
+
43fe83
+    ret = realstatfs(path, buf);
43fe83
+    if (!ret && STREQ(path, abs_builddir "/securityselinuxlabeldata/nfs"))
43fe83
+        buf->f_type = NFS_SUPER_MAGIC;
43fe83
+    return ret;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+int security_getenforce(void)
43fe83
+{
43fe83
+    /* For the purpose of our test, we are enforcing.  */
43fe83
+    return 1;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+int security_get_boolean_active(const char *name)
43fe83
+{
43fe83
+    /* For the purpose of our test, nfs is not permitted.  */
43fe83
+    if (STREQ(name, "virt_use_nfs"))
43fe83
+        return 0;
43fe83
+
43fe83
+    init_syms();
43fe83
+    return realsecurity_get_boolean_active(name);
43fe83
+}
43fe83
diff --git a/tests/securityselinuxlabeldata/nfs.txt b/tests/securityselinuxlabeldata/nfs.txt
43fe83
new file mode 100644
43fe83
index 0000000..4c1698e
43fe83
--- /dev/null
43fe83
+++ b/tests/securityselinuxlabeldata/nfs.txt
43fe83
@@ -0,0 +1 @@
43fe83
+/nfs/plain.raw;EOPNOTSUPP
43fe83
diff --git a/tests/securityselinuxlabeldata/nfs.xml b/tests/securityselinuxlabeldata/nfs.xml
43fe83
new file mode 100644
43fe83
index 0000000..46a1440
43fe83
--- /dev/null
43fe83
+++ b/tests/securityselinuxlabeldata/nfs.xml
43fe83
@@ -0,0 +1,24 @@
43fe83
+<domain type='kvm'>
43fe83
+  <name>vm1</name>
43fe83
+  <uuid>c7b3edbd-edaf-9455-926a-d65c16db1800</uuid>
43fe83
+  <memory unit='KiB'>219200</memory>
43fe83
+  <os>
43fe83
+    <type arch='i686' machine='pc-1.0'>hvm</type>
43fe83
+    <boot dev='cdrom'/>
43fe83
+  </os>
43fe83
+  <devices>
43fe83
+    <disk type='file' device='disk'>
43fe83
+      <driver name='qemu' type='raw'/>
43fe83
+      <source file='/nfs/plain.raw'/>
43fe83
+      <target dev='vda' bus='virtio'/>
43fe83
+    </disk>
43fe83
+    <input type='mouse' bus='ps2'/>
43fe83
+    <graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'>
43fe83
+      <listen type='address' address='0.0.0.0'/>
43fe83
+    </graphics>
43fe83
+  </devices>
43fe83
+  <seclabel model="selinux" type="dynamic" relabel="yes">
43fe83
+    <label>system_u:system_r:svirt_t:s0:c41,c264</label>
43fe83
+    <imagelabel>system_u:object_r:svirt_image_t:s0:c41,c264</imagelabel>
43fe83
+  </seclabel>
43fe83
+</domain>
43fe83
diff --git a/tests/securityselinuxlabeltest.c b/tests/securityselinuxlabeltest.c
43fe83
index efe825a..fa99f99 100644
43fe83
--- a/tests/securityselinuxlabeltest.c
43fe83
+++ b/tests/securityselinuxlabeltest.c
43fe83
@@ -209,7 +209,7 @@ testSELinuxCreateDisks(testSELinuxFile *files, size_t nfiles)
43fe83
 {
43fe83
     size_t i;
43fe83
 
43fe83
-    if (virFileMakePath(abs_builddir "/securityselinuxlabeldata") < 0)
43fe83
+    if (virFileMakePath(abs_builddir "/securityselinuxlabeldata/nfs") < 0)
43fe83
         return -1;
43fe83
 
43fe83
     for (i = 0; i < nfiles; i++) {
43fe83
@@ -228,6 +228,10 @@ testSELinuxDeleteDisks(testSELinuxFile *files, size_t nfiles)
43fe83
         if (unlink(files[i].file) < 0)
43fe83
             return -1;
43fe83
     }
43fe83
+    if (rmdir(abs_builddir "/securityselinuxlabeldata/nfs") < 0)
43fe83
+        return -1;
43fe83
+    /* Ignore failure to remove non-empty directory with in-tree build */
43fe83
+    rmdir(abs_builddir "/securityselinuxlabeldata");
43fe83
     return 0;
43fe83
 }
43fe83
 
43fe83
@@ -238,9 +242,13 @@ testSELinuxCheckLabels(testSELinuxFile *files, size_t nfiles)
43fe83
     security_context_t ctx;
43fe83
 
43fe83
     for (i = 0; i < nfiles; i++) {
43fe83
+        ctx = NULL;
43fe83
         if (getfilecon(files[i].file, &ctx) < 0) {
43fe83
             if (errno == ENODATA) {
43fe83
-                ctx = NULL;
43fe83
+                /* nothing to do */
43fe83
+            } else if (errno == EOPNOTSUPP) {
43fe83
+                if (VIR_STRDUP(ctx, "EOPNOTSUPP") < 0)
43fe83
+                    return -1;
43fe83
             } else {
43fe83
                 virReportSystemError(errno,
43fe83
                                      "Cannot read label on %s",
43fe83
@@ -252,8 +260,10 @@ testSELinuxCheckLabels(testSELinuxFile *files, size_t nfiles)
43fe83
             virReportError(VIR_ERR_INTERNAL_ERROR,
43fe83
                            "File %s context '%s' did not match epected '%s'",
43fe83
                            files[i].file, ctx, files[i].context);
43fe83
+            VIR_FREE(ctx);
43fe83
             return -1;
43fe83
         }
43fe83
+        VIR_FREE(ctx);
43fe83
     }
43fe83
     return 0;
43fe83
 }
43fe83
@@ -287,7 +297,7 @@ testSELinuxLabeling(const void *opaque)
43fe83
 
43fe83
 cleanup:
43fe83
     if (testSELinuxDeleteDisks(files, nfiles) < 0)
43fe83
-        goto cleanup;
43fe83
+        VIR_WARN("unable to fully clean up");
43fe83
 
43fe83
     virDomainDefFree(def);
43fe83
     for (i = 0; i < nfiles; i++) {
43fe83
@@ -334,6 +344,7 @@ mymain(void)
43fe83
     DO_TEST_LABELING("disks");
43fe83
     DO_TEST_LABELING("kernel");
43fe83
     DO_TEST_LABELING("chardev");
43fe83
+    DO_TEST_LABELING("nfs");
43fe83
 
43fe83
     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
43fe83
 }
43fe83
-- 
43fe83
1.8.3.2
43fe83