[lxc-devel] [lxc/master] lsm: simplifcations

brauner on Github lxc-bot at linuxcontainers.org
Mon Jan 22 11:16:56 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180122/fc9b1fa7/attachment.bin>
-------------- next part --------------
From e6e899749af3a28323fe12499dbed1faef4cacca Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 22 Jan 2018 10:48:56 +0100
Subject: [PATCH 1/5] lsm: non-functional changes

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/lsm/apparmor.c |  2 +-
 src/lxc/lsm/lsm.c      |  2 +-
 src/lxc/lsm/lsm.h      | 53 ++++++++++++++++++++++++++++++++++++--------------
 src/lxc/lsm/nop.c      |  2 +-
 src/lxc/lsm/selinux.c  |  2 +-
 5 files changed, 42 insertions(+), 19 deletions(-)

diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c
index 2faa9a20d..0021001ac 100644
--- a/src/lxc/lsm/apparmor.c
+++ b/src/lxc/lsm/apparmor.c
@@ -172,7 +172,7 @@ static bool aa_needs_transition(char *curlabel)
  * Notes: This relies on /proc being available.
  */
 static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf,
-				      int use_default, int on_exec)
+				      bool use_default, bool on_exec)
 {
 	const char *label = inlabel ? inlabel : conf->lsm_aa_profile;
 	char *curlabel;
diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
index 79f837fc6..75f20f13b 100644
--- a/src/lxc/lsm/lsm.c
+++ b/src/lxc/lsm/lsm.c
@@ -86,7 +86,7 @@ char *lsm_process_label_get(pid_t pid)
 }
 
 int lsm_process_label_set(const char *label, struct lxc_conf *conf,
-		int use_default, int on_exec)
+			  bool use_default, bool on_exec)
 {
 	if (!drv) {
 		ERROR("LSM driver not inited");
diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h
index b915e8ddd..3b08b3be7 100644
--- a/src/lxc/lsm/lsm.h
+++ b/src/lxc/lsm/lsm.h
@@ -28,29 +28,52 @@ struct lxc_conf;
 
 #include <sys/types.h>
 
+#include "../utils.h"
+
+#define LXC_LSMATTRLEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
+
 struct lsm_drv {
 	const char *name;
 
-	int   (*enabled)(void);
+	int (*enabled)(void);
 	char *(*process_label_get)(pid_t pid);
-	int   (*process_label_set)(const char *label, struct lxc_conf *conf,
-				   int use_default, int on_exec);
+	int (*process_label_set)(const char *label, struct lxc_conf *conf,
+				 bool use_default, bool on_exec);
 };
 
 #if HAVE_APPARMOR || HAVE_SELINUX
-void        lsm_init(void);
-int         lsm_enabled(void);
-const char *lsm_name(void);
-char       *lsm_process_label_get(pid_t pid);
-int         lsm_process_label_set(const char *label, struct lxc_conf *conf,
-		int use_default, int on_exec);
+extern void lsm_init(void);
+extern int lsm_enabled(void);
+extern const char *lsm_name(void);
+extern char *lsm_process_label_get(pid_t pid);
+extern int lsm_process_label_set(const char *label, struct lxc_conf *conf,
+				 bool use_default, bool on_exec);
 #else
-static inline void        lsm_init(void) { }
-static inline int         lsm_enabled(void) { return 0; }
-static inline const char *lsm_name(void) { return "none"; }
-static inline char       *lsm_process_label_get(pid_t pid) { return NULL; }
-static inline int         lsm_process_label_set(const char *label,
-		struct lxc_conf *conf, int use_default, int on_exec) { return 0; }
+static inline void lsm_init(void)
+{
+	return;
+}
+
+static inline int lsm_enabled(void) {
+	return 0;
+}
+
+static inline const char *lsm_name(void)
+{
+	return "none";
+}
+
+static inline char *lsm_process_label_get(pid_t pid)
+{
+	return NULL;
+}
+
+static inline int lsm_process_label_set(const char *label,
+					struct lxc_conf *conf, bool use_default,
+					bool on_exec)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c
index c13d8f528..7bb8121b8 100644
--- a/src/lxc/lsm/nop.c
+++ b/src/lxc/lsm/nop.c
@@ -30,7 +30,7 @@ static char *nop_process_label_get(pid_t pid)
 }
 
 static int nop_process_label_set(const char *label, struct lxc_conf *conf,
-		int use_default, int on_exec)
+				 bool use_default, bool on_exec)
 {
 	return 0;
 }
diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c
index 46554d84c..857fe29a8 100644
--- a/src/lxc/lsm/selinux.c
+++ b/src/lxc/lsm/selinux.c
@@ -72,7 +72,7 @@ static char *selinux_process_label_get(pid_t pid)
  * Notes: This relies on /proc being available.
  */
 static int selinux_process_label_set(const char *inlabel, struct lxc_conf *conf,
-				     int use_default, int on_exec)
+				     bool use_default, bool on_exec)
 {
 	const char *label = inlabel ? inlabel : conf->lsm_se_context;
 	if (!label) {

From 47ce2cb727eb0e306ab652910cf0b3fdd5cf7e24 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 22 Jan 2018 10:54:38 +0100
Subject: [PATCH 2/5] lsm: add lsm_process_label_fd_get()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/attach.c  | 45 ++++-----------------------------------------
 src/lxc/lsm/lsm.c | 36 ++++++++++++++++++++++++++++++++++++
 src/lxc/lsm/lsm.h |  6 ++++++
 3 files changed, 46 insertions(+), 41 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 34bdf9145..369d88183 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -88,44 +88,6 @@
 
 lxc_log_define(lxc_attach, lxc);
 
-/* /proc/pid-to-str/current\0 = (5 + 21 + 7 + 1) */
-#define __LSMATTRLEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
-static int lsm_open(pid_t pid, int on_exec)
-{
-	const char *name;
-	char path[__LSMATTRLEN];
-	int ret = -1;
-	int labelfd = -1;
-
-	name = lsm_name();
-
-	if (strcmp(name, "nop") == 0)
-		return 0;
-
-	if (strcmp(name, "none") == 0)
-		return 0;
-
-	/* We don't support on-exec with AppArmor */
-	if (strcmp(name, "AppArmor") == 0)
-		on_exec = 0;
-
-	if (on_exec)
-		ret = snprintf(path, __LSMATTRLEN, "/proc/%d/attr/exec", pid);
-	else
-		ret = snprintf(path, __LSMATTRLEN, "/proc/%d/attr/current", pid);
-	if (ret < 0 || ret >= __LSMATTRLEN)
-		return -1;
-
-	labelfd = open(path, O_RDWR);
-	if (labelfd < 0) {
-		SYSERROR("%s - Unable to open file descriptor to set LSM label",
-			 strerror(errno));
-		return -1;
-	}
-
-	return labelfd;
-}
-
 static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
 {
 	int fret = -1;
@@ -1396,11 +1358,12 @@ int lxc_attach(const char *name, const char *lxcpath,
 		if ((options->namespaces & CLONE_NEWNS) &&
 		    (options->attach_flags & LXC_ATTACH_LSM) &&
 		    init_ctx->lsm_label) {
-			int labelfd, on_exec;
 			int ret = -1;
+			int labelfd;
+			bool on_exec;
 
-			on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
-			labelfd = lsm_open(attached_pid, on_exec);
+			on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
+			labelfd = lsm_process_label_fd_get(attached_pid, on_exec);
 			if (labelfd < 0)
 				goto close_mainloop;
 			TRACE("Opened LSM label file descriptor %d", labelfd);
diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
index 75f20f13b..98bf083bb 100644
--- a/src/lxc/lsm/lsm.c
+++ b/src/lxc/lsm/lsm.c
@@ -85,6 +85,42 @@ char *lsm_process_label_get(pid_t pid)
 	return drv->process_label_get(pid);
 }
 
+int lsm_process_label_fd_get(pid_t pid, bool on_exec)
+{
+	int ret = -1;
+	int labelfd = -1;
+	const char *name;
+	char path[LXC_LSMATTRLEN];
+
+	name = lsm_name();
+
+	if (strcmp(name, "nop") == 0)
+		return 0;
+
+	if (strcmp(name, "none") == 0)
+		return 0;
+
+	/* We don't support on-exec with AppArmor */
+	if (strcmp(name, "AppArmor") == 0)
+		on_exec = 0;
+
+	if (on_exec)
+		ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/exec", pid);
+	else
+		ret = snprintf(path, LXC_LSMATTRLEN, "/proc/%d/attr/current", pid);
+	if (ret < 0 || ret >= LXC_LSMATTRLEN)
+		return -1;
+
+	labelfd = open(path, O_RDWR);
+	if (labelfd < 0) {
+		SYSERROR("%s - Unable to %s LSM label file descriptor",
+			 name, strerror(errno));
+		return -1;
+	}
+
+	return labelfd;
+}
+
 int lsm_process_label_set(const char *label, struct lxc_conf *conf,
 			  bool use_default, bool on_exec)
 {
diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h
index 3b08b3be7..db8738411 100644
--- a/src/lxc/lsm/lsm.h
+++ b/src/lxc/lsm/lsm.h
@@ -48,6 +48,7 @@ extern const char *lsm_name(void);
 extern char *lsm_process_label_get(pid_t pid);
 extern int lsm_process_label_set(const char *label, struct lxc_conf *conf,
 				 bool use_default, bool on_exec);
+extern int lsm_process_label_fd_get(pid_t pid, bool on_exec);
 #else
 static inline void lsm_init(void)
 {
@@ -74,6 +75,11 @@ static inline int lsm_process_label_set(const char *label,
 {
 	return 0;
 }
+
+static inline int lsm_process_label_fd_get(pid_t pid, bool on_exec)
+{
+	return 0;
+}
 #endif
 
 #endif

From d3ba7c987201cb461ed92c027e9f424737fbe341 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 22 Jan 2018 11:54:21 +0100
Subject: [PATCH 3/5] lsm: add lsm_process_label_set_at()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/attach.c  | 68 ++++---------------------------------------------------
 src/lxc/lsm/lsm.c | 53 +++++++++++++++++++++++++++++++++++++++++++
 src/lxc/lsm/lsm.h |  8 +++++++
 3 files changed, 65 insertions(+), 64 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 369d88183..45979bcdc 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -88,66 +88,6 @@
 
 lxc_log_define(lxc_attach, lxc);
 
-static int lsm_set_label_at(int lsm_labelfd, int on_exec, char *lsm_label)
-{
-	int fret = -1;
-	const char *name;
-	char *command = NULL;
-
-	name = lsm_name();
-
-	if (strcmp(name, "nop") == 0)
-		return 0;
-
-	if (strcmp(name, "none") == 0)
-		return 0;
-
-	/* We don't support on-exec with AppArmor */
-	if (strcmp(name, "AppArmor") == 0)
-		on_exec = 0;
-
-	if (strcmp(name, "AppArmor") == 0) {
-		int size;
-
-		command =
-		    malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
-		if (!command) {
-			SYSERROR("Failed to write apparmor profile.");
-			goto out;
-		}
-
-		size = sprintf(command, "changeprofile %s", lsm_label);
-		if (size < 0) {
-			SYSERROR("Failed to write apparmor profile.");
-			goto out;
-		}
-
-		if (write(lsm_labelfd, command, size + 1) < 0) {
-			SYSERROR("Unable to set LSM label: %s.", command);
-			goto out;
-		}
-		INFO("Set LSM label to: %s.", command);
-	} else if (strcmp(name, "SELinux") == 0) {
-		if (write(lsm_labelfd, lsm_label, strlen(lsm_label) + 1) < 0) {
-			SYSERROR("Unable to set LSM label: %s.", lsm_label);
-			goto out;
-		}
-		INFO("Set LSM label to: %s.", lsm_label);
-	} else {
-		ERROR("Unable to restore label for unknown LSM: %s.", name);
-		goto out;
-	}
-	fret = 0;
-
-out:
-	free(command);
-
-	if (lsm_labelfd != -1)
-		close(lsm_labelfd);
-
-	return fret;
-}
-
 /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
 #define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
 static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
@@ -922,15 +862,15 @@ static int attach_child_main(struct attach_clone_payload *payload)
 	}
 
 	if (needs_lsm) {
-		int on_exec;
+		bool on_exec;
 
 		/* Change into our new LSM profile. */
-		on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
-		ret = lsm_set_label_at(lsm_fd, on_exec, init_ctx->lsm_label);
+		on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? true : false;
+		ret = lsm_process_label_set_at(lsm_fd, init_ctx->lsm_label, on_exec);
 		close(lsm_fd);
 		if (ret < 0)
 			goto on_error;
-		TRACE("Set LSM label");
+		TRACE("Set %s LSM label to \"%s\"", lsm_name(), init_ctx->lsm_label);
 	}
 
 	if (init_ctx->container && init_ctx->container->lxc_conf &&
diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c
index 98bf083bb..677f53a61 100644
--- a/src/lxc/lsm/lsm.c
+++ b/src/lxc/lsm/lsm.c
@@ -121,6 +121,59 @@ int lsm_process_label_fd_get(pid_t pid, bool on_exec)
 	return labelfd;
 }
 
+int lsm_process_label_set_at(int label_fd, const char *label, bool on_exec)
+{
+	int ret = -1;
+	const char *name;
+
+	name = lsm_name();
+
+	if (strcmp(name, "nop") == 0)
+		return 0;
+
+	if (strcmp(name, "none") == 0)
+		return 0;
+
+	/* We don't support on-exec with AppArmor */
+	if (strcmp(name, "AppArmor") == 0)
+		on_exec = false;
+
+	if (strcmp(name, "AppArmor") == 0) {
+		size_t len;
+		char *command;
+
+		if (on_exec) {
+			ERROR("Changing AppArmor profile on exec not supported");
+			return -EINVAL;
+		}
+
+		len = strlen(label) + strlen("changeprofile ") + 1;
+		command = malloc(len);
+		if (!command)
+			return -1;
+
+		ret = snprintf(command, len, "changeprofile %s", label);
+		if (ret < 0 || (size_t)ret >= len) {
+			free(command);
+			return -1;
+		}
+
+		ret = lxc_write_nointr(label_fd, command, len - 1);
+		free(command);
+	} else if (strcmp(name, "SELinux") == 0) {
+		ret = lxc_write_nointr(label_fd, label, strlen(label));
+	} else {
+		ret = -EINVAL;
+	}
+	if (ret < 0) {
+		SYSERROR("Failed to set %s label \"%s\"", name, label);
+		return -1;
+	}
+
+	INFO("Set %s label to \"%s\"", name, label);
+	return 0;
+}
+
 int lsm_process_label_set(const char *label, struct lxc_conf *conf,
 			  bool use_default, bool on_exec)
 {
diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h
index db8738411..33a412b7b 100644
--- a/src/lxc/lsm/lsm.h
+++ b/src/lxc/lsm/lsm.h
@@ -49,6 +49,8 @@ extern char *lsm_process_label_get(pid_t pid);
 extern int lsm_process_label_set(const char *label, struct lxc_conf *conf,
 				 bool use_default, bool on_exec);
 extern int lsm_process_label_fd_get(pid_t pid, bool on_exec);
+extern int lsm_process_label_set_at(int label_fd, const char *label,
+				    bool on_exec);
 #else
 static inline void lsm_init(void)
 {
@@ -80,6 +82,12 @@ static inline int lsm_process_label_fd_get(pid_t pid, bool on_exec)
 {
 	return 0;
 }
+
+extern int lsm_process_label_set_at(int label_fd, const char *label,
+				    bool on_exec)
+{
+	return 0;
+}
 #endif
 
 #endif

From 5288a74faaa59680cab48f339e97c4ed6ce2a139 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 22 Jan 2018 12:02:44 +0100
Subject: [PATCH 4/5] apparmor: do not call aa_change_profile()

We can simply write the label ourselves. There's no magic happening.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/lsm/apparmor.c | 20 +++++++++++++++-----
 src/lxc/utils.h        |  9 +++++++++
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c
index 0021001ac..85b70de8d 100644
--- a/src/lxc/lsm/apparmor.c
+++ b/src/lxc/lsm/apparmor.c
@@ -25,11 +25,10 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
-#include <sys/apparmor.h>
 #include <sys/vfs.h>
 
 #include "log.h"
-#include "lsm/lsm.h"
+#include "lsm.h"
 #include "conf.h"
 #include "utils.h"
 
@@ -174,6 +173,8 @@ static bool aa_needs_transition(char *curlabel)
 static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf,
 				      bool use_default, bool on_exec)
 {
+	int label_fd, ret;
+	pid_t tid;
 	const char *label = inlabel ? inlabel : conf->lsm_aa_profile;
 	char *curlabel;
 
@@ -230,12 +231,21 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf
 		return 0;
 	}
 
-	if (aa_change_profile(label) < 0) {
-		SYSERROR("failed to change apparmor profile to %s", label);
+	tid = lxc_raw_gettid();
+	label_fd = lsm_process_label_fd_get(tid, on_exec);
+	if (label_fd < 0) {
+		SYSERROR("Failed to change apparmor profile to %s", label);
 		return -1;
 	}
 
-	INFO("changed apparmor profile to %s", label);
+	ret = lsm_process_label_set_at(label_fd, label, on_exec);
+	close(label_fd);
+	if (ret < 0) {
+		SYSERROR("Failed to change apparmor profile to %s", label);
+		return -1;
+	}
+
+	INFO("Changed apparmor profile to %s", label);
 	return 0;
 }
 
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index f8cf26fbf..188b646a3 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -541,4 +541,13 @@ static inline uint64_t lxc_getpagesize(void)
  */
 extern uint64_t lxc_find_next_power2(uint64_t n);
 
+static inline pid_t lxc_raw_gettid(void)
+{
+#ifdef SYS_gettid
+	return syscall(SYS_gettid);
+#else
+	return lxc_raw_getpid();
+#endif
+}
+
 #endif /* __LXC_UTILS_H */

From 05f0f93a93452070006524ac22a6f51e19f8271f Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 22 Jan 2018 12:14:21 +0100
Subject: [PATCH 5/5] autotools: do not link against libapparmor

Since we write the label directly without going through the AppArmor API it
doesn't make sense to link against it.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 configure.ac        | 5 -----
 src/lxc/Makefile.am | 4 ++--
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0bcd75a28..6713539b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,11 +258,6 @@ if test "$enable_apparmor" = "auto" ; then
 fi
 AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
 
-AM_COND_IF([ENABLE_APPARMOR],
-	[AC_CHECK_HEADER([sys/apparmor.h],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
-	AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
-	AC_SUBST([APPARMOR_LIBS], [-lapparmor])])
-
 # GnuTLS
 AC_ARG_ENABLE([gnutls],
 	[AC_HELP_STRING([--enable-gnutls], [enable GnuTLS support [default=auto]])],
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 895684e0b..8f9a7ab29 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -207,7 +207,7 @@ liblxc_la_LDFLAGS = \
 	-Wl,-soname,liblxc.so.$(firstword $(subst ., , at LXC_ABI@)) \
 	-version-info @LXC_ABI_MAJOR@
 
-liblxc_la_LIBADD = $(CAP_LIBS) $(APPARMOR_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS)
+liblxc_la_LIBADD = $(CAP_LIBS) $(SELINUX_LIBS) $(SECCOMP_LIBS)
 
 if ENABLE_CGMANAGER
 liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
@@ -264,7 +264,7 @@ AM_LDFLAGS = -Wl,-E
 if ENABLE_RPATH
 AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
 endif
-LDADD=liblxc.la @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
+LDADD=liblxc.la @CAP_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
 
 lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c
 lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c


More information about the lxc-devel mailing list