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