e836d5
From 3313343ba7803bff077af5d87df2260cdcd2d678 Mon Sep 17 00:00:00 2001
e836d5
From: Adrian Reber <areber@redhat.com>
e836d5
Date: Thu, 2 May 2019 13:41:46 +0000
e836d5
Subject: [PATCH 1/4] lsm: also dump and restore sockcreate
e836d5
e836d5
The file /proc/PID/attr/sockcreate is used by SELinux to label newly
e836d5
created sockets with the label available at sockcreate.
e836d5
e836d5
If it is NULL, the default label of the process will be used.
e836d5
e836d5
This reads out that file during checkpoint and restores the value during
e836d5
restore.
e836d5
e836d5
This value is irrelevant for existing sockets as they might have been
e836d5
created with another context. This is only to make sure that newly
e836d5
created sockets have the correct context.
e836d5
e836d5
Signed-off-by: Adrian Reber <areber@redhat.com>
e836d5
---
e836d5
 criu/cr-restore.c       | 36 ++++++++++++++++++++++++++++++++++++
e836d5
 criu/include/restorer.h |  2 ++
e836d5
 criu/lsm.c              | 32 ++++++++++++++++++++++++++++++++
e836d5
 criu/pie/restorer.c     | 15 ++++++++++-----
e836d5
 images/creds.proto      |  1 +
e836d5
 5 files changed, 81 insertions(+), 5 deletions(-)
e836d5
e836d5
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
e836d5
index 5fd22e9246..f254cbc0eb 100644
e836d5
--- a/criu/cr-restore.c
e836d5
+++ b/criu/cr-restore.c
e836d5
@@ -2997,6 +2997,8 @@ static void rst_reloc_creds(struct thread_restore_args *thread_args,
e836d5
 
e836d5
 	if (args->lsm_profile)
e836d5
 		args->lsm_profile = rst_mem_remap_ptr(args->mem_lsm_profile_pos, RM_PRIVATE);
e836d5
+	if (args->lsm_sockcreate)
e836d5
+		args->lsm_sockcreate = rst_mem_remap_ptr(args->mem_lsm_sockcreate_pos, RM_PRIVATE);
e836d5
 	if (args->groups)
e836d5
 		args->groups = rst_mem_remap_ptr(args->mem_groups_pos, RM_PRIVATE);
e836d5
 
e836d5
@@ -3062,6 +3064,40 @@ rst_prep_creds_args(CredsEntry *ce, unsigned long *prev_pos)
e836d5
 		args->mem_lsm_profile_pos = 0;
e836d5
 	}
e836d5
 
e836d5
+	if (ce->lsm_sockcreate) {
e836d5
+		char *rendered = NULL;
e836d5
+		char *profile;
e836d5
+
e836d5
+		profile = ce->lsm_sockcreate;
e836d5
+
e836d5
+		if (validate_lsm(profile) < 0)
e836d5
+			return ERR_PTR(-EINVAL);
e836d5
+
e836d5
+		if (profile && render_lsm_profile(profile, &rendered)) {
e836d5
+			return ERR_PTR(-EINVAL);
e836d5
+		}
e836d5
+		if (rendered) {
e836d5
+			size_t lsm_sockcreate_len;
e836d5
+			char *lsm_sockcreate;
e836d5
+
e836d5
+			args->mem_lsm_sockcreate_pos = rst_mem_align_cpos(RM_PRIVATE);
e836d5
+			lsm_sockcreate_len = strlen(rendered);
e836d5
+			lsm_sockcreate = rst_mem_alloc(lsm_sockcreate_len + 1, RM_PRIVATE);
e836d5
+			if (!lsm_sockcreate) {
e836d5
+				xfree(rendered);
e836d5
+				return ERR_PTR(-ENOMEM);
e836d5
+			}
e836d5
+
e836d5
+			args = rst_mem_remap_ptr(this_pos, RM_PRIVATE);
e836d5
+			args->lsm_sockcreate = lsm_sockcreate;
e836d5
+			strncpy(args->lsm_sockcreate, rendered, lsm_sockcreate_len);
e836d5
+			xfree(rendered);
e836d5
+		}
e836d5
+	} else {
e836d5
+		args->lsm_sockcreate = NULL;
e836d5
+		args->mem_lsm_sockcreate_pos = 0;
e836d5
+	}
e836d5
+
e836d5
 	/*
e836d5
 	 * Zap fields which we can't use.
e836d5
 	 */
e836d5
diff --git a/criu/include/restorer.h b/criu/include/restorer.h
e836d5
index 2884ce9e6d..b83e9130c5 100644
e836d5
--- a/criu/include/restorer.h
e836d5
+++ b/criu/include/restorer.h
e836d5
@@ -69,8 +69,10 @@ struct thread_creds_args {
e836d5
 	unsigned int			secbits;
e836d5
 	char				*lsm_profile;
e836d5
 	unsigned int			*groups;
e836d5
+	char				*lsm_sockcreate;
e836d5
 
e836d5
 	unsigned long			mem_lsm_profile_pos;
e836d5
+	unsigned long			mem_lsm_sockcreate_pos;
e836d5
 	unsigned long			mem_groups_pos;
e836d5
 
e836d5
 	unsigned long			mem_pos_next;
e836d5
diff --git a/criu/lsm.c b/criu/lsm.c
e836d5
index 849ec37cde..b0ef0c396c 100644
e836d5
--- a/criu/lsm.c
e836d5
+++ b/criu/lsm.c
e836d5
@@ -98,6 +98,32 @@ static int selinux_get_label(pid_t pid, char **output)
e836d5
 	freecon(ctx);
e836d5
 	return ret;
e836d5
 }
e836d5
+
e836d5
+/*
e836d5
+ * selinux_get_sockcreate_label reads /proc/PID/attr/sockcreate
e836d5
+ * to see if the PID has a special label specified for sockets.
e836d5
+ * Most of the time this will be empty and the process will use
e836d5
+ * the process context also for sockets.
e836d5
+ */
e836d5
+static int selinux_get_sockcreate_label(pid_t pid, char **output)
e836d5
+{
e836d5
+	FILE *f;
e836d5
+
e836d5
+	f = fopen_proc(pid, "attr/sockcreate");
e836d5
+	if (!f)
e836d5
+		return -1;
e836d5
+
e836d5
+	fscanf(f, "%ms", output);
e836d5
+	/*
e836d5
+	 * No need to check the result of fscanf(). If there is something
e836d5
+	 * in /proc/PID/attr/sockcreate it will be copied to *output. If
e836d5
+	 * there is nothing it will stay NULL. So whatever fscanf() does
e836d5
+	 * it should be correct.
e836d5
+	 */
e836d5
+
e836d5
+	fclose(f);
e836d5
+	return 0;
e836d5
+}
e836d5
 #endif
e836d5
 
e836d5
 void kerndat_lsm(void)
e836d5
@@ -132,6 +158,7 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce)
e836d5
 	int ret;
e836d5
 
e836d5
 	ce->lsm_profile = NULL;
e836d5
+	ce->lsm_sockcreate = NULL;
e836d5
 
e836d5
 	switch (kdat.lsm) {
e836d5
 	case LSMTYPE__NO_LSM:
e836d5
@@ -143,6 +170,9 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce)
e836d5
 #ifdef CONFIG_HAS_SELINUX
e836d5
 	case LSMTYPE__SELINUX:
e836d5
 		ret = selinux_get_label(pid, &ce->lsm_profile);
e836d5
+		if (ret)
e836d5
+			break;
e836d5
+		ret = selinux_get_sockcreate_label(pid, &ce->lsm_sockcreate);
e836d5
 		break;
e836d5
 #endif
e836d5
 	default:
e836d5
@@ -153,6 +183,8 @@ int collect_lsm_profile(pid_t pid, CredsEntry *ce)
e836d5
 
e836d5
 	if (ce->lsm_profile)
e836d5
 		pr_info("%d has lsm profile %s\n", pid, ce->lsm_profile);
e836d5
+	if (ce->lsm_sockcreate)
e836d5
+		pr_info("%d has lsm sockcreate label %s\n", pid, ce->lsm_sockcreate);
e836d5
 
e836d5
 	return ret;
e836d5
 }
e836d5
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
e836d5
index 6e18cc2606..4f42605a09 100644
e836d5
--- a/criu/pie/restorer.c
e836d5
+++ b/criu/pie/restorer.c
e836d5
@@ -149,7 +149,7 @@ static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
e836d5
 	sys_exit_group(1);
e836d5
 }
e836d5
 
e836d5
-static int lsm_set_label(char *label, int procfd)
e836d5
+static int lsm_set_label(char *label, char *type, int procfd)
e836d5
 {
e836d5
 	int ret = -1, len, lsmfd;
e836d5
 	char path[STD_LOG_SIMPLE_CHUNK];
e836d5
@@ -157,9 +157,9 @@ static int lsm_set_label(char *label, int procfd)
e836d5
 	if (!label)
e836d5
 		return 0;
e836d5
 
e836d5
-	pr_info("restoring lsm profile %s\n", label);
e836d5
+	pr_info("restoring lsm profile (%s) %s\n", type, label);
e836d5
 
e836d5
-	std_sprintf(path, "self/task/%ld/attr/current", sys_gettid());
e836d5
+	std_sprintf(path, "self/task/%ld/attr/%s", sys_gettid(), type);
e836d5
 
e836d5
 	lsmfd = sys_openat(procfd, path, O_WRONLY, 0);
e836d5
 	if (lsmfd < 0) {
e836d5
@@ -305,9 +305,14 @@ static int restore_creds(struct thread_creds_args *args, int procfd,
e836d5
 		 * SELinux and instead the process context is set before the
e836d5
 		 * threads are created.
e836d5
 		 */
e836d5
-		if (lsm_set_label(args->lsm_profile, procfd) < 0)
e836d5
+		if (lsm_set_label(args->lsm_profile, "current", procfd) < 0)
e836d5
 			return -1;
e836d5
 	}
e836d5
+
e836d5
+	/* Also set the sockcreate label for all threads */
e836d5
+	if (lsm_set_label(args->lsm_sockcreate, "sockcreate", procfd) < 0)
e836d5
+		return -1;
e836d5
+
e836d5
 	return 0;
e836d5
 }
e836d5
 
e836d5
@@ -1571,7 +1576,7 @@ long __export_restore_task(struct task_restore_args *args)
e836d5
 	if (args->lsm_type == LSMTYPE__SELINUX) {
e836d5
 		/* Only for SELinux */
e836d5
 		if (lsm_set_label(args->t->creds_args->lsm_profile,
e836d5
-				  args->proc_fd) < 0)
e836d5
+				  "current", args->proc_fd) < 0)
e836d5
 			goto core_restore_end;
e836d5
 	}
e836d5
 
e836d5
diff --git a/images/creds.proto b/images/creds.proto
e836d5
index 29fb8652eb..23b84c7e50 100644
e836d5
--- a/images/creds.proto
e836d5
+++ b/images/creds.proto
e836d5
@@ -20,4 +20,5 @@ message creds_entry {
e836d5
 	repeated uint32	groups	= 14;
e836d5
 
e836d5
 	optional string lsm_profile = 15;
e836d5
+	optional string lsm_sockcreate = 16;
e836d5
 }
e836d5
e836d5
From 495e6aa7ac51fcb36e6bc5f6c97f44cab7649b9c Mon Sep 17 00:00:00 2001
e836d5
From: Adrian Reber <areber@redhat.com>
e836d5
Date: Thu, 2 May 2019 13:47:29 +0000
e836d5
Subject: [PATCH 2/4] test: Verify that sockcreate does not change during
e836d5
 restore
e836d5
e836d5
This makes sure that sockcreate stays empty for selinux00 before and
e836d5
after checkpoint/restore.
e836d5
e836d5
Signed-off-by: Adrian Reber <areber@redhat.com>
e836d5
---
e836d5
 test/zdtm/static/selinux00.c | 34 ++++++++++++++++++++++++++++++++++
e836d5
 1 file changed, 34 insertions(+)
e836d5
e836d5
diff --git a/test/zdtm/static/selinux00.c b/test/zdtm/static/selinux00.c
e836d5
index dd9096a6fc..db8420eacb 100644
e836d5
--- a/test/zdtm/static/selinux00.c
e836d5
+++ b/test/zdtm/static/selinux00.c
e836d5
@@ -83,6 +83,31 @@ int checkprofile()
e836d5
 	return 0;
e836d5
 }
e836d5
 
e836d5
+int check_sockcreate()
e836d5
+{
e836d5
+	char *output = NULL;
e836d5
+	FILE *f = fopen("/proc/self/attr/sockcreate", "r");
e836d5
+	int ret = fscanf(f, "%ms", &output);
e836d5
+	fclose(f);
e836d5
+
e836d5
+	if (ret >= 1) {
e836d5
+		free(output);
e836d5
+		/* sockcreate should be empty, if fscanf found something
e836d5
+		 * it is wrong.*/
e836d5
+		fail("sockcreate should be empty\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	if (output) {
e836d5
+		free(output);
e836d5
+		/* Same here, output should still be NULL. */
e836d5
+		fail("sockcreate should be empty\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
 int main(int argc, char **argv)
e836d5
 {
e836d5
 	test_init(argc, argv);
e836d5
@@ -95,12 +120,21 @@ int main(int argc, char **argv)
e836d5
 		return 0;
e836d5
 	}
e836d5
 
e836d5
+	if (check_sockcreate())
e836d5
+		return -1;
e836d5
+
e836d5
 	if (setprofile())
e836d5
 		return -1;
e836d5
 
e836d5
+	if (check_sockcreate())
e836d5
+		return -1;
e836d5
+
e836d5
 	test_daemon();
e836d5
 	test_waitsig();
e836d5
 
e836d5
+	if (check_sockcreate())
e836d5
+		return -1;
e836d5
+
e836d5
 	if (checkprofile() == 0)
e836d5
 		pass();
e836d5
 
e836d5
e836d5
From fe52cf66b38a261846ff40fc425085724b2acc15 Mon Sep 17 00:00:00 2001
e836d5
From: Adrian Reber <areber@redhat.com>
e836d5
Date: Mon, 29 Apr 2019 15:21:59 +0200
e836d5
Subject: [PATCH 3/4] sockets: dump and restore xattr security labels
e836d5
e836d5
Restoring a SELinux process also requires to correctly label sockets.
e836d5
e836d5
During checkpointing fgetxattr() is used to retrieve the
e836d5
"security.selinux" xattr and during restore setsockcreatecon() is used
e836d5
before a socket is created.
e836d5
e836d5
Previous commits are already restoring the sockcreate SELinux setting if
e836d5
set by the process.
e836d5
e836d5
Signed-off-by: Adrian Reber <areber@redhat.com>
e836d5
---
e836d5
 criu/include/lsm.h  | 18 +++++++++++++++
e836d5
 criu/lsm.c          | 56 +++++++++++++++++++++++++++++++++++++++++++++
e836d5
 criu/sk-inet.c      | 12 ++++++++++
e836d5
 criu/sockets.c      |  4 ++++
e836d5
 images/fdinfo.proto |  1 +
e836d5
 5 files changed, 91 insertions(+)
e836d5
e836d5
diff --git a/criu/include/lsm.h b/criu/include/lsm.h
e836d5
index b4fce13039..3b82712829 100644
e836d5
--- a/criu/include/lsm.h
e836d5
+++ b/criu/include/lsm.h
e836d5
@@ -3,6 +3,7 @@
e836d5
 
e836d5
 #include "images/inventory.pb-c.h"
e836d5
 #include "images/creds.pb-c.h"
e836d5
+#include "images/fdinfo.pb-c.h"
e836d5
 
e836d5
 #define AA_SECURITYFS_PATH "/sys/kernel/security/apparmor"
e836d5
 
e836d5
@@ -34,4 +35,21 @@ int validate_lsm(char *profile);
e836d5
 int render_lsm_profile(char *profile, char **val);
e836d5
 
e836d5
 extern int lsm_check_opts(void);
e836d5
+
e836d5
+#ifdef CONFIG_HAS_SELINUX
e836d5
+int dump_xattr_security_selinux(int fd, FdinfoEntry *e);
e836d5
+int run_setsockcreatecon(FdinfoEntry *e);
e836d5
+int reset_setsockcreatecon();
e836d5
+#else
e836d5
+static inline int dump_xattr_security_selinux(int fd, FdinfoEntry *e) {
e836d5
+	return 0;
e836d5
+}
e836d5
+static inline int run_setsockcreatecon(FdinfoEntry *e) {
e836d5
+	return 0;
e836d5
+}
e836d5
+static inline int reset_setsockcreatecon() {
e836d5
+	return 0;
e836d5
+}
e836d5
+#endif
e836d5
+
e836d5
 #endif /* __CR_LSM_H__ */
e836d5
diff --git a/criu/lsm.c b/criu/lsm.c
e836d5
index b0ef0c396c..ef6ba112b3 100644
e836d5
--- a/criu/lsm.c
e836d5
+++ b/criu/lsm.c
e836d5
@@ -3,6 +3,7 @@
e836d5
 #include <stdlib.h>
e836d5
 #include <fcntl.h>
e836d5
 #include <sys/types.h>
e836d5
+#include <sys/xattr.h>
e836d5
 #include <unistd.h>
e836d5
 
e836d5
 #include "common/config.h"
e836d5
@@ -11,10 +12,12 @@
e836d5
 #include "util.h"
e836d5
 #include "cr_options.h"
e836d5
 #include "lsm.h"
e836d5
+#include "fdstore.h"
e836d5
 
e836d5
 #include "protobuf.h"
e836d5
 #include "images/inventory.pb-c.h"
e836d5
 #include "images/creds.pb-c.h"
e836d5
+#include "images/fdinfo.pb-c.h"
e836d5
 
e836d5
 #ifdef CONFIG_HAS_SELINUX
e836d5
 #include <selinux/selinux.h>
e836d5
@@ -124,6 +127,59 @@ static int selinux_get_sockcreate_label(pid_t pid, char **output)
e836d5
 	fclose(f);
e836d5
 	return 0;
e836d5
 }
e836d5
+
e836d5
+int reset_setsockcreatecon()
e836d5
+{
e836d5
+	return setsockcreatecon_raw(NULL);
e836d5
+}
e836d5
+
e836d5
+int run_setsockcreatecon(FdinfoEntry *e)
e836d5
+{
e836d5
+	char *ctx = NULL;
e836d5
+
e836d5
+	/* Currently this only works for SELinux. */
e836d5
+	if (kdat.lsm != LSMTYPE__SELINUX)
e836d5
+		return 0;
e836d5
+
e836d5
+	ctx = e->xattr_security_selinux;
e836d5
+	/* Writing to the FD using fsetxattr() did not work for some reason. */
e836d5
+	return setsockcreatecon_raw(ctx);
e836d5
+}
e836d5
+
e836d5
+int dump_xattr_security_selinux(int fd, FdinfoEntry *e)
e836d5
+{
e836d5
+	char *ctx = NULL;
e836d5
+	int len;
e836d5
+	int ret;
e836d5
+
e836d5
+	/* Currently this only works for SELinux. */
e836d5
+	if (kdat.lsm != LSMTYPE__SELINUX)
e836d5
+		return 0;
e836d5
+
e836d5
+	/* Get the size of the xattr. */
e836d5
+	len = fgetxattr(fd, "security.selinux", ctx, 0);
e836d5
+	if (len == -1) {
e836d5
+		pr_err("Reading xattr %s to FD %d failed\n", ctx, fd);
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	ctx = xmalloc(len);
e836d5
+	if (!ctx) {
e836d5
+		pr_err("xmalloc to read xattr for FD %d failed\n", fd);
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	ret = fgetxattr(fd, "security.selinux", ctx, len);
e836d5
+	if (len != ret) {
e836d5
+		pr_err("Reading xattr %s to FD %d failed\n", ctx, fd);
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	e->xattr_security_selinux = ctx;
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
 #endif
e836d5
 
e836d5
 void kerndat_lsm(void)
e836d5
diff --git a/criu/sk-inet.c b/criu/sk-inet.c
e836d5
index 60ee4c3155..ca5c9bf2cd 100644
e836d5
--- a/criu/sk-inet.c
e836d5
+++ b/criu/sk-inet.c
e836d5
@@ -23,6 +23,9 @@
e836d5
 #include "files.h"
e836d5
 #include "image.h"
e836d5
 #include "log.h"
e836d5
+#include "lsm.h"
e836d5
+#include "kerndat.h"
e836d5
+#include "pstree.h"
e836d5
 #include "rst-malloc.h"
e836d5
 #include "sockets.h"
e836d5
 #include "sk-inet.h"
e836d5
@@ -30,6 +33,8 @@
e836d5
 #include "util.h"
e836d5
 #include "namespaces.h"
e836d5
 
e836d5
+#include "images/inventory.pb-c.h"
e836d5
+
e836d5
 #undef  LOG_PREFIX
e836d5
 #define LOG_PREFIX "inet: "
e836d5
 
e836d5
@@ -804,12 +809,18 @@ static int open_inet_sk(struct file_desc *d, int *new_fd)
e836d5
 	if (set_netns(ie->ns_id))
e836d5
 		return -1;
e836d5
 
e836d5
+	if (run_setsockcreatecon(fle->fe))
e836d5
+		return -1;
e836d5
+
e836d5
 	sk = socket(ie->family, ie->type, ie->proto);
e836d5
 	if (sk < 0) {
e836d5
 		pr_perror("Can't create inet socket");
e836d5
 		return -1;
e836d5
 	}
e836d5
 
e836d5
+	if (reset_setsockcreatecon())
e836d5
+		return -1;
e836d5
+
e836d5
 	if (ie->v6only) {
e836d5
 		if (restore_opt(sk, SOL_IPV6, IPV6_V6ONLY, &yes) == -1)
e836d5
 			goto err;
e836d5
@@ -895,6 +906,7 @@ static int open_inet_sk(struct file_desc *d, int *new_fd)
e836d5
 	}
e836d5
 
e836d5
 	*new_fd = sk;
e836d5
+
e836d5
 	return 1;
e836d5
 err:
e836d5
 	close(sk);
e836d5
diff --git a/criu/sockets.c b/criu/sockets.c
e836d5
index 30072ac737..7f7453ca1d 100644
e836d5
--- a/criu/sockets.c
e836d5
+++ b/criu/sockets.c
e836d5
@@ -22,6 +22,7 @@
e836d5
 #include "util-pie.h"
e836d5
 #include "sk-packet.h"
e836d5
 #include "namespaces.h"
e836d5
+#include "lsm.h"
e836d5
 #include "net.h"
e836d5
 #include "xmalloc.h"
e836d5
 #include "fs-magic.h"
e836d5
@@ -663,6 +664,9 @@ int dump_socket(struct fd_parms *p, int lfd, FdinfoEntry *e)
e836d5
 	int family;
e836d5
 	const struct fdtype_ops *ops;
e836d5
 
e836d5
+	if (dump_xattr_security_selinux(lfd, e))
e836d5
+		return -1;
e836d5
+
e836d5
 	if (dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &family))
e836d5
 		return -1;
e836d5
 
e836d5
diff --git a/images/fdinfo.proto b/images/fdinfo.proto
e836d5
index ed82ceffe7..77e375aa94 100644
e836d5
--- a/images/fdinfo.proto
e836d5
+++ b/images/fdinfo.proto
e836d5
@@ -47,6 +47,7 @@ message fdinfo_entry {
e836d5
 	required uint32		flags	= 2;
e836d5
 	required fd_types	type	= 3;
e836d5
 	required uint32		fd	= 4;
e836d5
+	optional string		xattr_security_selinux = 5;
e836d5
 }
e836d5
 
e836d5
 message file_entry {
e836d5
e836d5
From ba42d30fad82f17a66617a33f03d3da05cc73bfe Mon Sep 17 00:00:00 2001
e836d5
From: Adrian Reber <areber@redhat.com>
e836d5
Date: Tue, 30 Apr 2019 09:47:32 +0000
e836d5
Subject: [PATCH 4/4] selinux: add socket label test
e836d5
e836d5
This adds two more SELinux test to verfy that checkpointing and
e836d5
restoring SELinux socket labels works correctly, if the process uses
e836d5
setsockcreatecon() or if the process leaves the default context for
e836d5
newly created sockets.
e836d5
e836d5
Signed-off-by: Adrian Reber <areber@redhat.com>
e836d5
---
e836d5
 test/zdtm/static/Makefile            |   3 +
e836d5
 test/zdtm/static/selinux01.c         | 200 +++++++++++++++++++++++++++
e836d5
 test/zdtm/static/selinux01.checkskip |   1 +
e836d5
 test/zdtm/static/selinux01.desc      |   1 +
e836d5
 test/zdtm/static/selinux01.hook      |   1 +
e836d5
 test/zdtm/static/selinux02.c         |   1 +
e836d5
 test/zdtm/static/selinux02.checkskip |   1 +
e836d5
 test/zdtm/static/selinux02.desc      |   1 +
e836d5
 test/zdtm/static/selinux02.hook      |   1 +
e836d5
 9 files changed, 210 insertions(+)
e836d5
 create mode 100644 test/zdtm/static/selinux01.c
e836d5
 create mode 120000 test/zdtm/static/selinux01.checkskip
e836d5
 create mode 120000 test/zdtm/static/selinux01.desc
e836d5
 create mode 120000 test/zdtm/static/selinux01.hook
e836d5
 create mode 120000 test/zdtm/static/selinux02.c
e836d5
 create mode 120000 test/zdtm/static/selinux02.checkskip
e836d5
 create mode 120000 test/zdtm/static/selinux02.desc
e836d5
 create mode 120000 test/zdtm/static/selinux02.hook
e836d5
e836d5
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
e836d5
index 8e3f39276a..1ffaa90394 100644
e836d5
--- a/test/zdtm/static/Makefile
e836d5
+++ b/test/zdtm/static/Makefile
e836d5
@@ -211,6 +211,8 @@ TST_NOFILE	:=				\
e836d5
 		thp_disable			\
e836d5
 		pid_file			\
e836d5
 		selinux00			\
e836d5
+		selinux01			\
e836d5
+		selinux02			\
e836d5
 #		jobctl00			\
e836d5
 
e836d5
 ifneq ($(SRCARCH),arm)
e836d5
@@ -513,6 +515,7 @@ unlink_fstat041:		CFLAGS += -DUNLINK_FSTAT041 -DUNLINK_FSTAT04
e836d5
 ghost_holes01:		CFLAGS += -DTAIL_HOLE
e836d5
 ghost_holes02:		CFLAGS += -DHEAD_HOLE
e836d5
 sk-freebind-false:	CFLAGS += -DZDTM_FREEBIND_FALSE
e836d5
+selinux02:		CFLAGS += -DUSING_SOCKCREATE
e836d5
 stopped01:		CFLAGS += -DZDTM_STOPPED_KILL
e836d5
 stopped02:		CFLAGS += -DZDTM_STOPPED_TKILL
e836d5
 stopped12:		CFLAGS += -DZDTM_STOPPED_KILL -DZDTM_STOPPED_TKILL
e836d5
diff --git a/test/zdtm/static/selinux01.c b/test/zdtm/static/selinux01.c
e836d5
new file mode 100644
e836d5
index 0000000000..9966455c47
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux01.c
e836d5
@@ -0,0 +1,200 @@
e836d5
+#include <unistd.h>
e836d5
+#include <stdio.h>
e836d5
+#include <stdlib.h>
e836d5
+#include <string.h>
e836d5
+#include <fcntl.h>
e836d5
+#include <sys/stat.h>
e836d5
+#include <sys/types.h>
e836d5
+#include <sys/mount.h>
e836d5
+#include <sys/socket.h>
e836d5
+#include <sys/xattr.h>
e836d5
+#include <linux/limits.h>
e836d5
+#include <signal.h>
e836d5
+#include "zdtmtst.h"
e836d5
+
e836d5
+/* Enabling the right policy happens in selinux00.hook and selinx00.checkskip */
e836d5
+
e836d5
+const char *test_doc	= "Check that a SELinux socket context is restored";
e836d5
+const char *test_author	= "Adrian Reber <areber@redhat.com>";
e836d5
+
e836d5
+/* This is all based on Tycho's apparmor code */
e836d5
+
e836d5
+#define CONTEXT "unconfined_u:unconfined_r:unconfined_dbusd_t:s0"
e836d5
+
e836d5
+/*
e836d5
+ * This is used to store the state of SELinux. For this test
e836d5
+ * SELinux is switched to permissive mode and later the previous
e836d5
+ * SELinux state is restored.
e836d5
+ */
e836d5
+char state;
e836d5
+
e836d5
+int check_for_selinux()
e836d5
+{
e836d5
+	if (access("/sys/fs/selinux", F_OK) == 0)
e836d5
+		return 0;
e836d5
+	return 1;
e836d5
+}
e836d5
+
e836d5
+int setprofile()
e836d5
+{
e836d5
+	int fd, len;
e836d5
+
e836d5
+	fd = open("/proc/self/attr/current", O_WRONLY);
e836d5
+	if (fd < 0) {
e836d5
+		fail("Could not open /proc/self/attr/current\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	len = write(fd, CONTEXT, strlen(CONTEXT));
e836d5
+	close(fd);
e836d5
+
e836d5
+	if (len < 0) {
e836d5
+		fail("Could not write context\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
+int set_sockcreate()
e836d5
+{
e836d5
+	int fd, len;
e836d5
+
e836d5
+	fd = open("/proc/self/attr/sockcreate", O_WRONLY);
e836d5
+	if (fd < 0) {
e836d5
+		fail("Could not open /proc/self/attr/sockcreate\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	len = write(fd, CONTEXT, strlen(CONTEXT));
e836d5
+	close(fd);
e836d5
+
e836d5
+	if (len < 0) {
e836d5
+		fail("Could not write context\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
+int check_sockcreate()
e836d5
+{
e836d5
+	int fd;
e836d5
+	char context[1024];
e836d5
+	int len;
e836d5
+
e836d5
+
e836d5
+	fd = open("/proc/self/attr/sockcreate", O_RDONLY);
e836d5
+	if (fd < 0) {
e836d5
+		fail("Could not open /proc/self/attr/sockcreate\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	len = read(fd, context, strlen(CONTEXT));
e836d5
+	close(fd);
e836d5
+	if (len != strlen(CONTEXT)) {
e836d5
+		fail("SELinux context has unexpected length %d, expected %zd\n",
e836d5
+			len, strlen(CONTEXT));
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	if (strncmp(context, CONTEXT, strlen(CONTEXT)) != 0) {
e836d5
+		fail("Wrong SELinux context %s expected %s\n", context, CONTEXT);
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
+int check_sockcreate_empty()
e836d5
+{
e836d5
+	char *output = NULL;
e836d5
+	FILE *f = fopen("/proc/self/attr/sockcreate", "r");
e836d5
+	int ret = fscanf(f, "%ms", &output);
e836d5
+	fclose(f);
e836d5
+
e836d5
+	if (ret >= 1) {
e836d5
+		free(output);
e836d5
+		/* sockcreate should be empty, if fscanf found something
e836d5
+		 * it is wrong.*/
e836d5
+		fail("sockcreate should be empty\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	if (output) {
e836d5
+		free(output);
e836d5
+		/* Same here, output should still be NULL. */
e836d5
+		fail("sockcreate should be empty\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
+
e836d5
+int main(int argc, char **argv)
e836d5
+{
e836d5
+	char ctx[1024];
e836d5
+	test_init(argc, argv);
e836d5
+
e836d5
+	if (check_for_selinux()) {
e836d5
+		skip("SELinux not found on this system.");
e836d5
+		test_daemon();
e836d5
+		test_waitsig();
e836d5
+		pass();
e836d5
+		return 0;
e836d5
+	}
e836d5
+
e836d5
+#ifdef USING_SOCKCREATE
e836d5
+	if (set_sockcreate())
e836d5
+		return -1;
e836d5
+#else
e836d5
+	if (check_sockcreate_empty())
e836d5
+		return -1;
e836d5
+
e836d5
+	if (setprofile())
e836d5
+		return -1;
e836d5
+
e836d5
+	if (check_sockcreate_empty())
e836d5
+		return -1;
e836d5
+#endif
e836d5
+
e836d5
+	/* Open our test socket */
e836d5
+	int sk = socket(AF_INET, SOCK_STREAM, 0);
e836d5
+	memset(ctx, 0, 1024);
e836d5
+	/* Read out the socket label */
e836d5
+	if (fgetxattr(sk, "security.selinux", ctx, 1024) == -1) {
e836d5
+		fail("Reading xattr 'security.selinux' failed.\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+	if (strncmp(ctx, CONTEXT, strlen(CONTEXT)) != 0) {
e836d5
+		fail("Wrong SELinux context %s expected %s\n", ctx, CONTEXT);
e836d5
+		return -1;
e836d5
+	}
e836d5
+	memset(ctx, 0, 1024);
e836d5
+
e836d5
+	test_daemon();
e836d5
+	test_waitsig();
e836d5
+
e836d5
+	/* Read out the socket label again */
e836d5
+
e836d5
+	if (fgetxattr(sk, "security.selinux", ctx, 1024) == -1) {
e836d5
+		fail("Reading xattr 'security.selinux' failed.\n");
e836d5
+		return -1;
e836d5
+	}
e836d5
+	if (strncmp(ctx, CONTEXT, strlen(CONTEXT)) != 0) {
e836d5
+		fail("Wrong SELinux context %s expected %s\n", ctx, CONTEXT);
e836d5
+		return -1;
e836d5
+	}
e836d5
+
e836d5
+#ifdef USING_SOCKCREATE
e836d5
+	if (check_sockcreate())
e836d5
+		return -1;
e836d5
+#else
e836d5
+	if (check_sockcreate_empty())
e836d5
+		return -1;
e836d5
+#endif
e836d5
+
e836d5
+	pass();
e836d5
+
e836d5
+	return 0;
e836d5
+}
e836d5
diff --git a/test/zdtm/static/selinux01.checkskip b/test/zdtm/static/selinux01.checkskip
e836d5
new file mode 120000
e836d5
index 0000000000..e8a172479e
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux01.checkskip
e836d5
@@ -0,0 +1 @@
e836d5
+selinux00.checkskip
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux01.desc b/test/zdtm/static/selinux01.desc
e836d5
new file mode 120000
e836d5
index 0000000000..2d2961a764
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux01.desc
e836d5
@@ -0,0 +1 @@
e836d5
+selinux00.desc
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux01.hook b/test/zdtm/static/selinux01.hook
e836d5
new file mode 120000
e836d5
index 0000000000..dd7ed6bb33
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux01.hook
e836d5
@@ -0,0 +1 @@
e836d5
+selinux00.hook
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux02.c b/test/zdtm/static/selinux02.c
e836d5
new file mode 120000
e836d5
index 0000000000..5702677858
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux02.c
e836d5
@@ -0,0 +1 @@
e836d5
+selinux01.c
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux02.checkskip b/test/zdtm/static/selinux02.checkskip
e836d5
new file mode 120000
e836d5
index 0000000000..2696e6e3de
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux02.checkskip
e836d5
@@ -0,0 +1 @@
e836d5
+selinux01.checkskip
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux02.desc b/test/zdtm/static/selinux02.desc
e836d5
new file mode 120000
e836d5
index 0000000000..9c6802c4da
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux02.desc
e836d5
@@ -0,0 +1 @@
e836d5
+selinux01.desc
e836d5
\ No newline at end of file
e836d5
diff --git a/test/zdtm/static/selinux02.hook b/test/zdtm/static/selinux02.hook
e836d5
new file mode 120000
e836d5
index 0000000000..e3ea0a6c80
e836d5
--- /dev/null
e836d5
+++ b/test/zdtm/static/selinux02.hook
e836d5
@@ -0,0 +1 @@
e836d5
+selinux01.hook
e836d5
\ No newline at end of file