Linux-EROFS Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] erofs-utils: support selinux file contexts
@ 2020-05-30 16:11 Gao Xiang
       [not found] ` <fb53174b-605c-b893-a2b0-d5a76132e244@aliyun.com>
  2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
  0 siblings, 2 replies; 11+ messages in thread
From: Gao Xiang @ 2020-05-30 16:11 UTC (permalink / raw)
  To: linux-erofs; +Cc: Shung Wang

Add --file-contexts flag that allows passing a selinux
file_context file to setup file selabels.

Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
prelimiary version.

 configure.ac           |  27 +++++++++
 include/erofs/config.h |  11 ++++
 include/erofs/xattr.h  |   3 +-
 lib/config.c           |  19 +++++++
 lib/exclude.c          |  12 +---
 lib/inode.c            |   3 +-
 lib/xattr.c            | 122 ++++++++++++++++++++++++++++++++---------
 man/mkfs.erofs.1       |   3 +
 mkfs/Makefile.am       |   4 +-
 mkfs/main.c            |  29 +++++++++-
 10 files changed, 190 insertions(+), 43 deletions(-)

diff --git a/configure.ac b/configure.ac
index 870dfb9..5145971 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
    [AS_HELP_STRING([--without-uuid],
       [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
 
+AC_ARG_WITH(selinux,
+   [AS_HELP_STRING([--with-selinux],
+      [enable and build with selinux support @<:@default=no@:>@])],
+   [case "$with_selinux" in
+      yes|no) ;;
+      *) AC_MSG_ERROR([invalid argument to --with-selinux])
+      ;;
+    esac], [with_selinux=no])
+
 # Checks for libraries.
 # Use customized LZ4 library path when specified.
 AC_ARG_WITH(lz4-incdir,
@@ -160,6 +169,20 @@ return 0;
   LIBS="${saved_LIBS}"
   CPPFLAGS="${saved_CPPFLAGS}"], [have_uuid="no"])
 
+# Configure selinux
+AS_IF([test "x$with_selinux" != "xno"], [
+  PKG_CHECK_MODULES([libselinux], [libselinux])
+  # Paranoia: don't trust the result reported by pkgconfig before trying out
+  saved_LIBS="$LIBS"
+  saved_CPPFLAGS=${CPPFLAGS}
+  CPPFLAGS="${libselinux_CFLAGS} ${CPPFLAGS}"
+  LIBS="${libselinux_LIBS} $LIBS"
+  AC_CHECK_LIB(selinux, selabel_lookup, [
+    have_selinux="yes" ], [
+    AC_MSG_ERROR([libselinux doesn't work properly])])
+  LIBS="${saved_LIBS}"
+  CPPFLAGS="${saved_CPPFLAGS}"], [have_selinux="no"])
+
 # Configure lz4
 test -z $LZ4_LIBS && LZ4_LIBS='-llz4'
 
@@ -199,6 +222,10 @@ if test "x$have_uuid" = "xyes"; then
   AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
 fi
 
+if test "x$have_selinux" = "xyes"; then
+  AC_DEFINE([HAVE_LIBSELINUX], 1, [Define to 1 if libselinux is found])
+fi
+
 if test "x${have_lz4}" = "xyes"; then
   AC_DEFINE([LZ4_ENABLED], [1], [Define to 1 if lz4 is enabled.])
 
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2be05ee..825abaf 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -11,6 +11,11 @@
 
 #include "defs.h"
 
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
+
 enum {
 	FORCE_INODE_COMPACT = 1,
 	FORCE_INODE_EXTENDED,
@@ -22,6 +27,9 @@ struct erofs_configure {
 	bool c_dry_run;
 	bool c_legacy_compress;
 
+#ifdef HAVE_LIBSELINUX
+	struct selabel_handle *sehnd;
+#endif
 	/* related arguments for mkfs.erofs */
 	char *c_img_path;
 	char *c_src_path;
@@ -39,5 +47,8 @@ void erofs_init_configure(void);
 void erofs_show_config(void);
 void erofs_exit_configure(void);
 
+void erofs_set_fs_root(const char *rootdir);
+const char *erofs_fspath(const char *fullpath);
+
 #endif
 
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 3dff1ea..2e99669 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -42,7 +42,8 @@
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs);
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs);
 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
 int erofs_build_shared_xattrs_from_path(const char *path);
 
diff --git a/lib/config.c b/lib/config.c
index cbbecce..ae21252 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -36,6 +36,25 @@ void erofs_show_config(void)
 
 void erofs_exit_configure(void)
 {
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd)
+		selabel_close(cfg.sehnd);
+#endif
+}
+
+static unsigned int fullpath_prefix;	/* root directory prefix length */
+
+void erofs_set_fs_root(const char *rootdir)
+{
+	fullpath_prefix = strlen(rootdir);
+}
+
+const char *erofs_fspath(const char *fullpath)
+{
+	const char *s = fullpath + fullpath_prefix;
 
+	while (*s == '/')
+		s++;
+	return s;
 }
 
diff --git a/lib/exclude.c b/lib/exclude.c
index 47b467d..73b3720 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -17,13 +17,6 @@
 static LIST_HEAD(exclude_head);
 static LIST_HEAD(regex_exclude_head);
 
-static unsigned int rpathlen;		/* root directory prefix length */
-
-void erofs_exclude_set_root(const char *rootdir)
-{
-	rpathlen = strlen(rootdir);
-}
-
 static void dump_regerror(int errcode, const char *s, const regex_t *preg)
 {
 	char str[512];
@@ -120,10 +113,7 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
 		s = buf;
 	}
 
-	s += rpathlen;
-	while (*s == '/')
-		s++;
-
+	s = erofs_fspath(s);
 	list_for_each_entry(r, &exclude_head, list) {
 		if (!strcmp(r->pattern, s))
 			return r;
diff --git a/lib/inode.c b/lib/inode.c
index 7114023..dff5f2c 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -827,7 +827,8 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 	struct dirent *dp;
 	struct erofs_dentry *d;
 
-	ret = erofs_prepare_xattr_ibody(dir->i_srcpath, &dir->i_xattrs);
+	ret = erofs_prepare_xattr_ibody(dir->i_srcpath,
+					dir->i_mode, &dir->i_xattrs);
 	if (ret < 0)
 		return ERR_PTR(ret);
 	dir->xattr_isize = ret;
diff --git a/lib/xattr.c b/lib/xattr.c
index 1564016..698c237 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -186,6 +186,43 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key,
 	return get_xattritem(prefix, kvbuf, len);
 }
 
+static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
+						  mode_t mode)
+{
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd) {
+		char *secontext;
+		int ret;
+		unsigned int len[2];
+		char *kvbuf, *fspath;
+
+		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
+		if (ret <= 0)
+			return ERR_PTR(-ENOMEM);
+
+		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
+		free(fspath);
+
+		if (ret) {
+			ret = -errno;
+			erofs_err("cannot lookup selabel for %s", srcpath);
+			/* secontext = strdup("u:object_r:unlabeled:s0"); */
+			return ERR_PTR(ret);
+		}
+
+		len[0] = sizeof("selinux") - 1;
+		len[1] = strlen(secontext);
+		kvbuf = malloc(len[0] + len[1] + 1);
+		if (!kvbuf)
+			return ERR_PTR(-ENOMEM);
+
+		sprintf(kvbuf, "selinux%s", secontext);
+		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
+	}
+#endif
+	return NULL;
+}
+
 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
 {
 	struct inode_xattr_node *node = malloc(sizeof(*node));
@@ -215,19 +252,48 @@ static int shared_xattr_add(struct xattr_item *item)
 	return ++shared_xattrs_count;
 }
 
-static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
+static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+{
+	if (ixattrs)
+		return inode_xattr_add(ixattrs, item);
+
+	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
+		int ret = shared_xattr_add(item);
+
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static bool erofs_is_skipped_xattr(const char *key)
+{
+#ifdef HAVE_LIBSELINUX
+	/* if sehnd is valid, selabels will be overridden */
+	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
+		return true;
+#endif
+	return false;
+}
+
+static int read_xattrs_from_file(const char *path, mode_t mode,
+				 struct list_head *ixattrs)
 {
-	int ret = 0;
-	char *keylst, *key;
 	ssize_t kllen = llistxattr(path, NULL, 0);
+	int ret;
+	char *keylst, *key, *klend;
+	unsigned int keylen;
+	struct xattr_item *item;
 
 	if (kllen < 0 && errno != ENODATA) {
 		erofs_err("llistxattr to get the size of names for %s failed",
 			  path);
 		return -errno;
 	}
+
+	ret = 0;
 	if (kllen <= 1)
-		return 0;
+		goto out;
 
 	keylst = malloc(kllen);
 	if (!keylst)
@@ -246,36 +312,38 @@ static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
 	 * attribute keys. Use the remaining buffer length to determine
 	 * the end of the list.
 	 */
-	key = keylst;
-	while (kllen > 0) {
-		unsigned int keylen = strlen(key);
-		struct xattr_item *item = parse_one_xattr(path, key, keylen);
+	klend = keylst + kllen;
+	ret = 0;
+
+	for (key = keylst; key != klend; key += keylen + 1) {
+		keylen = strlen(key);
+		if (erofs_is_skipped_xattr(key))
+			continue;
 
+		item = parse_one_xattr(path, key, keylen);
 		if (IS_ERR(item)) {
 			ret = PTR_ERR(item);
 			goto err;
 		}
 
-		if (ixattrs) {
-			ret = inode_xattr_add(ixattrs, item);
-			if (ret < 0)
-				goto err;
-		} else if (item->count == cfg.c_inline_xattr_tolerance + 1) {
-			ret = shared_xattr_add(item);
-			if (ret < 0)
-				goto err;
-			ret = 0;
-		}
-		kllen -= keylen + 1;
-		key += keylen + 1;
+		ret = erofs_xattr_add(ixattrs, item);
+		if (ret < 0)
+			goto err;
 	}
-err:
 	free(keylst);
+out:
+	item = erofs_get_selabel_xattr(path, mode);
+	if (item)
+		ret = erofs_xattr_add(ixattrs, item);
 	return ret;
 
+err:
+	free(keylst);
+	return ret;
 }
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs)
 {
 	int ret;
 	struct inode_xattr_node *node;
@@ -284,7 +352,7 @@ int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
 	if (cfg.c_inline_xattr_tolerance < 0)
 		return 0;
 
-	ret = read_xattrs_from_file(path, ixattrs);
+	ret = read_xattrs_from_file(path, mode, ixattrs);
 	if (ret < 0)
 		return ret;
 
@@ -345,16 +413,16 @@ static int erofs_count_all_xattrs_from_path(const char *path)
 			goto fail;
 		}
 
-		ret = read_xattrs_from_file(buf, NULL);
-		if (ret)
-			goto fail;
-
 		ret = lstat64(buf, &st);
 		if (ret) {
 			ret = -errno;
 			goto fail;
 		}
 
+		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
+		if (ret)
+			goto fail;
+
 		if (!S_ISDIR(st.st_mode))
 			continue;
 
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d47207a..891c5a8 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -60,6 +60,9 @@ You may give multiple `--exclude-path' options.
 Ignore files that match the given regular expression.
 You may give multiple `--exclude-regex` options.
 .TP
+.BI "\-\-file-contexts=" file
+Specify a \fIfile_contexts\fR file to setup / override selinux labels.
+.TP
 .B \-\-help
 Display this help and exit.
 .SH AUTHOR
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 9ce06d6..97ba148 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -3,8 +3,8 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = mkfs.erofs
-AM_CPPFLAGS = ${libuuid_CFLAGS}
+AM_CPPFLAGS = ${libuuid_CFLAGS} ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
-mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS}
+mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} ${libselinux_LIBS}
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 940d4e8..7de929f 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -33,6 +33,9 @@ static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
 	{"exclude-path", required_argument, NULL, 2},
 	{"exclude-regex", required_argument, NULL, 3},
+#ifdef HAVE_LIBSELINUX
+	{"file-contexts", required_argument, NULL, 4},
+#endif
 	{0, 0, 0, 0},
 };
 
@@ -60,6 +63,9 @@ static void usage(void)
 	      " -T#               set a fixed UNIX timestamp # to all files\n"
 	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
 	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
+#ifdef HAVE_LIBSELINUX
+	      " --file-contexts=X specify a file contexts file to setup selinux labels\n"
+#endif
 	      " --help            display this help and exit\n"
 	      "\nAvailable compressors are: ", stderr);
 	print_available_compressors(stderr, ", ");
@@ -198,6 +204,27 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				return opt;
 			}
 			break;
+
+#ifdef HAVE_LIBSELINUX
+		case 4: {
+			struct selinux_opt seopts[] = {
+				{ .type = SELABEL_OPT_PATH, .value = optarg }
+			};
+
+			if (cfg.sehnd) {
+				erofs_info("ignore duplicated file contexts \"%s\"",
+					   optarg);
+				break;
+			}
+			cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+			if (!cfg.sehnd) {
+				erofs_err("failed to open file contexts \"%s\"",
+					  optarg);
+				return -EINVAL;
+			}
+			break;
+		}
+#endif
 		case 1:
 			usage();
 			exit(0);
@@ -392,7 +419,7 @@ int main(int argc, char **argv)
 	}
 
 	erofs_show_config();
-	erofs_exclude_set_root(cfg.c_src_path);
+	erofs_set_fs_root(cfg.c_src_path);
 
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
-- 
2.18.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] erofs-utils: support selinux file contexts
       [not found] ` <fb53174b-605c-b893-a2b0-d5a76132e244@aliyun.com>
@ 2020-06-04  1:36   ` Gao Xiang
  0 siblings, 0 replies; 11+ messages in thread
From: Gao Xiang @ 2020-06-04  1:36 UTC (permalink / raw)
  To: Li GuiFu; +Cc: linux-erofs, Shung Wang

Hi Guifu,

On Wed, Jun 03, 2020 at 11:54:11PM +0800, Li GuiFu wrote:
> Gao Xiang
>   I have given some opinion
>   Please have a look, and resend a new one

It seems your email still didn't work properly since I don't
find that in the mailing list (as many other previous mail
providers of you...)

> 
> On 2020/5/31 0:11, Gao Xiang wrote:
> > Add --file-contexts flag that allows passing a selinux
> > file_context file to setup file selabels.
> > 
> > Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> > ---
> > prelimiary version.
> > 
> >  configure.ac           |  27 +++++++++
> >  include/erofs/config.h |  11 ++++
> >  include/erofs/xattr.h  |   3 +-
> >  lib/config.c           |  19 +++++++
> >  lib/exclude.c          |  12 +---
> >  lib/inode.c            |   3 +-
> >  lib/xattr.c            | 122 ++++++++++++++++++++++++++++++++---------
> >  man/mkfs.erofs.1       |   3 +
> >  mkfs/Makefile.am       |   4 +-
> >  mkfs/main.c            |  29 +++++++++-
> >  10 files changed, 190 insertions(+), 43 deletions(-)
> > 
> > diff --git a/configure.ac b/configure.ac
> > index 870dfb9..5145971 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
> >     [AS_HELP_STRING([--without-uuid],
> >        [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
> >  
> > +AC_ARG_WITH(selinux,
> > +   [AS_HELP_STRING([--with-selinux],
> > +      [enable and build with selinux support @<:@default=no@:>@])],
> > +   [case "$with_selinux" in
> > +      yes|no) ;;
> > +      *) AC_MSG_ERROR([invalid argument to --with-selinux])
> > +      ;;
> > +    esac], [with_selinux=no])
> > +
> >  # Checks for libraries.
> >  # Use customized LZ4 library path when specified.
> >  AC_ARG_WITH(lz4-incdir,
> > @@ -160,6 +169,20 @@ return 0;
> >    LIBS="${saved_LIBS}"
> >    CPPFLAGS="${saved_CPPFLAGS}"], [have_uuid="no"])
> >  
> > +# Configure selinux
> > +AS_IF([test "x$with_selinux" != "xno"], [
> > +  PKG_CHECK_MODULES([libselinux], [libselinux])
> > +  # Paranoia: don't trust the result reported by pkgconfig before trying out
> > +  saved_LIBS="$LIBS"
> > +  saved_CPPFLAGS=${CPPFLAGS}
> > +  CPPFLAGS="${libselinux_CFLAGS} ${CPPFLAGS}"
> > +  LIBS="${libselinux_LIBS} $LIBS"
> > +  AC_CHECK_LIB(selinux, selabel_lookup, [
> > +    have_selinux="yes" ], [
> > +    AC_MSG_ERROR([libselinux doesn't work properly])])
> > +  LIBS="${saved_LIBS}"
> > +  CPPFLAGS="${saved_CPPFLAGS}"], [have_selinux="no"])
> > +
> >  # Configure lz4
> >  test -z $LZ4_LIBS && LZ4_LIBS='-llz4'
> >  
> > @@ -199,6 +222,10 @@ if test "x$have_uuid" = "xyes"; then
> >    AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
> >  fi
> >  
> > +if test "x$have_selinux" = "xyes"; then
> > +  AC_DEFINE([HAVE_LIBSELINUX], 1, [Define to 1 if libselinux is found])
> > +fi
> > +
> >  if test "x${have_lz4}" = "xyes"; then
> >    AC_DEFINE([LZ4_ENABLED], [1], [Define to 1 if lz4 is enabled.])
> >  
> Is it good to enable selinux support by default
> if the host has selinux installed  ?

Currently, configure.ac doesn't have --with-selinux=check option.

That means if "$with_selinux" == yes, it will fail if libselinux
doesn't find. That's for safety concern (just let users to install
if --with-selinux is enabled rather than build without libselinux).

Note that libselinux is an optional feature and unnecessary
for primary use cases. So users don't have to install it
apart from such as Android use cases.

> 
> > diff --git a/include/erofs/config.h b/include/erofs/config.h
> > index 2be05ee..825abaf 100644
> > --- a/include/erofs/config.h
> > +++ b/include/erofs/config.h
> > @@ -11,6 +11,11 @@
> >  
> >  #include "defs.h"
> >  
> > +#ifdef HAVE_LIBSELINUX
> > +#include <selinux/selinux.h>
> > +#include <selinux/label.h>
> > +#endif
> > +
> >  enum {
> >  	FORCE_INODE_COMPACT = 1,
> >  	FORCE_INODE_EXTENDED,
> > @@ -22,6 +27,9 @@ struct erofs_configure {
> >  	bool c_dry_run;
> >  	bool c_legacy_compress;
> >  
> > +#ifdef HAVE_LIBSELINUX
> > +	struct selabel_handle *sehnd;
> > +#endif
> >  	/* related arguments for mkfs.erofs */
> >  	char *c_img_path;
> >  	char *c_src_path;
> > @@ -39,5 +47,8 @@ void erofs_init_configure(void);
> >  void erofs_show_config(void);
> >  void erofs_exit_configure(void);
> >  
> > +void erofs_set_fs_root(const char *rootdir);
> > +const char *erofs_fspath(const char *fullpath);
> > +
> >  #endif
> >  
> > diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
> > index 3dff1ea..2e99669 100644
> > --- a/include/erofs/xattr.h
> > +++ b/include/erofs/xattr.h
> > @@ -42,7 +42,8 @@
> >  #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
> >  #endif
> >  
> > -int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs);
> > +int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
> > +			      struct list_head *ixattrs);
> >  char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
> >  int erofs_build_shared_xattrs_from_path(const char *path);
> >  
> > diff --git a/lib/config.c b/lib/config.c
> > index cbbecce..ae21252 100644
> > --- a/lib/config.c
> > +++ b/lib/config.c
> > @@ -36,6 +36,25 @@ void erofs_show_config(void)
> >  
> >  void erofs_exit_configure(void)
> >  {
> > +#ifdef HAVE_LIBSELINUX
> > +	if (cfg.sehnd)
> > +		selabel_close(cfg.sehnd);
> > +#endif
> > +}
> > +
> > +static unsigned int fullpath_prefix;	/* root directory prefix length */
> > +
> > +void erofs_set_fs_root(const char *rootdir)
> > +{
> > +	fullpath_prefix = strlen(rootdir);
> > +}
> > +
> > +const char *erofs_fspath(const char *fullpath)
> > +{
> > +	const char *s = fullpath + fullpath_prefix;
> >  
> > +	while (*s == '/')
> > +		s++;
> > +	return s;
> >  }
> >  
> > diff --git a/lib/exclude.c b/lib/exclude.c
> > index 47b467d..73b3720 100644
> > --- a/lib/exclude.c
> > +++ b/lib/exclude.c
> > @@ -17,13 +17,6 @@
> >  static LIST_HEAD(exclude_head);
> >  static LIST_HEAD(regex_exclude_head);
> >  
> > -static unsigned int rpathlen;		/* root directory prefix length */
> > -
> > -void erofs_exclude_set_root(const char *rootdir)
> > -{
> > -	rpathlen = strlen(rootdir);
> > -}
> > -
> >  static void dump_regerror(int errcode, const char *s, const regex_t *preg)
> >  {
> >  	char str[512];
> > @@ -120,10 +113,7 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
> >  		s = buf;
> >  	}
> >  
> > -	s += rpathlen;
> > -	while (*s == '/')
> > -		s++;
> > -
> > +	s = erofs_fspath(s);
> >  	list_for_each_entry(r, &exclude_head, list) {
> >  		if (!strcmp(r->pattern, s))
> >  			return r;
> > diff --git a/lib/inode.c b/lib/inode.c
> > index 7114023..dff5f2c 100644
> > --- a/lib/inode.c
> > +++ b/lib/inode.c
> > @@ -827,7 +827,8 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
> >  	struct dirent *dp;
> >  	struct erofs_dentry *d;
> >  
> > -	ret = erofs_prepare_xattr_ibody(dir->i_srcpath, &dir->i_xattrs);
> > +	ret = erofs_prepare_xattr_ibody(dir->i_srcpath,
> > +					dir->i_mode, &dir->i_xattrs);
> >  	if (ret < 0)
> >  		return ERR_PTR(ret);
> >  	dir->xattr_isize = ret;
> > diff --git a/lib/xattr.c b/lib/xattr.c
> > index 1564016..698c237 100644
> > --- a/lib/xattr.c
> > +++ b/lib/xattr.c
> > @@ -186,6 +186,43 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key,
> >  	return get_xattritem(prefix, kvbuf, len);
> >  }
> >  
> > +static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
> > +						  mode_t mode)
> > +{
> > +#ifdef HAVE_LIBSELINUX
> > +	if (cfg.sehnd) {
> > +		char *secontext;
> > +		int ret;
> > +		unsigned int len[2];
> > +		char *kvbuf, *fspath;
> > +
> > +		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
> > +		if (ret <= 0)
> > +			return ERR_PTR(-ENOMEM);
> > +
> > +		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
> > +		free(fspath);
> > +
> > +		if (ret) {
> > +			ret = -errno;
> > +			erofs_err("cannot lookup selabel for %s", srcpath);
> > +			/* secontext = strdup("u:object_r:unlabeled:s0"); */
> > +			return ERR_PTR(ret);
> > +		}
> > +
> > +		len[0] = sizeof("selinux") - 1;
> > +		len[1] = strlen(secontext);
> > +		kvbuf = malloc(len[0] + len[1] + 1);
> > +		if (!kvbuf)
> > +			return ERR_PTR(-ENOMEM);
> > +
> > +		sprintf(kvbuf, "selinux%s", secontext);
> > +		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
> > +	}
> > +#endif
> > +	return NULL;
> > +}
> > +
> >  static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
> >  {
> >  	struct inode_xattr_node *node = malloc(sizeof(*node));
> > @@ -215,19 +252,48 @@ static int shared_xattr_add(struct xattr_item *item)
> >  	return ++shared_xattrs_count;
> >  }
> >  
> > -static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
> > +static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
> > +{
> > +	if (ixattrs)
> > +		return inode_xattr_add(ixattrs, item);
> > +
> > +	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
> > +		int ret = shared_xattr_add(item);
> > +
> > +		if (ret < 0)
> > +			return ret;
> > +	}
> > +	return 0;
> > +}
> > +
> > +static bool erofs_is_skipped_xattr(const char *key)
> > +{
> > +#ifdef HAVE_LIBSELINUX
> > +	/* if sehnd is valid, selabels will be overridden */
> > +	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
> > +		return true;
> > +#endif
> > +	return false;
> > +}
> > +
> > +static int read_xattrs_from_file(const char *path, mode_t mode,
> > +				 struct list_head *ixattrs)
> >  {
> > -	int ret = 0;
> > -	char *keylst, *key;
> >  	ssize_t kllen = llistxattr(path, NULL, 0);
> > +	int ret;
> > +	char *keylst, *key, *klend;
> > +	unsigned int keylen;
> > +	struct xattr_item *item;
> >  
> >  	if (kllen < 0 && errno != ENODATA) {
> >  		erofs_err("llistxattr to get the size of names for %s failed",
> >  			  path);
> >  		return -errno;
> >  	}
> > +
> > +	ret = 0;
> >  	if (kllen <= 1)
> > -		return 0;
> > +		goto out;
> >  
> >  	keylst = malloc(kllen);
> >  	if (!keylst)
> > @@ -246,36 +312,38 @@ static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
> >  	 * attribute keys. Use the remaining buffer length to determine
> >  	 * the end of the list.
> >  	 */
> > -	key = keylst;
> > -	while (kllen > 0) {
> > -		unsigned int keylen = strlen(key);
> > -		struct xattr_item *item = parse_one_xattr(path, key, keylen);
> > +	klend = keylst + kllen;
> > +	ret = 0;
> > +
> > +	for (key = keylst; key != klend; key += keylen + 1) {
> > +		keylen = strlen(key);
> > +		if (erofs_is_skipped_xattr(key))
> > +			continue;
> >  
> > +		item = parse_one_xattr(path, key, keylen);
> >  		if (IS_ERR(item)) {
> >  			ret = PTR_ERR(item);
> >  			goto err;
> >  		}
> >  
> > -		if (ixattrs) {
> > -			ret = inode_xattr_add(ixattrs, item);
> > -			if (ret < 0)
> > -				goto err;
> > -		} else if (item->count == cfg.c_inline_xattr_tolerance + 1) {
> > -			ret = shared_xattr_add(item);
> > -			if (ret < 0)
> > -				goto err;
> > -			ret = 0;
> > -		}
> > -		kllen -= keylen + 1;
> > -		key += keylen + 1;
> > +		ret = erofs_xattr_add(ixattrs, item);
> > +		if (ret < 0)
> > +			goto err;
> >  	}
> > -err:
> >  	free(keylst);
> > +out:
> > +	item = erofs_get_selabel_xattr(path, mode);
> > +	if (item)
> > +		ret = erofs_xattr_add(ixattrs, item);
> item may cause a segment fault if erofs_get_selabel_xattr goes fail
> which return a ERR_PTR.

Good catch! will fix it soon. Thank you!

> 
> Does it need create a new function detach from xattr ?
> So read_xattrs_from_file just do one thing

These short part only have one user for now and it's really a part of
generating xattrs for a file. So I think it's unnecessary to create
a new helper for this. (I'd like to avoid too many one-shot short
helpers since I don't think that is a good habit. You know that
readers will look into an extra function and go back to trace the
whole path, that seems redundant. As for better understanding,
I think we can leave some comments here.)

> 
> >  	return ret;
> >  
> > +err:
> > +	free(keylst);
> > +	return ret;
> >  }
> >  
> > -int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
> > +int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
> > +			      struct list_head *ixattrs)
> >  {
> >  	int ret;
> >  	struct inode_xattr_node *node;
> > @@ -284,7 +352,7 @@ int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
> >  	if (cfg.c_inline_xattr_tolerance < 0)
> >  		return 0;
> >  
> > -	ret = read_xattrs_from_file(path, ixattrs);
> > +	ret = read_xattrs_from_file(path, mode, ixattrs);
> >  	if (ret < 0)
> >  		return ret;
> >  
> > @@ -345,16 +413,16 @@ static int erofs_count_all_xattrs_from_path(const char *path)
> >  			goto fail;
> >  		}
> >  
> > -		ret = read_xattrs_from_file(buf, NULL);
> > -		if (ret)
> > -			goto fail;
> > -
> >  		ret = lstat64(buf, &st);
> >  		if (ret) {
> >  			ret = -errno;
> >  			goto fail;
> >  		}
> >  
> > +		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
> > +		if (ret)
> > +			goto fail;
> > +
> >  		if (!S_ISDIR(st.st_mode))
> >  			continue;
> >  
> > diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
> > index d47207a..891c5a8 100644
> > --- a/man/mkfs.erofs.1
> > +++ b/man/mkfs.erofs.1
> > @@ -60,6 +60,9 @@ You may give multiple `--exclude-path' options.
> >  Ignore files that match the given regular expression.
> >  You may give multiple `--exclude-regex` options.
> >  .TP
> > +.BI "\-\-file-contexts=" file
> > +Specify a \fIfile_contexts\fR file to setup / override selinux labels.
> > +.TP
> >  .B \-\-help
> >  Display this help and exit.
> >  .SH AUTHOR
> > diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
> > index 9ce06d6..97ba148 100644
> > --- a/mkfs/Makefile.am
> > +++ b/mkfs/Makefile.am
> > @@ -3,8 +3,8 @@
> >  
> >  AUTOMAKE_OPTIONS = foreign
> >  bin_PROGRAMS     = mkfs.erofs
> > -AM_CPPFLAGS = ${libuuid_CFLAGS}
> > +AM_CPPFLAGS = ${libuuid_CFLAGS} ${libselinux_CFLAGS}
> >  mkfs_erofs_SOURCES = main.c
> >  mkfs_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
> > -mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS}
> > +mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} ${libselinux_LIBS}
> >  
> > diff --git a/mkfs/main.c b/mkfs/main.c
> > index 940d4e8..7de929f 100644
> > --- a/mkfs/main.c
> > +++ b/mkfs/main.c
> > @@ -33,6 +33,9 @@ static struct option long_options[] = {
> >  	{"help", no_argument, 0, 1},
> >  	{"exclude-path", required_argument, NULL, 2},
> >  	{"exclude-regex", required_argument, NULL, 3},
> > +#ifdef HAVE_LIBSELINUX
> > +	{"file-contexts", required_argument, NULL, 4},
> > +#endif
> 
> Many other fs tool use "-S" to set file contexts file path,
> What's you opinon to add a short option ?

"--file-contexts" is a straight-forward way for understanding
this concept. "-S" should have more common and useful meanings,
such as "sparse" or "strip", or "size" (but usually in low-case
"-s"). I'd like to keep some more common meaning in sync with
other tools.

I know your mean make_ext4fs has "-S" option for selinux file
contexts file. but make_ext4fs was an Android only tool (which
was also deprecated by using e2fsprogs). Also, as you can see
what Google did for squashfs-tools, they used a long option
at that time.

If you consider some HUAWEI Android in-house downstream
compatibility, I'd suggest to modify build scripts for this.
Anyway, I'd like to upstream erofs for AOSP. But we need to
complete all remaining Android-specific stuffs (such as fs
config, Android.bp, build scripts) in advance.

> 
> >  	{0, 0, 0, 0},
> >  };
> >  
> > @@ -60,6 +63,9 @@ static void usage(void)
> >  	      " -T#               set a fixed UNIX timestamp # to all files\n"
> >  	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
> >  	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
> > +#ifdef HAVE_LIBSELINUX
> > +	      " --file-contexts=X specify a file contexts file to setup selinux labels\n"
> > +#endif
> >  	      " --help            display this help and exit\n"
> >  	      "\nAvailable compressors are: ", stderr);
> >  	print_available_compressors(stderr, ", ");
> > @@ -198,6 +204,27 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
> >  				return opt;
> >  			}
> >  			break;
> > +
> > +#ifdef HAVE_LIBSELINUX
> > +		case 4: {
> > +			struct selinux_opt seopts[] = {
> > +				{ .type = SELABEL_OPT_PATH, .value = optarg }
> > +			};
> > +
> > +			if (cfg.sehnd) {
> > +				erofs_info("ignore duplicated file contexts \"%s\"",
> > +					   optarg);
> > +				break;
> > +			}
> > +			cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
> > +			if (!cfg.sehnd) {
> > +				erofs_err("failed to open file contexts \"%s\"",
> > +					  optarg);
> > +				return -EINVAL;
> > +			}
> > +			break;
> > +		}
> > +#endif
> it seems  more clear and not complex if move selable_open to xattr.c file.

Okay, will move it to config.c.

Thanks,
Gao Xiang

> 
> 
> >  		case 1:
> >  			usage();
> >  			exit(0);
> > @@ -392,7 +419,7 @@ int main(int argc, char **argv)
> >  	}
> >  
> >  	erofs_show_config();
> > -	erofs_exclude_set_root(cfg.c_src_path);
> > +	erofs_set_fs_root(cfg.c_src_path);
> >  
> >  	sb_bh = erofs_buffer_init();
> >  	if (IS_ERR(sb_bh)) {
> > 
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2] erofs-utils: support selinux file contexts
  2020-05-30 16:11 [PATCH] erofs-utils: support selinux file contexts Gao Xiang
       [not found] ` <fb53174b-605c-b893-a2b0-d5a76132e244@aliyun.com>
@ 2020-06-06  8:17 ` Gao Xiang
  2020-06-07  9:25   ` Li GuiFu via Linux-erofs
                     ` (3 more replies)
  1 sibling, 4 replies; 11+ messages in thread
From: Gao Xiang @ 2020-06-06  8:17 UTC (permalink / raw)
  To: linux-erofs; +Cc: Shung Wang

Add --file-contexts flag that allows passing a selinux
file_context file to setup file selabels.

Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
changes since v1:
 fix selinux error handing and wrap up selabel
 open pointed out by Guifu;

 configure.ac           |  27 +++++++++
 include/erofs/config.h |  21 +++++++
 include/erofs/xattr.h  |   3 +-
 lib/config.c           |  42 +++++++++++++
 lib/exclude.c          |  12 +---
 lib/inode.c            |   3 +-
 lib/xattr.c            | 130 ++++++++++++++++++++++++++++++++---------
 man/mkfs.erofs.1       |   3 +
 mkfs/Makefile.am       |   4 +-
 mkfs/main.c            |  15 ++++-
 10 files changed, 217 insertions(+), 43 deletions(-)

diff --git a/configure.ac b/configure.ac
index 870dfb9..5145971 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
    [AS_HELP_STRING([--without-uuid],
       [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
 
+AC_ARG_WITH(selinux,
+   [AS_HELP_STRING([--with-selinux],
+      [enable and build with selinux support @<:@default=no@:>@])],
+   [case "$with_selinux" in
+      yes|no) ;;
+      *) AC_MSG_ERROR([invalid argument to --with-selinux])
+      ;;
+    esac], [with_selinux=no])
+
 # Checks for libraries.
 # Use customized LZ4 library path when specified.
 AC_ARG_WITH(lz4-incdir,
@@ -160,6 +169,20 @@ return 0;
   LIBS="${saved_LIBS}"
   CPPFLAGS="${saved_CPPFLAGS}"], [have_uuid="no"])
 
+# Configure selinux
+AS_IF([test "x$with_selinux" != "xno"], [
+  PKG_CHECK_MODULES([libselinux], [libselinux])
+  # Paranoia: don't trust the result reported by pkgconfig before trying out
+  saved_LIBS="$LIBS"
+  saved_CPPFLAGS=${CPPFLAGS}
+  CPPFLAGS="${libselinux_CFLAGS} ${CPPFLAGS}"
+  LIBS="${libselinux_LIBS} $LIBS"
+  AC_CHECK_LIB(selinux, selabel_lookup, [
+    have_selinux="yes" ], [
+    AC_MSG_ERROR([libselinux doesn't work properly])])
+  LIBS="${saved_LIBS}"
+  CPPFLAGS="${saved_CPPFLAGS}"], [have_selinux="no"])
+
 # Configure lz4
 test -z $LZ4_LIBS && LZ4_LIBS='-llz4'
 
@@ -199,6 +222,10 @@ if test "x$have_uuid" = "xyes"; then
   AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
 fi
 
+if test "x$have_selinux" = "xyes"; then
+  AC_DEFINE([HAVE_LIBSELINUX], 1, [Define to 1 if libselinux is found])
+fi
+
 if test "x${have_lz4}" = "xyes"; then
   AC_DEFINE([LZ4_ENABLED], [1], [Define to 1 if lz4 is enabled.])
 
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2be05ee..2f09749 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -10,6 +10,12 @@
 #define __EROFS_CONFIG_H
 
 #include "defs.h"
+#include "err.h"
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
 
 enum {
 	FORCE_INODE_COMPACT = 1,
@@ -22,6 +28,9 @@ struct erofs_configure {
 	bool c_dry_run;
 	bool c_legacy_compress;
 
+#ifdef HAVE_LIBSELINUX
+	struct selabel_handle *sehnd;
+#endif
 	/* related arguments for mkfs.erofs */
 	char *c_img_path;
 	char *c_src_path;
@@ -39,5 +48,17 @@ void erofs_init_configure(void);
 void erofs_show_config(void);
 void erofs_exit_configure(void);
 
+void erofs_set_fs_root(const char *rootdir);
+const char *erofs_fspath(const char *fullpath);
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts);
+#else
+static inline int erofs_selabel_open(const char *file_contexts)
+{
+	return -EINVAL;
+}
+#endif
+
 #endif
 
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 3dff1ea..2e99669 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -42,7 +42,8 @@
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs);
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs);
 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
 int erofs_build_shared_xattrs_from_path(const char *path);
 
diff --git a/lib/config.c b/lib/config.c
index cbbecce..da0c260 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -36,6 +36,48 @@ void erofs_show_config(void)
 
 void erofs_exit_configure(void)
 {
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd)
+		selabel_close(cfg.sehnd);
+#endif
+}
+
+static unsigned int fullpath_prefix;	/* root directory prefix length */
+
+void erofs_set_fs_root(const char *rootdir)
+{
+	fullpath_prefix = strlen(rootdir);
+}
+
+const char *erofs_fspath(const char *fullpath)
+{
+	const char *s = fullpath + fullpath_prefix;
+
+	while (*s == '/')
+		s++;
+	return s;
+}
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts)
+{
+	struct selinux_opt seopts[] = {
+		{ .type = SELABEL_OPT_PATH, .value = file_contexts }
+	};
+
+	if (cfg.sehnd) {
+		erofs_info("ignore duplicated file contexts \"%s\"",
+			   file_contexts);
+		return -EBUSY;
+	}
 
+	cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+	if (!cfg.sehnd) {
+		erofs_err("failed to open file contexts \"%s\"",
+			  file_contexts);
+		return -EINVAL;
+	}
+	return 0;
 }
+#endif
 
diff --git a/lib/exclude.c b/lib/exclude.c
index 47b467d..73b3720 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -17,13 +17,6 @@
 static LIST_HEAD(exclude_head);
 static LIST_HEAD(regex_exclude_head);
 
-static unsigned int rpathlen;		/* root directory prefix length */
-
-void erofs_exclude_set_root(const char *rootdir)
-{
-	rpathlen = strlen(rootdir);
-}
-
 static void dump_regerror(int errcode, const char *s, const regex_t *preg)
 {
 	char str[512];
@@ -120,10 +113,7 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
 		s = buf;
 	}
 
-	s += rpathlen;
-	while (*s == '/')
-		s++;
-
+	s = erofs_fspath(s);
 	list_for_each_entry(r, &exclude_head, list) {
 		if (!strcmp(r->pattern, s))
 			return r;
diff --git a/lib/inode.c b/lib/inode.c
index 7114023..dff5f2c 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -827,7 +827,8 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 	struct dirent *dp;
 	struct erofs_dentry *d;
 
-	ret = erofs_prepare_xattr_ibody(dir->i_srcpath, &dir->i_xattrs);
+	ret = erofs_prepare_xattr_ibody(dir->i_srcpath,
+					dir->i_mode, &dir->i_xattrs);
 	if (ret < 0)
 		return ERR_PTR(ret);
 	dir->xattr_isize = ret;
diff --git a/lib/xattr.c b/lib/xattr.c
index 1564016..65c84be 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -186,6 +186,47 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key,
 	return get_xattritem(prefix, kvbuf, len);
 }
 
+static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
+						  mode_t mode)
+{
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd) {
+		char *secontext;
+		int ret;
+		unsigned int len[2];
+		char *kvbuf, *fspath;
+
+		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
+		if (ret <= 0)
+			return ERR_PTR(-ENOMEM);
+
+		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
+		free(fspath);
+
+		if (ret) {
+			ret = -errno;
+			if (ret != -ENOENT) {
+				erofs_err("failed to lookup selabel for %s: %s",
+					  srcpath, erofs_strerror(ret));
+				return ERR_PTR(ret);
+			}
+			/* secontext = "u:object_r:unlabeled:s0"; */
+			return NULL;
+		}
+
+		len[0] = sizeof("selinux") - 1;
+		len[1] = strlen(secontext);
+		kvbuf = malloc(len[0] + len[1] + 1);
+		if (!kvbuf)
+			return ERR_PTR(-ENOMEM);
+
+		sprintf(kvbuf, "selinux%s", secontext);
+		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
+	}
+#endif
+	return NULL;
+}
+
 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
 {
 	struct inode_xattr_node *node = malloc(sizeof(*node));
@@ -215,19 +256,48 @@ static int shared_xattr_add(struct xattr_item *item)
 	return ++shared_xattrs_count;
 }
 
-static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
+static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+{
+	if (ixattrs)
+		return inode_xattr_add(ixattrs, item);
+
+	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
+		int ret = shared_xattr_add(item);
+
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static bool erofs_is_skipped_xattr(const char *key)
+{
+#ifdef HAVE_LIBSELINUX
+	/* if sehnd is valid, selabels will be overridden */
+	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
+		return true;
+#endif
+	return false;
+}
+
+static int read_xattrs_from_file(const char *path, mode_t mode,
+				 struct list_head *ixattrs)
 {
-	int ret = 0;
-	char *keylst, *key;
 	ssize_t kllen = llistxattr(path, NULL, 0);
+	int ret;
+	char *keylst, *key, *klend;
+	unsigned int keylen;
+	struct xattr_item *item;
 
 	if (kllen < 0 && errno != ENODATA) {
 		erofs_err("llistxattr to get the size of names for %s failed",
 			  path);
 		return -errno;
 	}
+
+	ret = 0;
 	if (kllen <= 1)
-		return 0;
+		goto out;
 
 	keylst = malloc(kllen);
 	if (!keylst)
@@ -246,36 +316,42 @@ static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
 	 * attribute keys. Use the remaining buffer length to determine
 	 * the end of the list.
 	 */
-	key = keylst;
-	while (kllen > 0) {
-		unsigned int keylen = strlen(key);
-		struct xattr_item *item = parse_one_xattr(path, key, keylen);
+	klend = keylst + kllen;
+	ret = 0;
+
+	for (key = keylst; key != klend; key += keylen + 1) {
+		keylen = strlen(key);
+		if (erofs_is_skipped_xattr(key))
+			continue;
 
+		item = parse_one_xattr(path, key, keylen);
 		if (IS_ERR(item)) {
 			ret = PTR_ERR(item);
 			goto err;
 		}
 
-		if (ixattrs) {
-			ret = inode_xattr_add(ixattrs, item);
-			if (ret < 0)
-				goto err;
-		} else if (item->count == cfg.c_inline_xattr_tolerance + 1) {
-			ret = shared_xattr_add(item);
-			if (ret < 0)
-				goto err;
-			ret = 0;
-		}
-		kllen -= keylen + 1;
-		key += keylen + 1;
+		ret = erofs_xattr_add(ixattrs, item);
+		if (ret < 0)
+			goto err;
 	}
-err:
 	free(keylst);
+
+out:
+	/* if some selabel is avilable, need to add right now */
+	item = erofs_get_selabel_xattr(path, mode);
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+	if (item)
+		ret = erofs_xattr_add(ixattrs, item);
 	return ret;
 
+err:
+	free(keylst);
+	return ret;
 }
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs)
 {
 	int ret;
 	struct inode_xattr_node *node;
@@ -284,7 +360,7 @@ int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
 	if (cfg.c_inline_xattr_tolerance < 0)
 		return 0;
 
-	ret = read_xattrs_from_file(path, ixattrs);
+	ret = read_xattrs_from_file(path, mode, ixattrs);
 	if (ret < 0)
 		return ret;
 
@@ -345,16 +421,16 @@ static int erofs_count_all_xattrs_from_path(const char *path)
 			goto fail;
 		}
 
-		ret = read_xattrs_from_file(buf, NULL);
-		if (ret)
-			goto fail;
-
 		ret = lstat64(buf, &st);
 		if (ret) {
 			ret = -errno;
 			goto fail;
 		}
 
+		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
+		if (ret)
+			goto fail;
+
 		if (!S_ISDIR(st.st_mode))
 			continue;
 
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d47207a..891c5a8 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -60,6 +60,9 @@ You may give multiple `--exclude-path' options.
 Ignore files that match the given regular expression.
 You may give multiple `--exclude-regex` options.
 .TP
+.BI "\-\-file-contexts=" file
+Specify a \fIfile_contexts\fR file to setup / override selinux labels.
+.TP
 .B \-\-help
 Display this help and exit.
 .SH AUTHOR
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 9ce06d6..97ba148 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -3,8 +3,8 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = mkfs.erofs
-AM_CPPFLAGS = ${libuuid_CFLAGS}
+AM_CPPFLAGS = ${libuuid_CFLAGS} ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
-mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS}
+mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} ${libselinux_LIBS}
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 940d4e8..94bf1e6 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -33,6 +33,9 @@ static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
 	{"exclude-path", required_argument, NULL, 2},
 	{"exclude-regex", required_argument, NULL, 3},
+#ifdef HAVE_LIBSELINUX
+	{"file-contexts", required_argument, NULL, 4},
+#endif
 	{0, 0, 0, 0},
 };
 
@@ -60,6 +63,9 @@ static void usage(void)
 	      " -T#               set a fixed UNIX timestamp # to all files\n"
 	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
 	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
+#ifdef HAVE_LIBSELINUX
+	      " --file-contexts=X specify a file contexts file to setup selinux labels\n"
+#endif
 	      " --help            display this help and exit\n"
 	      "\nAvailable compressors are: ", stderr);
 	print_available_compressors(stderr, ", ");
@@ -198,6 +204,13 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				return opt;
 			}
 			break;
+
+		case 4:
+			opt = erofs_selabel_open(optarg);
+			if (opt && opt != -EBUSY)
+				return opt;
+			break;
+
 		case 1:
 			usage();
 			exit(0);
@@ -392,7 +405,7 @@ int main(int argc, char **argv)
 	}
 
 	erofs_show_config();
-	erofs_exclude_set_root(cfg.c_src_path);
+	erofs_set_fs_root(cfg.c_src_path);
 
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
-- 
2.18.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] erofs-utils: support selinux file contexts
  2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
@ 2020-06-07  9:25   ` Li GuiFu via Linux-erofs
  2020-06-07  9:51     ` Gao Xiang
  2020-06-07 11:49   ` Li GuiFu via Linux-erofs
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Li GuiFu via Linux-erofs @ 2020-06-07  9:25 UTC (permalink / raw)
  To: Gao Xiang, linux-erofs; +Cc: Shung Wang

It cacuses one build error in my Ubuntu 18.04.1 LTS
and it seems selinux static lib link cause it
libtool: link: gcc -Wall -Werror -I../include -g -O2 -static -o
mkfs.erofs mkfs_erofs-main.o  ../lib/.libs/liberofs.a
-L/home/liguifu/codes/lz4 -luuid -lselinux -llz4
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(seusers.o):
In function `getseuserbyname':
(.text+0x5e9): warning: Using 'getgrouplist' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
(.text+0x570): warning: Using 'getgrnam_r' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
(.text+0x9e): warning: Using 'getpwnam_r' in statically linked
applications requires at runtime the shared libraries from the glibc
version used for linking
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_writef':
(.text+0x73): undefined reference to `pcre_fullinfo'
(.text+0xe7): undefined reference to `pcre_fullinfo'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_data_free':
(.text+0x1da): undefined reference to `pcre_free'
(.text+0x1e8): undefined reference to `pcre_free_study'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_prepare_data':
(.text+0x248): undefined reference to `pcre_compile'
(.text+0x269): undefined reference to `pcre_study'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_load_mmap':
(.text+0x36a): undefined reference to `pcre_fullinfo'
(.text+0x3df): undefined reference to `pcre_fullinfo'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_match':
(.text+0x48b): undefined reference to `pcre_exec'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_cmp':
(.text+0x4ed): undefined reference to `pcre_fullinfo'
(.text+0x506): undefined reference to `pcre_fullinfo'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(regex.o):
In function `regex_version':
(.text+0x11): undefined reference to `pcre_version'
/usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(load_policy.o):
In function `selinux_mkload_policy':
(.text+0x134): undefined reference to `sepol_policy_kern_vers_max'
(.text+0x13d): undefined reference to `sepol_policy_kern_vers_min'
(.text+0x2f3): undefined reference to `sepol_policy_kern_vers_max'
(.text+0x2fc): undefined reference to `sepol_policy_kern_vers_min'
(.text+0x331): undefined reference to `sepol_policy_kern_vers_max'
(.text+0x33a): undefined reference to `sepol_policy_kern_vers_min'
(.text+0x3b2): undefined reference to `sepol_policy_file_create'
(.text+0x3c4): undefined reference to `sepol_policydb_create'
(.text+0x3e0): undefined reference to `sepol_policy_file_set_mem'
(.text+0x3ef): undefined reference to `sepol_policydb_read'
(.text+0x405): undefined reference to `sepol_policydb_set_vers'
(.text+0x41f): undefined reference to `sepol_policydb_to_image'
(.text+0x451): undefined reference to `sepol_policy_file_free'
(.text+0x45b): undefined reference to `sepol_policydb_free'
(.text+0x4a0): undefined reference to `sepol_policy_kern_vers_max'
(.text+0x4a9): undefined reference to `sepol_policy_kern_vers_min'
(.text+0x4bf): undefined reference to `sepol_policy_file_free'
(.text+0x4c9): undefined reference to `sepol_policydb_free'
(.text+0x5bf): undefined reference to `sepol_policy_file_free'
(.text+0x5d3): undefined reference to `sepol_policy_file_free'
(.text+0x5dd): undefined reference to `sepol_policydb_free'
(.text+0x6d9): undefined reference to `sepol_genbools_array'
(.text+0x73a): undefined reference to `sepol_genusers'
(.text+0x76e): undefined reference to `sepol_genbools'
collect2: error: ld returned 1 exit status
Makefile:398: recipe for target 'mkfs.erofs' failed

On 2020/6/6 16:17, Gao Xiang wrote:
> Add --file-contexts flag that allows passing a selinux
> file_context file to setup file selabels.
> 
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> changes since v1:
>  fix selinux error handing and wrap up selabel
>  open pointed out by Guifu;
> 
>  configure.ac           |  27 +++++++++
>  include/erofs/config.h |  21 +++++++
>  include/erofs/xattr.h  |   3 +-
>  lib/config.c           |  42 +++++++++++++
>  lib/exclude.c          |  12 +---
>  lib/inode.c            |   3 +-
>  lib/xattr.c            | 130 ++++++++++++++++++++++++++++++++---------
>  man/mkfs.erofs.1       |   3 +
>  mkfs/Makefile.am       |   4 +-
>  mkfs/main.c            |  15 ++++-
>  10 files changed, 217 insertions(+), 43 deletions(-)
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] erofs-utils: support selinux file contexts
  2020-06-07  9:25   ` Li GuiFu via Linux-erofs
@ 2020-06-07  9:51     ` Gao Xiang
  0 siblings, 0 replies; 11+ messages in thread
From: Gao Xiang @ 2020-06-07  9:51 UTC (permalink / raw)
  To: Li GuiFu; +Cc: linux-erofs, Shung Wang

Hi Guifu,

On Sun, Jun 07, 2020 at 05:25:12PM +0800, Li GuiFu wrote:
> It cacuses one build error in my Ubuntu 18.04.1 LTS
> and it seems selinux static lib link cause it
> libtool: link: gcc -Wall -Werror -I../include -g -O2 -static -o
> mkfs.erofs mkfs_erofs-main.o  ../lib/.libs/liberofs.a
> -L/home/liguifu/codes/lz4 -luuid -lselinux -llz4
> /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libselinux.a(seusers.o):
> In function `getseuserbyname':
> (.text+0x5e9): warning: Using 'getgrouplist' in statically linked
> applications requires at runtime the shared libraries from the glibc
> version used for linking

Did you apply the following patch as well?
https://lore.kernel.org/r/20200531034510.5019-1-hsiangkao@aol.com/

And then I think you need "make distclean", "./autogen.sh" and
"./configure" again.

Thanks,
Gao Xiang


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] erofs-utils: support selinux file contexts
  2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
  2020-06-07  9:25   ` Li GuiFu via Linux-erofs
@ 2020-06-07 11:49   ` Li GuiFu via Linux-erofs
  2020-06-07 14:07     ` Gao Xiang
  2020-06-07 14:59   ` Li Guifu
  2020-06-08 12:34   ` [PATCH v3] " Gao Xiang via Linux-erofs
  3 siblings, 1 reply; 11+ messages in thread
From: Li GuiFu via Linux-erofs @ 2020-06-07 11:49 UTC (permalink / raw)
  To: Gao Xiang, linux-erofs; +Cc: Shung Wang


On 2020/6/6 16:17, Gao Xiang wrote:
> Add --file-contexts flag that allows passing a selinux
> file_context file to setup file selabels.
>
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> changes since v1:
>  fix selinux error handing and wrap up selabel
>  open pointed out by Guifu;
>
>  configure.ac           |  27 +++++++++
>  include/erofs/config.h |  21 +++++++
>  include/erofs/xattr.h  |   3 +-
>  lib/config.c           |  42 +++++++++++++
>  lib/exclude.c          |  12 +---
>  lib/inode.c            |   3 +-
>  lib/xattr.c            | 130 ++++++++++++++++++++++++++++++++---------
>  man/mkfs.erofs.1       |   3 +
>  mkfs/Makefile.am       |   4 +-
>  mkfs/main.c            |  15 ++++-
>  10 files changed, 217 insertions(+), 43 deletions(-)
>
> diff --git a/configure.ac b/configure.ac
> index 870dfb9..5145971 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
>     [AS_HELP_STRING([--without-uuid],
>        [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
>  
> +AC_ARG_WITH(selinux,
> +   [AS_HELP_STRING([--with-selinux],
> +      [enable and build with selinux support @<:@default=no@:>@])],
> +   [case "$with_selinux" in
> +      yes|no) ;;
> +      *) AC_MSG_ERROR([invalid argument to --with-selinux])
> +      ;;
> +    esac], [with_selinux=no])
> Can "with_selinux" to be set as "auto" ? it can be decide by the host, selinux installed enable selinux feature
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] erofs-utils: support selinux file contexts
  2020-06-07 11:49   ` Li GuiFu via Linux-erofs
@ 2020-06-07 14:07     ` Gao Xiang
  0 siblings, 0 replies; 11+ messages in thread
From: Gao Xiang @ 2020-06-07 14:07 UTC (permalink / raw)
  To: Li GuiFu; +Cc: linux-erofs, Shung Wang

On Sun, Jun 07, 2020 at 07:49:57PM +0800, Li GuiFu via Linux-erofs wrote:
>
> On 2020/6/6 16:17, Gao Xiang wrote:
> > Can "with_selinux" to be set as "auto" ? it can be decide by the host, selinux installed enable selinux feature

As I said before, we don't support that feature. It's really unsafe.

I think you can try what f2fs-tools or some else did (e.g. just try
./configure --with-selinux without your selinux library.)

Thanks,
Gao Xiang

> >

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] erofs-utils: support selinux file contexts
  2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
  2020-06-07  9:25   ` Li GuiFu via Linux-erofs
  2020-06-07 11:49   ` Li GuiFu via Linux-erofs
@ 2020-06-07 14:59   ` Li Guifu
  2020-06-08 12:34   ` [PATCH v3] " Gao Xiang via Linux-erofs
  3 siblings, 0 replies; 11+ messages in thread
From: Li Guifu @ 2020-06-07 14:59 UTC (permalink / raw)
  To: Gao Xiang, linux-erofs; +Cc: Shung Wang

On 2020/6/6 16:17, Gao Xiang wrote:
> Add --file-contexts flag that allows passing a selinux
> file_context file to setup file selabels.
>
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> It looks good
> Reviewed-by: Li Guifu <bluce.lee@aliyun.com>
> Tested-by: Li Guifu <bluce.lee@aliyun.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v3] erofs-utils: support selinux file contexts
  2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
                     ` (2 preceding siblings ...)
  2020-06-07 14:59   ` Li Guifu
@ 2020-06-08 12:34   ` Gao Xiang via Linux-erofs
  2020-06-08 13:08     ` [PATCH v4] " Gao Xiang via Linux-erofs
  3 siblings, 1 reply; 11+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-06-08 12:34 UTC (permalink / raw)
  To: linux-erofs; +Cc: Li Guifu

From: Gao Xiang <hsiangkao@redhat.com>

Add --file-contexts flag that allows passing a selinux
file_context file to setup file selabels.

Reviewed-and-tested-by: Li Guifu <bluce.lee@aliyun.com>
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
changes since v2:
 - fix variable "secontext" memory leak in erofs_get_selabel_xattr.

 configure.ac           |  27 +++++++++
 include/erofs/config.h |  21 +++++++
 include/erofs/xattr.h  |   3 +-
 lib/config.c           |  42 +++++++++++++
 lib/exclude.c          |  12 +---
 lib/inode.c            |   3 +-
 lib/xattr.c            | 132 ++++++++++++++++++++++++++++++++---------
 man/mkfs.erofs.1       |   3 +
 mkfs/Makefile.am       |   4 +-
 mkfs/main.c            |  15 ++++-
 10 files changed, 219 insertions(+), 43 deletions(-)

diff --git a/configure.ac b/configure.ac
index 870dfb9..5145971 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
    [AS_HELP_STRING([--without-uuid],
       [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
 
+AC_ARG_WITH(selinux,
+   [AS_HELP_STRING([--with-selinux],
+      [enable and build with selinux support @<:@default=no@:>@])],
+   [case "$with_selinux" in
+      yes|no) ;;
+      *) AC_MSG_ERROR([invalid argument to --with-selinux])
+      ;;
+    esac], [with_selinux=no])
+
 # Checks for libraries.
 # Use customized LZ4 library path when specified.
 AC_ARG_WITH(lz4-incdir,
@@ -160,6 +169,20 @@ return 0;
   LIBS="${saved_LIBS}"
   CPPFLAGS="${saved_CPPFLAGS}"], [have_uuid="no"])
 
+# Configure selinux
+AS_IF([test "x$with_selinux" != "xno"], [
+  PKG_CHECK_MODULES([libselinux], [libselinux])
+  # Paranoia: don't trust the result reported by pkgconfig before trying out
+  saved_LIBS="$LIBS"
+  saved_CPPFLAGS=${CPPFLAGS}
+  CPPFLAGS="${libselinux_CFLAGS} ${CPPFLAGS}"
+  LIBS="${libselinux_LIBS} $LIBS"
+  AC_CHECK_LIB(selinux, selabel_lookup, [
+    have_selinux="yes" ], [
+    AC_MSG_ERROR([libselinux doesn't work properly])])
+  LIBS="${saved_LIBS}"
+  CPPFLAGS="${saved_CPPFLAGS}"], [have_selinux="no"])
+
 # Configure lz4
 test -z $LZ4_LIBS && LZ4_LIBS='-llz4'
 
@@ -199,6 +222,10 @@ if test "x$have_uuid" = "xyes"; then
   AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
 fi
 
+if test "x$have_selinux" = "xyes"; then
+  AC_DEFINE([HAVE_LIBSELINUX], 1, [Define to 1 if libselinux is found])
+fi
+
 if test "x${have_lz4}" = "xyes"; then
   AC_DEFINE([LZ4_ENABLED], [1], [Define to 1 if lz4 is enabled.])
 
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2be05ee..2f09749 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -10,6 +10,12 @@
 #define __EROFS_CONFIG_H
 
 #include "defs.h"
+#include "err.h"
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
 
 enum {
 	FORCE_INODE_COMPACT = 1,
@@ -22,6 +28,9 @@ struct erofs_configure {
 	bool c_dry_run;
 	bool c_legacy_compress;
 
+#ifdef HAVE_LIBSELINUX
+	struct selabel_handle *sehnd;
+#endif
 	/* related arguments for mkfs.erofs */
 	char *c_img_path;
 	char *c_src_path;
@@ -39,5 +48,17 @@ void erofs_init_configure(void);
 void erofs_show_config(void);
 void erofs_exit_configure(void);
 
+void erofs_set_fs_root(const char *rootdir);
+const char *erofs_fspath(const char *fullpath);
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts);
+#else
+static inline int erofs_selabel_open(const char *file_contexts)
+{
+	return -EINVAL;
+}
+#endif
+
 #endif
 
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 3dff1ea..2e99669 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -42,7 +42,8 @@
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs);
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs);
 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
 int erofs_build_shared_xattrs_from_path(const char *path);
 
diff --git a/lib/config.c b/lib/config.c
index cbbecce..da0c260 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -36,6 +36,48 @@ void erofs_show_config(void)
 
 void erofs_exit_configure(void)
 {
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd)
+		selabel_close(cfg.sehnd);
+#endif
+}
+
+static unsigned int fullpath_prefix;	/* root directory prefix length */
+
+void erofs_set_fs_root(const char *rootdir)
+{
+	fullpath_prefix = strlen(rootdir);
+}
+
+const char *erofs_fspath(const char *fullpath)
+{
+	const char *s = fullpath + fullpath_prefix;
+
+	while (*s == '/')
+		s++;
+	return s;
+}
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts)
+{
+	struct selinux_opt seopts[] = {
+		{ .type = SELABEL_OPT_PATH, .value = file_contexts }
+	};
+
+	if (cfg.sehnd) {
+		erofs_info("ignore duplicated file contexts \"%s\"",
+			   file_contexts);
+		return -EBUSY;
+	}
 
+	cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+	if (!cfg.sehnd) {
+		erofs_err("failed to open file contexts \"%s\"",
+			  file_contexts);
+		return -EINVAL;
+	}
+	return 0;
 }
+#endif
 
diff --git a/lib/exclude.c b/lib/exclude.c
index 47b467d..73b3720 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -17,13 +17,6 @@
 static LIST_HEAD(exclude_head);
 static LIST_HEAD(regex_exclude_head);
 
-static unsigned int rpathlen;		/* root directory prefix length */
-
-void erofs_exclude_set_root(const char *rootdir)
-{
-	rpathlen = strlen(rootdir);
-}
-
 static void dump_regerror(int errcode, const char *s, const regex_t *preg)
 {
 	char str[512];
@@ -120,10 +113,7 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
 		s = buf;
 	}
 
-	s += rpathlen;
-	while (*s == '/')
-		s++;
-
+	s = erofs_fspath(s);
 	list_for_each_entry(r, &exclude_head, list) {
 		if (!strcmp(r->pattern, s))
 			return r;
diff --git a/lib/inode.c b/lib/inode.c
index 7114023..dff5f2c 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -827,7 +827,8 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 	struct dirent *dp;
 	struct erofs_dentry *d;
 
-	ret = erofs_prepare_xattr_ibody(dir->i_srcpath, &dir->i_xattrs);
+	ret = erofs_prepare_xattr_ibody(dir->i_srcpath,
+					dir->i_mode, &dir->i_xattrs);
 	if (ret < 0)
 		return ERR_PTR(ret);
 	dir->xattr_isize = ret;
diff --git a/lib/xattr.c b/lib/xattr.c
index 1564016..543ed71 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -186,6 +186,49 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key,
 	return get_xattritem(prefix, kvbuf, len);
 }
 
+static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
+						  mode_t mode)
+{
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd) {
+		char *secontext;
+		int ret;
+		unsigned int len[2];
+		char *kvbuf, *fspath;
+
+		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
+		if (ret <= 0)
+			return ERR_PTR(-ENOMEM);
+
+		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
+		free(fspath);
+
+		if (ret) {
+			ret = -errno;
+			if (ret != -ENOENT) {
+				erofs_err("failed to lookup selabel for %s: %s",
+					  srcpath, erofs_strerror(ret));
+				return ERR_PTR(ret);
+			}
+			/* secontext = "u:object_r:unlabeled:s0"; */
+			return NULL;
+		}
+
+		len[0] = sizeof("selinux") - 1;
+		len[1] = strlen(secontext);
+		kvbuf = malloc(len[0] + len[1] + 1);
+		if (!kvbuf) {
+			free(secontext);
+			return ERR_PTR(-ENOMEM);
+		}
+		sprintf(kvbuf, "selinux%s", secontext);
+		free(secontext);
+		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
+	}
+#endif
+	return NULL;
+}
+
 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
 {
 	struct inode_xattr_node *node = malloc(sizeof(*node));
@@ -215,19 +258,48 @@ static int shared_xattr_add(struct xattr_item *item)
 	return ++shared_xattrs_count;
 }
 
-static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
+static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+{
+	if (ixattrs)
+		return inode_xattr_add(ixattrs, item);
+
+	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
+		int ret = shared_xattr_add(item);
+
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static bool erofs_is_skipped_xattr(const char *key)
+{
+#ifdef HAVE_LIBSELINUX
+	/* if sehnd is valid, selabels will be overridden */
+	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
+		return true;
+#endif
+	return false;
+}
+
+static int read_xattrs_from_file(const char *path, mode_t mode,
+				 struct list_head *ixattrs)
 {
-	int ret = 0;
-	char *keylst, *key;
 	ssize_t kllen = llistxattr(path, NULL, 0);
+	int ret;
+	char *keylst, *key, *klend;
+	unsigned int keylen;
+	struct xattr_item *item;
 
 	if (kllen < 0 && errno != ENODATA) {
 		erofs_err("llistxattr to get the size of names for %s failed",
 			  path);
 		return -errno;
 	}
+
+	ret = 0;
 	if (kllen <= 1)
-		return 0;
+		goto out;
 
 	keylst = malloc(kllen);
 	if (!keylst)
@@ -246,36 +318,42 @@ static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
 	 * attribute keys. Use the remaining buffer length to determine
 	 * the end of the list.
 	 */
-	key = keylst;
-	while (kllen > 0) {
-		unsigned int keylen = strlen(key);
-		struct xattr_item *item = parse_one_xattr(path, key, keylen);
+	klend = keylst + kllen;
+	ret = 0;
+
+	for (key = keylst; key != klend; key += keylen + 1) {
+		keylen = strlen(key);
+		if (erofs_is_skipped_xattr(key))
+			continue;
 
+		item = parse_one_xattr(path, key, keylen);
 		if (IS_ERR(item)) {
 			ret = PTR_ERR(item);
 			goto err;
 		}
 
-		if (ixattrs) {
-			ret = inode_xattr_add(ixattrs, item);
-			if (ret < 0)
-				goto err;
-		} else if (item->count == cfg.c_inline_xattr_tolerance + 1) {
-			ret = shared_xattr_add(item);
-			if (ret < 0)
-				goto err;
-			ret = 0;
-		}
-		kllen -= keylen + 1;
-		key += keylen + 1;
+		ret = erofs_xattr_add(ixattrs, item);
+		if (ret < 0)
+			goto err;
 	}
-err:
 	free(keylst);
+
+out:
+	/* if some selabel is avilable, need to add right now */
+	item = erofs_get_selabel_xattr(path, mode);
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+	if (item)
+		ret = erofs_xattr_add(ixattrs, item);
 	return ret;
 
+err:
+	free(keylst);
+	return ret;
 }
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs)
 {
 	int ret;
 	struct inode_xattr_node *node;
@@ -284,7 +362,7 @@ int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
 	if (cfg.c_inline_xattr_tolerance < 0)
 		return 0;
 
-	ret = read_xattrs_from_file(path, ixattrs);
+	ret = read_xattrs_from_file(path, mode, ixattrs);
 	if (ret < 0)
 		return ret;
 
@@ -345,16 +423,16 @@ static int erofs_count_all_xattrs_from_path(const char *path)
 			goto fail;
 		}
 
-		ret = read_xattrs_from_file(buf, NULL);
-		if (ret)
-			goto fail;
-
 		ret = lstat64(buf, &st);
 		if (ret) {
 			ret = -errno;
 			goto fail;
 		}
 
+		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
+		if (ret)
+			goto fail;
+
 		if (!S_ISDIR(st.st_mode))
 			continue;
 
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d47207a..891c5a8 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -60,6 +60,9 @@ You may give multiple `--exclude-path' options.
 Ignore files that match the given regular expression.
 You may give multiple `--exclude-regex` options.
 .TP
+.BI "\-\-file-contexts=" file
+Specify a \fIfile_contexts\fR file to setup / override selinux labels.
+.TP
 .B \-\-help
 Display this help and exit.
 .SH AUTHOR
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 9ce06d6..97ba148 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -3,8 +3,8 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = mkfs.erofs
-AM_CPPFLAGS = ${libuuid_CFLAGS}
+AM_CPPFLAGS = ${libuuid_CFLAGS} ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
-mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS}
+mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} ${libselinux_LIBS}
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 940d4e8..94bf1e6 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -33,6 +33,9 @@ static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
 	{"exclude-path", required_argument, NULL, 2},
 	{"exclude-regex", required_argument, NULL, 3},
+#ifdef HAVE_LIBSELINUX
+	{"file-contexts", required_argument, NULL, 4},
+#endif
 	{0, 0, 0, 0},
 };
 
@@ -60,6 +63,9 @@ static void usage(void)
 	      " -T#               set a fixed UNIX timestamp # to all files\n"
 	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
 	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
+#ifdef HAVE_LIBSELINUX
+	      " --file-contexts=X specify a file contexts file to setup selinux labels\n"
+#endif
 	      " --help            display this help and exit\n"
 	      "\nAvailable compressors are: ", stderr);
 	print_available_compressors(stderr, ", ");
@@ -198,6 +204,13 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				return opt;
 			}
 			break;
+
+		case 4:
+			opt = erofs_selabel_open(optarg);
+			if (opt && opt != -EBUSY)
+				return opt;
+			break;
+
 		case 1:
 			usage();
 			exit(0);
@@ -392,7 +405,7 @@ int main(int argc, char **argv)
 	}
 
 	erofs_show_config();
-	erofs_exclude_set_root(cfg.c_src_path);
+	erofs_set_fs_root(cfg.c_src_path);
 
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
-- 
2.24.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4] erofs-utils: support selinux file contexts
  2020-06-08 12:34   ` [PATCH v3] " Gao Xiang via Linux-erofs
@ 2020-06-08 13:08     ` Gao Xiang via Linux-erofs
  2020-06-08 15:51       ` Li GuiFu via Linux-erofs
  0 siblings, 1 reply; 11+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-06-08 13:08 UTC (permalink / raw)
  To: linux-erofs; +Cc: Li Guifu

From: Gao Xiang <hsiangkao@redhat.com>

Add --file-contexts flag that allows passing a selinux
file_context file to setup file selabels.

Reviewed-and-tested-by: Li Guifu <bluce.lee@aliyun.com>
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
---
v4: freecon() should be used instead of free(). (although
    they're equivalent, but that is what manpage prefers...)

 configure.ac           |  27 +++++++++
 include/erofs/config.h |  21 +++++++
 include/erofs/xattr.h  |   3 +-
 lib/config.c           |  42 +++++++++++++
 lib/exclude.c          |  12 +---
 lib/inode.c            |   3 +-
 lib/xattr.c            | 132 ++++++++++++++++++++++++++++++++---------
 man/mkfs.erofs.1       |   3 +
 mkfs/Makefile.am       |   4 +-
 mkfs/main.c            |  15 ++++-
 10 files changed, 219 insertions(+), 43 deletions(-)

diff --git a/configure.ac b/configure.ac
index 870dfb9..5145971 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,15 @@ AC_ARG_WITH(uuid,
    [AS_HELP_STRING([--without-uuid],
       [Ignore presence of libuuid and disable uuid support @<:@default=enabled@:>@])])
 
+AC_ARG_WITH(selinux,
+   [AS_HELP_STRING([--with-selinux],
+      [enable and build with selinux support @<:@default=no@:>@])],
+   [case "$with_selinux" in
+      yes|no) ;;
+      *) AC_MSG_ERROR([invalid argument to --with-selinux])
+      ;;
+    esac], [with_selinux=no])
+
 # Checks for libraries.
 # Use customized LZ4 library path when specified.
 AC_ARG_WITH(lz4-incdir,
@@ -160,6 +169,20 @@ return 0;
   LIBS="${saved_LIBS}"
   CPPFLAGS="${saved_CPPFLAGS}"], [have_uuid="no"])
 
+# Configure selinux
+AS_IF([test "x$with_selinux" != "xno"], [
+  PKG_CHECK_MODULES([libselinux], [libselinux])
+  # Paranoia: don't trust the result reported by pkgconfig before trying out
+  saved_LIBS="$LIBS"
+  saved_CPPFLAGS=${CPPFLAGS}
+  CPPFLAGS="${libselinux_CFLAGS} ${CPPFLAGS}"
+  LIBS="${libselinux_LIBS} $LIBS"
+  AC_CHECK_LIB(selinux, selabel_lookup, [
+    have_selinux="yes" ], [
+    AC_MSG_ERROR([libselinux doesn't work properly])])
+  LIBS="${saved_LIBS}"
+  CPPFLAGS="${saved_CPPFLAGS}"], [have_selinux="no"])
+
 # Configure lz4
 test -z $LZ4_LIBS && LZ4_LIBS='-llz4'
 
@@ -199,6 +222,10 @@ if test "x$have_uuid" = "xyes"; then
   AC_DEFINE([HAVE_LIBUUID], 1, [Define to 1 if libuuid is found])
 fi
 
+if test "x$have_selinux" = "xyes"; then
+  AC_DEFINE([HAVE_LIBSELINUX], 1, [Define to 1 if libselinux is found])
+fi
+
 if test "x${have_lz4}" = "xyes"; then
   AC_DEFINE([LZ4_ENABLED], [1], [Define to 1 if lz4 is enabled.])
 
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 2be05ee..2f09749 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -10,6 +10,12 @@
 #define __EROFS_CONFIG_H
 
 #include "defs.h"
+#include "err.h"
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
 
 enum {
 	FORCE_INODE_COMPACT = 1,
@@ -22,6 +28,9 @@ struct erofs_configure {
 	bool c_dry_run;
 	bool c_legacy_compress;
 
+#ifdef HAVE_LIBSELINUX
+	struct selabel_handle *sehnd;
+#endif
 	/* related arguments for mkfs.erofs */
 	char *c_img_path;
 	char *c_src_path;
@@ -39,5 +48,17 @@ void erofs_init_configure(void);
 void erofs_show_config(void);
 void erofs_exit_configure(void);
 
+void erofs_set_fs_root(const char *rootdir);
+const char *erofs_fspath(const char *fullpath);
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts);
+#else
+static inline int erofs_selabel_open(const char *file_contexts)
+{
+	return -EINVAL;
+}
+#endif
+
 #endif
 
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 3dff1ea..2e99669 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -42,7 +42,8 @@
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs);
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs);
 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
 int erofs_build_shared_xattrs_from_path(const char *path);
 
diff --git a/lib/config.c b/lib/config.c
index cbbecce..da0c260 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -36,6 +36,48 @@ void erofs_show_config(void)
 
 void erofs_exit_configure(void)
 {
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd)
+		selabel_close(cfg.sehnd);
+#endif
+}
+
+static unsigned int fullpath_prefix;	/* root directory prefix length */
+
+void erofs_set_fs_root(const char *rootdir)
+{
+	fullpath_prefix = strlen(rootdir);
+}
+
+const char *erofs_fspath(const char *fullpath)
+{
+	const char *s = fullpath + fullpath_prefix;
+
+	while (*s == '/')
+		s++;
+	return s;
+}
+
+#ifdef HAVE_LIBSELINUX
+int erofs_selabel_open(const char *file_contexts)
+{
+	struct selinux_opt seopts[] = {
+		{ .type = SELABEL_OPT_PATH, .value = file_contexts }
+	};
+
+	if (cfg.sehnd) {
+		erofs_info("ignore duplicated file contexts \"%s\"",
+			   file_contexts);
+		return -EBUSY;
+	}
 
+	cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+	if (!cfg.sehnd) {
+		erofs_err("failed to open file contexts \"%s\"",
+			  file_contexts);
+		return -EINVAL;
+	}
+	return 0;
 }
+#endif
 
diff --git a/lib/exclude.c b/lib/exclude.c
index 47b467d..73b3720 100644
--- a/lib/exclude.c
+++ b/lib/exclude.c
@@ -17,13 +17,6 @@
 static LIST_HEAD(exclude_head);
 static LIST_HEAD(regex_exclude_head);
 
-static unsigned int rpathlen;		/* root directory prefix length */
-
-void erofs_exclude_set_root(const char *rootdir)
-{
-	rpathlen = strlen(rootdir);
-}
-
 static void dump_regerror(int errcode, const char *s, const regex_t *preg)
 {
 	char str[512];
@@ -120,10 +113,7 @@ struct erofs_exclude_rule *erofs_is_exclude_path(const char *dir,
 		s = buf;
 	}
 
-	s += rpathlen;
-	while (*s == '/')
-		s++;
-
+	s = erofs_fspath(s);
 	list_for_each_entry(r, &exclude_head, list) {
 		if (!strcmp(r->pattern, s))
 			return r;
diff --git a/lib/inode.c b/lib/inode.c
index 7114023..dff5f2c 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -827,7 +827,8 @@ struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 	struct dirent *dp;
 	struct erofs_dentry *d;
 
-	ret = erofs_prepare_xattr_ibody(dir->i_srcpath, &dir->i_xattrs);
+	ret = erofs_prepare_xattr_ibody(dir->i_srcpath,
+					dir->i_mode, &dir->i_xattrs);
 	if (ret < 0)
 		return ERR_PTR(ret);
 	dir->xattr_isize = ret;
diff --git a/lib/xattr.c b/lib/xattr.c
index 1564016..aa614f6 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -186,6 +186,49 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key,
 	return get_xattritem(prefix, kvbuf, len);
 }
 
+static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
+						  mode_t mode)
+{
+#ifdef HAVE_LIBSELINUX
+	if (cfg.sehnd) {
+		char *secontext;
+		int ret;
+		unsigned int len[2];
+		char *kvbuf, *fspath;
+
+		ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
+		if (ret <= 0)
+			return ERR_PTR(-ENOMEM);
+
+		ret = selabel_lookup(cfg.sehnd, &secontext, fspath, mode);
+		free(fspath);
+
+		if (ret) {
+			ret = -errno;
+			if (ret != -ENOENT) {
+				erofs_err("failed to lookup selabel for %s: %s",
+					  srcpath, erofs_strerror(ret));
+				return ERR_PTR(ret);
+			}
+			/* secontext = "u:object_r:unlabeled:s0"; */
+			return NULL;
+		}
+
+		len[0] = sizeof("selinux") - 1;
+		len[1] = strlen(secontext);
+		kvbuf = malloc(len[0] + len[1] + 1);
+		if (!kvbuf) {
+			freecon(secontext);
+			return ERR_PTR(-ENOMEM);
+		}
+		sprintf(kvbuf, "selinux%s", secontext);
+		freecon(secontext);
+		return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len);
+	}
+#endif
+	return NULL;
+}
+
 static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
 {
 	struct inode_xattr_node *node = malloc(sizeof(*node));
@@ -215,19 +258,48 @@ static int shared_xattr_add(struct xattr_item *item)
 	return ++shared_xattrs_count;
 }
 
-static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
+static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+{
+	if (ixattrs)
+		return inode_xattr_add(ixattrs, item);
+
+	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
+		int ret = shared_xattr_add(item);
+
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+static bool erofs_is_skipped_xattr(const char *key)
+{
+#ifdef HAVE_LIBSELINUX
+	/* if sehnd is valid, selabels will be overridden */
+	if (cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
+		return true;
+#endif
+	return false;
+}
+
+static int read_xattrs_from_file(const char *path, mode_t mode,
+				 struct list_head *ixattrs)
 {
-	int ret = 0;
-	char *keylst, *key;
 	ssize_t kllen = llistxattr(path, NULL, 0);
+	int ret;
+	char *keylst, *key, *klend;
+	unsigned int keylen;
+	struct xattr_item *item;
 
 	if (kllen < 0 && errno != ENODATA) {
 		erofs_err("llistxattr to get the size of names for %s failed",
 			  path);
 		return -errno;
 	}
+
+	ret = 0;
 	if (kllen <= 1)
-		return 0;
+		goto out;
 
 	keylst = malloc(kllen);
 	if (!keylst)
@@ -246,36 +318,42 @@ static int read_xattrs_from_file(const char *path, struct list_head *ixattrs)
 	 * attribute keys. Use the remaining buffer length to determine
 	 * the end of the list.
 	 */
-	key = keylst;
-	while (kllen > 0) {
-		unsigned int keylen = strlen(key);
-		struct xattr_item *item = parse_one_xattr(path, key, keylen);
+	klend = keylst + kllen;
+	ret = 0;
+
+	for (key = keylst; key != klend; key += keylen + 1) {
+		keylen = strlen(key);
+		if (erofs_is_skipped_xattr(key))
+			continue;
 
+		item = parse_one_xattr(path, key, keylen);
 		if (IS_ERR(item)) {
 			ret = PTR_ERR(item);
 			goto err;
 		}
 
-		if (ixattrs) {
-			ret = inode_xattr_add(ixattrs, item);
-			if (ret < 0)
-				goto err;
-		} else if (item->count == cfg.c_inline_xattr_tolerance + 1) {
-			ret = shared_xattr_add(item);
-			if (ret < 0)
-				goto err;
-			ret = 0;
-		}
-		kllen -= keylen + 1;
-		key += keylen + 1;
+		ret = erofs_xattr_add(ixattrs, item);
+		if (ret < 0)
+			goto err;
 	}
-err:
 	free(keylst);
+
+out:
+	/* if some selabel is avilable, need to add right now */
+	item = erofs_get_selabel_xattr(path, mode);
+	if (IS_ERR(item))
+		return PTR_ERR(item);
+	if (item)
+		ret = erofs_xattr_add(ixattrs, item);
 	return ret;
 
+err:
+	free(keylst);
+	return ret;
 }
 
-int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
+int erofs_prepare_xattr_ibody(const char *path, mode_t mode,
+			      struct list_head *ixattrs)
 {
 	int ret;
 	struct inode_xattr_node *node;
@@ -284,7 +362,7 @@ int erofs_prepare_xattr_ibody(const char *path, struct list_head *ixattrs)
 	if (cfg.c_inline_xattr_tolerance < 0)
 		return 0;
 
-	ret = read_xattrs_from_file(path, ixattrs);
+	ret = read_xattrs_from_file(path, mode, ixattrs);
 	if (ret < 0)
 		return ret;
 
@@ -345,16 +423,16 @@ static int erofs_count_all_xattrs_from_path(const char *path)
 			goto fail;
 		}
 
-		ret = read_xattrs_from_file(buf, NULL);
-		if (ret)
-			goto fail;
-
 		ret = lstat64(buf, &st);
 		if (ret) {
 			ret = -errno;
 			goto fail;
 		}
 
+		ret = read_xattrs_from_file(buf, st.st_mode, NULL);
+		if (ret)
+			goto fail;
+
 		if (!S_ISDIR(st.st_mode))
 			continue;
 
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d47207a..891c5a8 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -60,6 +60,9 @@ You may give multiple `--exclude-path' options.
 Ignore files that match the given regular expression.
 You may give multiple `--exclude-regex` options.
 .TP
+.BI "\-\-file-contexts=" file
+Specify a \fIfile_contexts\fR file to setup / override selinux labels.
+.TP
 .B \-\-help
 Display this help and exit.
 .SH AUTHOR
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 9ce06d6..97ba148 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -3,8 +3,8 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = mkfs.erofs
-AM_CPPFLAGS = ${libuuid_CFLAGS}
+AM_CPPFLAGS = ${libuuid_CFLAGS} ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
-mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS}
+mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libuuid_LIBS} ${libselinux_LIBS}
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 940d4e8..94bf1e6 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -33,6 +33,9 @@ static struct option long_options[] = {
 	{"help", no_argument, 0, 1},
 	{"exclude-path", required_argument, NULL, 2},
 	{"exclude-regex", required_argument, NULL, 3},
+#ifdef HAVE_LIBSELINUX
+	{"file-contexts", required_argument, NULL, 4},
+#endif
 	{0, 0, 0, 0},
 };
 
@@ -60,6 +63,9 @@ static void usage(void)
 	      " -T#               set a fixed UNIX timestamp # to all files\n"
 	      " --exclude-path=X  avoid including file X (X = exact literal path)\n"
 	      " --exclude-regex=X avoid including files that match X (X = regular expression)\n"
+#ifdef HAVE_LIBSELINUX
+	      " --file-contexts=X specify a file contexts file to setup selinux labels\n"
+#endif
 	      " --help            display this help and exit\n"
 	      "\nAvailable compressors are: ", stderr);
 	print_available_compressors(stderr, ", ");
@@ -198,6 +204,13 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 				return opt;
 			}
 			break;
+
+		case 4:
+			opt = erofs_selabel_open(optarg);
+			if (opt && opt != -EBUSY)
+				return opt;
+			break;
+
 		case 1:
 			usage();
 			exit(0);
@@ -392,7 +405,7 @@ int main(int argc, char **argv)
 	}
 
 	erofs_show_config();
-	erofs_exclude_set_root(cfg.c_src_path);
+	erofs_set_fs_root(cfg.c_src_path);
 
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
-- 
2.24.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4] erofs-utils: support selinux file contexts
  2020-06-08 13:08     ` [PATCH v4] " Gao Xiang via Linux-erofs
@ 2020-06-08 15:51       ` Li GuiFu via Linux-erofs
  0 siblings, 0 replies; 11+ messages in thread
From: Li GuiFu via Linux-erofs @ 2020-06-08 15:51 UTC (permalink / raw)
  To: hsiangkao, linux-erofs


On 2020/6/8 21:08, hsiangkao@aol.com wrote:
> From: Gao Xiang <hsiangkao@redhat.com>
> 
> Add --file-contexts flag that allows passing a selinux
> file_context file to setup file selabels.
> 
> Reviewed-and-tested-by: Li Guifu <bluce.lee@aliyun.com>
> Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
> ---
> v4: freecon() should be used instead of free(). (although
>     they're equivalent, but that is what manpage prefers...)
> 
It looks good
Reviewed-by: Li Guifu <bluce.lee@aliyun.com>
Tested-by: Li Guifu <bluce.lee@aliyun.com>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, back to index

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-30 16:11 [PATCH] erofs-utils: support selinux file contexts Gao Xiang
     [not found] ` <fb53174b-605c-b893-a2b0-d5a76132e244@aliyun.com>
2020-06-04  1:36   ` Gao Xiang
2020-06-06  8:17 ` [PATCH v2] " Gao Xiang
2020-06-07  9:25   ` Li GuiFu via Linux-erofs
2020-06-07  9:51     ` Gao Xiang
2020-06-07 11:49   ` Li GuiFu via Linux-erofs
2020-06-07 14:07     ` Gao Xiang
2020-06-07 14:59   ` Li Guifu
2020-06-08 12:34   ` [PATCH v3] " Gao Xiang via Linux-erofs
2020-06-08 13:08     ` [PATCH v4] " Gao Xiang via Linux-erofs
2020-06-08 15:51       ` Li GuiFu via Linux-erofs

Linux-EROFS Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-erofs/0 linux-erofs/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-erofs linux-erofs/ https://lore.kernel.org/linux-erofs \
		linux-erofs@lists.ozlabs.org linux-erofs@ozlabs.org
	public-inbox-index linux-erofs

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.ozlabs.lists.linux-erofs


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git