[PATCH 2/4] qemusecuritytest: Test SELinux too

2020-11-03 Thread Michal Privoznik
The qemusecuritytest checks for random domain XMLs from
qemuxml2argvdata/ whether set+restore seclabels leaves something
behind. It can be an XATTR that we forgot to remove or a file
that the owner was not restored on. But so far only DAC driver is
checked. Implement missing pieces and enable SELinux testing too.

This is done by mocking some libselinux APIs and following the
same logic used for DAC - everything is implemented in memory,
there is new hash table introduced that holds SELinux labels for
paths that were setfilecon_raw()-ed and in the end the hash table
is checked for entries that don't have the default SELinux label
(i.e. were not restored).

Signed-off-by: Michal Privoznik 
---
 tests/qemusecuritydata/virtual_domain_context |   2 +
 tests/qemusecuritydata/virtual_image_context  |   2 +
 tests/qemusecuritymock.c  | 195 +-
 tests/qemusecuritytest.c  |  51 -
 4 files changed, 240 insertions(+), 10 deletions(-)
 create mode 100644 tests/qemusecuritydata/virtual_domain_context
 create mode 100644 tests/qemusecuritydata/virtual_image_context

diff --git a/tests/qemusecuritydata/virtual_domain_context 
b/tests/qemusecuritydata/virtual_domain_context
new file mode 100644
index 00..150f281d10
--- /dev/null
+++ b/tests/qemusecuritydata/virtual_domain_context
@@ -0,0 +1,2 @@
+system_u:system_r:svirt_t:s0
+system_u:system_r:svirt_tcg_t:s0
diff --git a/tests/qemusecuritydata/virtual_image_context 
b/tests/qemusecuritydata/virtual_image_context
new file mode 100644
index 00..8ab1e27ea2
--- /dev/null
+++ b/tests/qemusecuritydata/virtual_image_context
@@ -0,0 +1,2 @@
+system_u:object_r:svirt_image_t:s0
+system_u:object_r:virt_content_t:s0
diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c
index 543a5f7f3f..db03572dbe 100644
--- a/tests/qemusecuritymock.c
+++ b/tests/qemusecuritymock.c
@@ -24,6 +24,11 @@
 #include 
 #include 
 
+#ifdef WITH_SELINUX
+# include 
+# include 
+#endif
+
 #include "virmock.h"
 #include "virfile.h"
 #include "virthread.h"
@@ -41,7 +46,8 @@
  * work as expected. Therefore there is a lot we have to mock
  * (chown, stat, XATTR APIs, etc.). Since the test won't run as
  * root chown() would fail, therefore we have to keep everything
- * in memory. By default, all files are owned by 1:2.
+ * in memory. By default, all files are owned by 1:2 and have a
+ * SELinux label.
  * By the way, since there are some cases where real stat needs
  * to be called, the mocked functions are effective only if
  * $ENVVAR is set.
@@ -49,11 +55,16 @@
 
 #define DEFAULT_UID 1
 #define DEFAULT_GID 2
+#define DEFAULT_SELINUX_LABEL "system_u:object_r:default_t:s0"
 
 
 static int (*real_chown)(const char *path, uid_t uid, gid_t gid);
 static int (*real_open)(const char *path, int flags, ...);
 static int (*real_close)(int fd);
+#ifdef WITH_SELINUX
+static int (*real_setfilecon_raw)(const char *path, const char *context);
+static int (*real_getfilecon_raw)(const char *path, char **context);
+#endif
 
 
 /* Global mutex to avoid races */
@@ -71,6 +82,10 @@ virHashTablePtr xattr_paths = NULL;
  * the lower half is UID and the higher is GID. */
 virHashTablePtr chown_paths = NULL;
 
+/* The SELinux label is stored in a hash table. For simplicity,
+ * the path os the key and the value is the label. */
+virHashTablePtr selinux_paths = NULL;
+
 
 static void
 init_hash(void)
@@ -94,6 +109,11 @@ init_hash(void)
 fprintf(stderr, "Unable to create hash table for chowned paths\n");
 abort();
 }
+
+if (!(selinux_paths = virHashNew(g_free))) {
+fprintf(stderr, "Unable to create hash table for selinux labels\n");
+abort();
+}
 }
 
 
@@ -106,6 +126,10 @@ init_syms(void)
 VIR_MOCK_REAL_INIT(chown);
 VIR_MOCK_REAL_INIT(open);
 VIR_MOCK_REAL_INIT(close);
+#ifdef WITH_SELINUX
+VIR_MOCK_REAL_INIT(setfilecon_raw);
+VIR_MOCK_REAL_INIT(getfilecon_raw);
+#endif
 
 /* Intentionally not calling init_hash() here */
 }
@@ -376,9 +400,30 @@ typedef struct _checkOwnerData checkOwnerData;
 struct _checkOwnerData {
 const char **paths;
 bool chown_fail;
+bool selinux_fail;
 };
 
 
+static int
+checkSELinux(void *payload,
+ const char *name,
+ void *opaque)
+{
+checkOwnerData *data = opaque;
+char *label = payload;
+
+if (STRNEQ(label, DEFAULT_SELINUX_LABEL) &&
+!virStringListHasString(data->paths, name)) {
+fprintf(stderr,
+"Path %s wasn't restored back to its original SELinux label\n",
+name);
+data->selinux_fail = true;
+}
+
+return 0;
+}
+
+
 static int
 checkOwner(void *payload,
const char *name,
@@ -431,7 +476,7 @@ printXATTR(void *payload,
 int checkPaths(const char **paths)
 {
 int ret = -1;
-checkOwnerData data = { .paths = paths, .chown_fail = false };
+checkOwnerData data = { .paths = paths, .chown_fail = false, .selinux_fail 
= false };
  

Re: [PATCH 2/4] qemusecuritytest: Test SELinux too

2020-11-04 Thread Andrea Bolognani
On Tue, 2020-11-03 at 14:13 +0100, Michal Privoznik wrote:
> +++ b/tests/qemusecuritymock.c
> @@ -71,6 +82,10 @@ virHashTablePtr xattr_paths = NULL;
>   * the lower half is UID and the higher is GID. */
>  virHashTablePtr chown_paths = NULL;
>  
> +/* The SELinux label is stored in a hash table. For simplicity,
> + * the path os the key and the value is the label. */

s/path os/path is/

-- 
Andrea Bolognani / Red Hat / Virtualization