All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon
@ 2022-05-05 17:44 Christian Göttsche
  2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
  2022-05-11 19:09 ` [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon James Carter
  0 siblings, 2 replies; 14+ messages in thread
From: Christian Göttsche @ 2022-05-05 17:44 UTC (permalink / raw)
  To: selinux

Operating on a file descriptor avoids TOCTOU issues and one opened via
O_PATH avoids the requirement of having read access to the file.  Since
Linux does not natively support file descriptors opened via O_PATH in
fgetxattr(2) and at least glibc and musl does not emulate O_PATH support
in their implementations, fgetfilecon(3) and fsetfilecon(3) also do not
currently support file descriptors opened with O_PATH.

Inspired by CVE-2013-4392: https://github.com/systemd/systemd/pull/8583
Implementation adapted from: https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204%5E%21/

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/man/man3/getfilecon.3 |  4 +++-
 libselinux/man/man3/setfilecon.3 |  4 +++-
 libselinux/src/fgetfilecon.c     | 28 +++++++++++++++++++++++++---
 libselinux/src/fsetfilecon.c     | 23 ++++++++++++++++++++++-
 4 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/libselinux/man/man3/getfilecon.3 b/libselinux/man/man3/getfilecon.3
index 5bb575b5..c3e92ba1 100644
--- a/libselinux/man/man3/getfilecon.3
+++ b/libselinux/man/man3/getfilecon.3
@@ -33,7 +33,9 @@ is identical to
 .BR getfilecon (),
 only the open file pointed to by filedes (as returned by
 .BR open (2))
-is interrogated in place of path.
+is interrogated in place of path.  Since libselinux 3.4 a file opened via
+.I O_PATH
+is supported.
 
 .BR getfilecon_raw (),
 .BR lgetfilecon_raw ()
diff --git a/libselinux/man/man3/setfilecon.3 b/libselinux/man/man3/setfilecon.3
index 0e9a383f..61f9a806 100644
--- a/libselinux/man/man3/setfilecon.3
+++ b/libselinux/man/man3/setfilecon.3
@@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to.
 is identical to setfilecon, only the open file pointed to by filedes (as
 returned by
 .BR open (2))
-has it's context set in place of path.
+has it's context set in place of path.  Since libselinux 3.4 a file opened via
+.I O_PATH
+is supported.
 
 .BR setfilecon_raw (),
 .BR lsetfilecon_raw (),
diff --git a/libselinux/src/fgetfilecon.c b/libselinux/src/fgetfilecon.c
index 8c748f8a..baf38ec1 100644
--- a/libselinux/src/fgetfilecon.c
+++ b/libselinux/src/fgetfilecon.c
@@ -3,10 +3,32 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <stdio.h>
 #include <sys/xattr.h>
 #include "selinux_internal.h"
 #include "policy.h"
 
+static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
+	char buf[40];
+	int fd_flag, saved_errno = errno;
+	ssize_t ret;
+
+	ret = fgetxattr(fd, name, value, size);
+	if (ret != -1 || errno != EBADF)
+		return ret;
+
+	/* Emulate O_PATH support */
+	fd_flag = fcntl(fd, F_GETFL);
+	if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
+		errno = EBADF;
+		return -1;
+	}
+
+	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+	errno = saved_errno;
+	return getxattr(buf, name, value, size);
+}
+
 int fgetfilecon_raw(int fd, char ** context)
 {
 	char *buf;
@@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context)
 		return -1;
 	memset(buf, 0, size);
 
-	ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
+	ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
 	if (ret < 0 && errno == ERANGE) {
 		char *newbuf;
 
-		size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
+		size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
 		if (size < 0)
 			goto out;
 
@@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context)
 
 		buf = newbuf;
 		memset(buf, 0, size);
-		ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
+		ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
 	}
       out:
 	if (ret == 0) {
diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c
index 5cf34e3f..be821c7a 100644
--- a/libselinux/src/fsetfilecon.c
+++ b/libselinux/src/fsetfilecon.c
@@ -3,13 +3,34 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <stdio.h>
 #include <sys/xattr.h>
 #include "selinux_internal.h"
 #include "policy.h"
 
+static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) {
+	char buf[40];
+	int rc, fd_flag, saved_errno = errno;
+
+	rc = fsetxattr(fd, name, value, size, flags);
+	if (rc == 0 || errno != EBADF)
+		return rc;
+
+	/* Emulate O_PATH support */
+	fd_flag = fcntl(fd, F_GETFL);
+	if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
+		errno = EBADF;
+		return -1;
+	}
+
+	snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+	errno = saved_errno;
+	return setxattr(buf, name, value, size, flags);
+}
+
 int fsetfilecon_raw(int fd, const char * context)
 {
-	int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
+	int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
 			 0);
 	if (rc < 0 && errno == ENOTSUP) {
 		char * ccontext = NULL;
-- 
2.36.0


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

* [RFC PATCH 2/4] libselinux: restorecon: misc tweaks
  2022-05-05 17:44 [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon Christian Göttsche
@ 2022-05-11 18:42 ` Christian Göttsche
  2022-05-11 18:42   ` [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT Christian Göttsche
                     ` (2 more replies)
  2022-05-11 19:09 ` [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon James Carter
  1 sibling, 3 replies; 14+ messages in thread
From: Christian Göttsche @ 2022-05-11 18:42 UTC (permalink / raw)
  To: selinux

* mark read-only parameters const
* check for overflow when adding exclude directory
* use 64 bit integer for file counting
* avoid implicit conversions

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/src/selinux_restorecon.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index e6192912..c158ead8 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -44,7 +44,7 @@
 static struct selabel_handle *fc_sehandle = NULL;
 static bool selabel_no_digest;
 static char *rootpath = NULL;
-static int rootpathlen;
+static size_t rootpathlen;
 
 /* Information on excluded fs and directories. */
 struct edir {
@@ -55,7 +55,7 @@ struct edir {
 };
 #define CALLER_EXCLUDED true
 static bool ignore_mounts;
-static int exclude_non_seclabel_mounts(void);
+static uint64_t exclude_non_seclabel_mounts(void);
 static int exclude_count = 0;
 static struct edir *exclude_lst = NULL;
 static uint64_t fc_count = 0;	/* Number of files processed so far */
@@ -169,6 +169,12 @@ static int add_exclude(const char *directory, bool who)
 		return -1;
 	}
 
+	if (exclude_count >= INT_MAX - 1) {
+		selinux_log(SELINUX_ERROR, "Too many directory excludes: %d.\n", exclude_count);
+		errno = EOVERFLOW;
+		return -1;
+	}
+
 	tmp_list = realloc(exclude_lst,
 			   sizeof(struct edir) * (exclude_count + 1));
 	if (!tmp_list)
@@ -211,10 +217,10 @@ static int check_excluded(const char *file)
 	return 0;
 }
 
-static int file_system_count(char *name)
+static uint64_t file_system_count(const char *name)
 {
 	struct statvfs statvfs_buf;
-	int nfile = 0;
+	uint64_t nfile = 0;
 
 	memset(&statvfs_buf, 0, sizeof(statvfs_buf));
 	if (!statvfs(name, &statvfs_buf))
@@ -230,12 +236,13 @@ static int file_system_count(char *name)
  * that support security labels have the seclabel option, return
  * approximate total file count.
  */
-static int exclude_non_seclabel_mounts(void)
+static uint64_t exclude_non_seclabel_mounts(void)
 {
 	struct utsname uts;
 	FILE *fp;
 	size_t len;
-	int index = 0, found = 0, nfile = 0;
+	int index = 0, found = 0;
+	uint64_t nfile = 0;
 	char *mount_info[4];
 	char *buf = NULL, *item;
 
@@ -300,7 +307,8 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch,
 {
 	char *sha1_buf = NULL;
 	size_t i, digest_len = 0;
-	int rc, digest_result;
+	int rc;
+	enum digest_result digest_result;
 	bool match;
 	struct dir_xattr *new_entry;
 	uint8_t *xattr_digest = NULL;
@@ -573,7 +581,7 @@ static void filespec_destroy(void)
  * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
  * the type components differ, updating newtypecon if so.
  */
-static int compare_types(char *curcon, char *newcon, char **newtypecon)
+static int compare_types(const char *curcon, const char *newcon, char **newtypecon)
 {
 	int types_differ = 0;
 	context_t cona;
@@ -1398,7 +1406,7 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list)
 /* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
 int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
 {
-	int len;
+	size_t len;
 
 	/* This should be NULL on first use */
 	if (rootpath)
-- 
2.36.1


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

* [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT
  2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
@ 2022-05-11 18:42   ` Christian Göttsche
  2022-05-12 17:39     ` James Carter
  2022-05-11 18:42   ` [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues Christian Göttsche
  2022-05-12 17:38   ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks James Carter
  2 siblings, 1 reply; 14+ messages in thread
From: Christian Göttsche @ 2022-05-11 18:42 UTC (permalink / raw)
  To: selinux

selabel_lookup_raw(3) can fail for other reasons than no corresponding
context found, e.g. ENOMEM or EINVAL for invalid key or type.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/src/selinux_restorecon.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index c158ead8..42ef30cb 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -651,12 +651,16 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 						    sb->st_mode);
 
 	if (rc < 0) {
-		if (errno == ENOENT && flags->warnonnomatch && first)
-			selinux_log(SELINUX_INFO,
-				    "Warning no default label for %s\n",
-				    lookup_path);
+		if (errno == ENOENT) {
+			if (flags->warnonnomatch && first)
+				selinux_log(SELINUX_INFO,
+					    "Warning no default label for %s\n",
+					    lookup_path);
 
-		return 0; /* no match, but not an error */
+			return 0; /* no match, but not an error */
+		}
+
+		return -1;
 	}
 
 	if (flags->progress) {
-- 
2.36.1


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

* [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues
  2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
  2022-05-11 18:42   ` [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT Christian Göttsche
@ 2022-05-11 18:42   ` Christian Göttsche
  2022-05-12 17:39     ` James Carter
  2022-05-12 17:38   ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks James Carter
  2 siblings, 1 reply; 14+ messages in thread
From: Christian Göttsche @ 2022-05-11 18:42 UTC (permalink / raw)
  To: selinux

Pin the file to operate on in restorecon_sb() to prevent symlink attacks
in between the label database lookup, the current context query and the
final context write.  Also don't use the file information from
fts_read(3), which might also be out of sync.

Due to querying file information twice, one in fts_read(3) needed for
the cross device check and one on the pinned file descriptor for the
database lookup, there is a slight slowdown:

    [current]
    Time (mean ± σ):     14.456 s ±  0.306 s    [User: 45.863 s, System: 4.463 s]
    Range (min … max):   14.275 s … 15.294 s    10 runs

    [changed]
    Time (mean ± σ):     15.843 s ±  0.045 s    [User: 46.274 s, System: 9.495 s]
    Range (min … max):   15.787 s … 15.916 s    10 runs

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libselinux/src/selinux_restorecon.c | 43 +++++++++++++++++------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 42ef30cb..12b85101 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -621,13 +621,13 @@ out:
 	return rc;
 }
 
-static int restorecon_sb(const char *pathname, const struct stat *sb,
-			    struct rest_flags *flags, bool first)
+static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
 {
 	char *newcon = NULL;
 	char *curcon = NULL;
 	char *newtypecon = NULL;
-	int rc;
+	int fd = -1, rc;
+	struct stat stat_buf;
 	bool updated = false;
 	const char *lookup_path = pathname;
 	float pc;
@@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 		lookup_path += rootpathlen;
 	}
 
+	fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL);
+	if (fd < 0)
+		goto err;
+
+	rc = fstat(fd, &stat_buf);
+	if (rc < 0)
+		goto err;
+
 	if (rootpath != NULL && lookup_path[0] == '\0')
 		/* this is actually the root dir of the alt root. */
 		rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
-						    sb->st_mode);
+						    stat_buf.st_mode);
 	else
 		rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
-						    sb->st_mode);
+						    stat_buf.st_mode);
 
 	if (rc < 0) {
 		if (errno == ENOENT) {
@@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 					    "Warning no default label for %s\n",
 					    lookup_path);
 
-			return 0; /* no match, but not an error */
+			goto out; /* no match, but not an error */
 		}
 
-		return -1;
+		goto err;
 	}
 
 	if (flags->progress) {
@@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 	}
 
 	if (flags->add_assoc) {
-		rc = filespec_add(sb->st_ino, newcon, pathname, flags);
+		rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
 
 		if (rc < 0) {
 			selinux_log(SELINUX_ERROR,
 				    "filespec_add error: %s\n", pathname);
-			freecon(newcon);
-			return -1;
+			goto out1;
 		}
 
 		if (rc > 0) {
 			/* Already an association and it took precedence. */
-			freecon(newcon);
-			return 0;
+			goto out;
 		}
 	}
 
@@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 		selinux_log(SELINUX_INFO, "%s matched by %s\n",
 			    pathname, newcon);
 
-	if (lgetfilecon_raw(pathname, &curcon) < 0) {
+	if (fgetfilecon_raw(fd, &curcon) < 0) {
 		if (errno != ENODATA)
 			goto err;
 
@@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 		}
 
 		if (!flags->nochange) {
-			if (lsetfilecon(pathname, newcon) < 0)
+			if (fsetfilecon(fd, newcon) < 0)
 				goto err;
 			updated = true;
 		}
@@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
 out:
 	rc = 0;
 out1:
+	if (fd >= 0)
+		close(fd);
 	freecon(curcon);
 	freecon(newcon);
 	return rc;
@@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg)
 	FTSENT *ftsent;
 	int error;
 	char ent_path[PATH_MAX];
-	struct stat ent_st;
 	bool first = false;
 
 	if (state->parallel)
@@ -953,11 +960,11 @@ loop_body:
 			/* fall through */
 		default:
 			strcpy(ent_path, ftsent->fts_path);
-			ent_st = *ftsent->fts_statp;
+
 			if (state->parallel)
 				pthread_mutex_unlock(&state->mutex);
 
-			error = restorecon_sb(ent_path, &ent_st, &state->flags,
+			error = restorecon_sb(ent_path, &state->flags,
 					      first);
 
 			if (state->parallel) {
@@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
 			goto cleanup;
 		}
 
-		error = restorecon_sb(pathname, &sb, &state.flags, true);
+		error = restorecon_sb(pathname, &state.flags, true);
 		goto cleanup;
 	}
 
-- 
2.36.1


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

* Re: [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon
  2022-05-05 17:44 [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon Christian Göttsche
  2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
@ 2022-05-11 19:09 ` James Carter
  2022-05-16 17:07   ` James Carter
  1 sibling, 1 reply; 14+ messages in thread
From: James Carter @ 2022-05-11 19:09 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Sun, May 8, 2022 at 3:19 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Operating on a file descriptor avoids TOCTOU issues and one opened via
> O_PATH avoids the requirement of having read access to the file.  Since
> Linux does not natively support file descriptors opened via O_PATH in
> fgetxattr(2) and at least glibc and musl does not emulate O_PATH support
> in their implementations, fgetfilecon(3) and fsetfilecon(3) also do not
> currently support file descriptors opened with O_PATH.
>
> Inspired by CVE-2013-4392: https://github.com/systemd/systemd/pull/8583
> Implementation adapted from: https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204%5E%21/
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>

Works as advertised.

Acked-by: James Carter <jwcart2@gmail.com>

> ---
>  libselinux/man/man3/getfilecon.3 |  4 +++-
>  libselinux/man/man3/setfilecon.3 |  4 +++-
>  libselinux/src/fgetfilecon.c     | 28 +++++++++++++++++++++++++---
>  libselinux/src/fsetfilecon.c     | 23 ++++++++++++++++++++++-
>  4 files changed, 53 insertions(+), 6 deletions(-)
>
> diff --git a/libselinux/man/man3/getfilecon.3 b/libselinux/man/man3/getfilecon.3
> index 5bb575b5..c3e92ba1 100644
> --- a/libselinux/man/man3/getfilecon.3
> +++ b/libselinux/man/man3/getfilecon.3
> @@ -33,7 +33,9 @@ is identical to
>  .BR getfilecon (),
>  only the open file pointed to by filedes (as returned by
>  .BR open (2))
> -is interrogated in place of path.
> +is interrogated in place of path.  Since libselinux 3.4 a file opened via
> +.I O_PATH
> +is supported.
>
>  .BR getfilecon_raw (),
>  .BR lgetfilecon_raw ()
> diff --git a/libselinux/man/man3/setfilecon.3 b/libselinux/man/man3/setfilecon.3
> index 0e9a383f..61f9a806 100644
> --- a/libselinux/man/man3/setfilecon.3
> +++ b/libselinux/man/man3/setfilecon.3
> @@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to.
>  is identical to setfilecon, only the open file pointed to by filedes (as
>  returned by
>  .BR open (2))
> -has it's context set in place of path.
> +has it's context set in place of path.  Since libselinux 3.4 a file opened via
> +.I O_PATH
> +is supported.
>
>  .BR setfilecon_raw (),
>  .BR lsetfilecon_raw (),
> diff --git a/libselinux/src/fgetfilecon.c b/libselinux/src/fgetfilecon.c
> index 8c748f8a..baf38ec1 100644
> --- a/libselinux/src/fgetfilecon.c
> +++ b/libselinux/src/fgetfilecon.c
> @@ -3,10 +3,32 @@
>  #include <string.h>
>  #include <stdlib.h>
>  #include <errno.h>
> +#include <stdio.h>
>  #include <sys/xattr.h>
>  #include "selinux_internal.h"
>  #include "policy.h"
>
> +static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
> +       char buf[40];
> +       int fd_flag, saved_errno = errno;
> +       ssize_t ret;
> +
> +       ret = fgetxattr(fd, name, value, size);
> +       if (ret != -1 || errno != EBADF)
> +               return ret;
> +
> +       /* Emulate O_PATH support */
> +       fd_flag = fcntl(fd, F_GETFL);
> +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> +               errno = EBADF;
> +               return -1;
> +       }
> +
> +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> +       errno = saved_errno;
> +       return getxattr(buf, name, value, size);
> +}
> +
>  int fgetfilecon_raw(int fd, char ** context)
>  {
>         char *buf;
> @@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context)
>                 return -1;
>         memset(buf, 0, size);
>
> -       ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> +       ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
>         if (ret < 0 && errno == ERANGE) {
>                 char *newbuf;
>
> -               size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
> +               size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
>                 if (size < 0)
>                         goto out;
>
> @@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context)
>
>                 buf = newbuf;
>                 memset(buf, 0, size);
> -               ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> +               ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
>         }
>        out:
>         if (ret == 0) {
> diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c
> index 5cf34e3f..be821c7a 100644
> --- a/libselinux/src/fsetfilecon.c
> +++ b/libselinux/src/fsetfilecon.c
> @@ -3,13 +3,34 @@
>  #include <string.h>
>  #include <stdlib.h>
>  #include <errno.h>
> +#include <stdio.h>
>  #include <sys/xattr.h>
>  #include "selinux_internal.h"
>  #include "policy.h"
>
> +static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) {
> +       char buf[40];
> +       int rc, fd_flag, saved_errno = errno;
> +
> +       rc = fsetxattr(fd, name, value, size, flags);
> +       if (rc == 0 || errno != EBADF)
> +               return rc;
> +
> +       /* Emulate O_PATH support */
> +       fd_flag = fcntl(fd, F_GETFL);
> +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> +               errno = EBADF;
> +               return -1;
> +       }
> +
> +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> +       errno = saved_errno;
> +       return setxattr(buf, name, value, size, flags);
> +}
> +
>  int fsetfilecon_raw(int fd, const char * context)
>  {
> -       int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
> +       int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
>                          0);
>         if (rc < 0 && errno == ENOTSUP) {
>                 char * ccontext = NULL;
> --
> 2.36.0
>

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

* Re: [RFC PATCH 2/4] libselinux: restorecon: misc tweaks
  2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
  2022-05-11 18:42   ` [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT Christian Göttsche
  2022-05-11 18:42   ` [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues Christian Göttsche
@ 2022-05-12 17:38   ` James Carter
  2022-05-16 17:10     ` James Carter
  2 siblings, 1 reply; 14+ messages in thread
From: James Carter @ 2022-05-12 17:38 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Wed, May 11, 2022 at 7:58 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> * mark read-only parameters const
> * check for overflow when adding exclude directory
> * use 64 bit integer for file counting
> * avoid implicit conversions
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>

Acked-by: James Carter <jwcart2@gmail.com>

> ---
>  libselinux/src/selinux_restorecon.c | 26 +++++++++++++++++---------
>  1 file changed, 17 insertions(+), 9 deletions(-)
>
> diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> index e6192912..c158ead8 100644
> --- a/libselinux/src/selinux_restorecon.c
> +++ b/libselinux/src/selinux_restorecon.c
> @@ -44,7 +44,7 @@
>  static struct selabel_handle *fc_sehandle = NULL;
>  static bool selabel_no_digest;
>  static char *rootpath = NULL;
> -static int rootpathlen;
> +static size_t rootpathlen;
>
>  /* Information on excluded fs and directories. */
>  struct edir {
> @@ -55,7 +55,7 @@ struct edir {
>  };
>  #define CALLER_EXCLUDED true
>  static bool ignore_mounts;
> -static int exclude_non_seclabel_mounts(void);
> +static uint64_t exclude_non_seclabel_mounts(void);
>  static int exclude_count = 0;
>  static struct edir *exclude_lst = NULL;
>  static uint64_t fc_count = 0;  /* Number of files processed so far */
> @@ -169,6 +169,12 @@ static int add_exclude(const char *directory, bool who)
>                 return -1;
>         }
>
> +       if (exclude_count >= INT_MAX - 1) {
> +               selinux_log(SELINUX_ERROR, "Too many directory excludes: %d.\n", exclude_count);
> +               errno = EOVERFLOW;
> +               return -1;
> +       }
> +
>         tmp_list = realloc(exclude_lst,
>                            sizeof(struct edir) * (exclude_count + 1));
>         if (!tmp_list)
> @@ -211,10 +217,10 @@ static int check_excluded(const char *file)
>         return 0;
>  }
>
> -static int file_system_count(char *name)
> +static uint64_t file_system_count(const char *name)
>  {
>         struct statvfs statvfs_buf;
> -       int nfile = 0;
> +       uint64_t nfile = 0;
>
>         memset(&statvfs_buf, 0, sizeof(statvfs_buf));
>         if (!statvfs(name, &statvfs_buf))
> @@ -230,12 +236,13 @@ static int file_system_count(char *name)
>   * that support security labels have the seclabel option, return
>   * approximate total file count.
>   */
> -static int exclude_non_seclabel_mounts(void)
> +static uint64_t exclude_non_seclabel_mounts(void)
>  {
>         struct utsname uts;
>         FILE *fp;
>         size_t len;
> -       int index = 0, found = 0, nfile = 0;
> +       int index = 0, found = 0;
> +       uint64_t nfile = 0;
>         char *mount_info[4];
>         char *buf = NULL, *item;
>
> @@ -300,7 +307,8 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch,
>  {
>         char *sha1_buf = NULL;
>         size_t i, digest_len = 0;
> -       int rc, digest_result;
> +       int rc;
> +       enum digest_result digest_result;
>         bool match;
>         struct dir_xattr *new_entry;
>         uint8_t *xattr_digest = NULL;
> @@ -573,7 +581,7 @@ static void filespec_destroy(void)
>   * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
>   * the type components differ, updating newtypecon if so.
>   */
> -static int compare_types(char *curcon, char *newcon, char **newtypecon)
> +static int compare_types(const char *curcon, const char *newcon, char **newtypecon)
>  {
>         int types_differ = 0;
>         context_t cona;
> @@ -1398,7 +1406,7 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list)
>  /* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
>  int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
>  {
> -       int len;
> +       size_t len;
>
>         /* This should be NULL on first use */
>         if (rootpath)
> --
> 2.36.1
>

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

* Re: [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT
  2022-05-11 18:42   ` [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT Christian Göttsche
@ 2022-05-12 17:39     ` James Carter
  2022-05-16 17:10       ` James Carter
  0 siblings, 1 reply; 14+ messages in thread
From: James Carter @ 2022-05-12 17:39 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, May 12, 2022 at 5:54 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> selabel_lookup_raw(3) can fail for other reasons than no corresponding
> context found, e.g. ENOMEM or EINVAL for invalid key or type.
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>

Acked-by: James Carter <jwcart2@gmail.com>

> ---
>  libselinux/src/selinux_restorecon.c | 14 +++++++++-----
>  1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> index c158ead8..42ef30cb 100644
> --- a/libselinux/src/selinux_restorecon.c
> +++ b/libselinux/src/selinux_restorecon.c
> @@ -651,12 +651,16 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>                                                     sb->st_mode);
>
>         if (rc < 0) {
> -               if (errno == ENOENT && flags->warnonnomatch && first)
> -                       selinux_log(SELINUX_INFO,
> -                                   "Warning no default label for %s\n",
> -                                   lookup_path);
> +               if (errno == ENOENT) {
> +                       if (flags->warnonnomatch && first)
> +                               selinux_log(SELINUX_INFO,
> +                                           "Warning no default label for %s\n",
> +                                           lookup_path);
>
> -               return 0; /* no match, but not an error */
> +                       return 0; /* no match, but not an error */
> +               }
> +
> +               return -1;
>         }
>
>         if (flags->progress) {
> --
> 2.36.1
>

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

* Re: [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues
  2022-05-11 18:42   ` [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues Christian Göttsche
@ 2022-05-12 17:39     ` James Carter
  2022-05-16 17:12       ` James Carter
  0 siblings, 1 reply; 14+ messages in thread
From: James Carter @ 2022-05-12 17:39 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Wed, May 11, 2022 at 3:32 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Pin the file to operate on in restorecon_sb() to prevent symlink attacks
> in between the label database lookup, the current context query and the
> final context write.  Also don't use the file information from
> fts_read(3), which might also be out of sync.
>
> Due to querying file information twice, one in fts_read(3) needed for
> the cross device check and one on the pinned file descriptor for the
> database lookup, there is a slight slowdown:
>
>     [current]
>     Time (mean ± σ):     14.456 s ±  0.306 s    [User: 45.863 s, System: 4.463 s]
>     Range (min … max):   14.275 s … 15.294 s    10 runs
>
>     [changed]
>     Time (mean ± σ):     15.843 s ±  0.045 s    [User: 46.274 s, System: 9.495 s]
>     Range (min … max):   15.787 s … 15.916 s    10 runs
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>

Acked-by: James Carter <jwcart2@gmail.com>

> ---
>  libselinux/src/selinux_restorecon.c | 43 +++++++++++++++++------------
>  1 file changed, 25 insertions(+), 18 deletions(-)
>
> diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> index 42ef30cb..12b85101 100644
> --- a/libselinux/src/selinux_restorecon.c
> +++ b/libselinux/src/selinux_restorecon.c
> @@ -621,13 +621,13 @@ out:
>         return rc;
>  }
>
> -static int restorecon_sb(const char *pathname, const struct stat *sb,
> -                           struct rest_flags *flags, bool first)
> +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
>  {
>         char *newcon = NULL;
>         char *curcon = NULL;
>         char *newtypecon = NULL;
> -       int rc;
> +       int fd = -1, rc;
> +       struct stat stat_buf;
>         bool updated = false;
>         const char *lookup_path = pathname;
>         float pc;
> @@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>                 lookup_path += rootpathlen;
>         }
>
> +       fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL);
> +       if (fd < 0)
> +               goto err;
> +
> +       rc = fstat(fd, &stat_buf);
> +       if (rc < 0)
> +               goto err;
> +
>         if (rootpath != NULL && lookup_path[0] == '\0')
>                 /* this is actually the root dir of the alt root. */
>                 rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
> -                                                   sb->st_mode);
> +                                                   stat_buf.st_mode);
>         else
>                 rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
> -                                                   sb->st_mode);
> +                                                   stat_buf.st_mode);
>
>         if (rc < 0) {
>                 if (errno == ENOENT) {
> @@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>                                             "Warning no default label for %s\n",
>                                             lookup_path);
>
> -                       return 0; /* no match, but not an error */
> +                       goto out; /* no match, but not an error */
>                 }
>
> -               return -1;
> +               goto err;
>         }
>
>         if (flags->progress) {
> @@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>         }
>
>         if (flags->add_assoc) {
> -               rc = filespec_add(sb->st_ino, newcon, pathname, flags);
> +               rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
>
>                 if (rc < 0) {
>                         selinux_log(SELINUX_ERROR,
>                                     "filespec_add error: %s\n", pathname);
> -                       freecon(newcon);
> -                       return -1;
> +                       goto out1;
>                 }
>
>                 if (rc > 0) {
>                         /* Already an association and it took precedence. */
> -                       freecon(newcon);
> -                       return 0;
> +                       goto out;
>                 }
>         }
>
> @@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>                 selinux_log(SELINUX_INFO, "%s matched by %s\n",
>                             pathname, newcon);
>
> -       if (lgetfilecon_raw(pathname, &curcon) < 0) {
> +       if (fgetfilecon_raw(fd, &curcon) < 0) {
>                 if (errno != ENODATA)
>                         goto err;
>
> @@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>                 }
>
>                 if (!flags->nochange) {
> -                       if (lsetfilecon(pathname, newcon) < 0)
> +                       if (fsetfilecon(fd, newcon) < 0)
>                                 goto err;
>                         updated = true;
>                 }
> @@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
>  out:
>         rc = 0;
>  out1:
> +       if (fd >= 0)
> +               close(fd);
>         freecon(curcon);
>         freecon(newcon);
>         return rc;
> @@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg)
>         FTSENT *ftsent;
>         int error;
>         char ent_path[PATH_MAX];
> -       struct stat ent_st;
>         bool first = false;
>
>         if (state->parallel)
> @@ -953,11 +960,11 @@ loop_body:
>                         /* fall through */
>                 default:
>                         strcpy(ent_path, ftsent->fts_path);
> -                       ent_st = *ftsent->fts_statp;
> +
>                         if (state->parallel)
>                                 pthread_mutex_unlock(&state->mutex);
>
> -                       error = restorecon_sb(ent_path, &ent_st, &state->flags,
> +                       error = restorecon_sb(ent_path, &state->flags,
>                                               first);
>
>                         if (state->parallel) {
> @@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
>                         goto cleanup;
>                 }
>
> -               error = restorecon_sb(pathname, &sb, &state.flags, true);
> +               error = restorecon_sb(pathname, &state.flags, true);
>                 goto cleanup;
>         }
>
> --
> 2.36.1
>

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

* Re: [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon
  2022-05-11 19:09 ` [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon James Carter
@ 2022-05-16 17:07   ` James Carter
  0 siblings, 0 replies; 14+ messages in thread
From: James Carter @ 2022-05-16 17:07 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Wed, May 11, 2022 at 3:09 PM James Carter <jwcart2@gmail.com> wrote:
>
> On Sun, May 8, 2022 at 3:19 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > Operating on a file descriptor avoids TOCTOU issues and one opened via
> > O_PATH avoids the requirement of having read access to the file.  Since
> > Linux does not natively support file descriptors opened via O_PATH in
> > fgetxattr(2) and at least glibc and musl does not emulate O_PATH support
> > in their implementations, fgetfilecon(3) and fsetfilecon(3) also do not
> > currently support file descriptors opened with O_PATH.
> >
> > Inspired by CVE-2013-4392: https://github.com/systemd/systemd/pull/8583
> > Implementation adapted from: https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204%5E%21/
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
> Works as advertised.
>
> Acked-by: James Carter <jwcart2@gmail.com>
>

Merged.
Thanks,
Jim

> > ---
> >  libselinux/man/man3/getfilecon.3 |  4 +++-
> >  libselinux/man/man3/setfilecon.3 |  4 +++-
> >  libselinux/src/fgetfilecon.c     | 28 +++++++++++++++++++++++++---
> >  libselinux/src/fsetfilecon.c     | 23 ++++++++++++++++++++++-
> >  4 files changed, 53 insertions(+), 6 deletions(-)
> >
> > diff --git a/libselinux/man/man3/getfilecon.3 b/libselinux/man/man3/getfilecon.3
> > index 5bb575b5..c3e92ba1 100644
> > --- a/libselinux/man/man3/getfilecon.3
> > +++ b/libselinux/man/man3/getfilecon.3
> > @@ -33,7 +33,9 @@ is identical to
> >  .BR getfilecon (),
> >  only the open file pointed to by filedes (as returned by
> >  .BR open (2))
> > -is interrogated in place of path.
> > +is interrogated in place of path.  Since libselinux 3.4 a file opened via
> > +.I O_PATH
> > +is supported.
> >
> >  .BR getfilecon_raw (),
> >  .BR lgetfilecon_raw ()
> > diff --git a/libselinux/man/man3/setfilecon.3 b/libselinux/man/man3/setfilecon.3
> > index 0e9a383f..61f9a806 100644
> > --- a/libselinux/man/man3/setfilecon.3
> > +++ b/libselinux/man/man3/setfilecon.3
> > @@ -29,7 +29,9 @@ link itself has it's context set, not the file that it refers to.
> >  is identical to setfilecon, only the open file pointed to by filedes (as
> >  returned by
> >  .BR open (2))
> > -has it's context set in place of path.
> > +has it's context set in place of path.  Since libselinux 3.4 a file opened via
> > +.I O_PATH
> > +is supported.
> >
> >  .BR setfilecon_raw (),
> >  .BR lsetfilecon_raw (),
> > diff --git a/libselinux/src/fgetfilecon.c b/libselinux/src/fgetfilecon.c
> > index 8c748f8a..baf38ec1 100644
> > --- a/libselinux/src/fgetfilecon.c
> > +++ b/libselinux/src/fgetfilecon.c
> > @@ -3,10 +3,32 @@
> >  #include <string.h>
> >  #include <stdlib.h>
> >  #include <errno.h>
> > +#include <stdio.h>
> >  #include <sys/xattr.h>
> >  #include "selinux_internal.h"
> >  #include "policy.h"
> >
> > +static ssize_t fgetxattr_wrapper(int fd, const char *name, void *value, size_t size) {
> > +       char buf[40];
> > +       int fd_flag, saved_errno = errno;
> > +       ssize_t ret;
> > +
> > +       ret = fgetxattr(fd, name, value, size);
> > +       if (ret != -1 || errno != EBADF)
> > +               return ret;
> > +
> > +       /* Emulate O_PATH support */
> > +       fd_flag = fcntl(fd, F_GETFL);
> > +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> > +               errno = EBADF;
> > +               return -1;
> > +       }
> > +
> > +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> > +       errno = saved_errno;
> > +       return getxattr(buf, name, value, size);
> > +}
> > +
> >  int fgetfilecon_raw(int fd, char ** context)
> >  {
> >         char *buf;
> > @@ -19,11 +41,11 @@ int fgetfilecon_raw(int fd, char ** context)
> >                 return -1;
> >         memset(buf, 0, size);
> >
> > -       ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> > +       ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
> >         if (ret < 0 && errno == ERANGE) {
> >                 char *newbuf;
> >
> > -               size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
> > +               size = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, NULL, 0);
> >                 if (size < 0)
> >                         goto out;
> >
> > @@ -34,7 +56,7 @@ int fgetfilecon_raw(int fd, char ** context)
> >
> >                 buf = newbuf;
> >                 memset(buf, 0, size);
> > -               ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
> > +               ret = fgetxattr_wrapper(fd, XATTR_NAME_SELINUX, buf, size - 1);
> >         }
> >        out:
> >         if (ret == 0) {
> > diff --git a/libselinux/src/fsetfilecon.c b/libselinux/src/fsetfilecon.c
> > index 5cf34e3f..be821c7a 100644
> > --- a/libselinux/src/fsetfilecon.c
> > +++ b/libselinux/src/fsetfilecon.c
> > @@ -3,13 +3,34 @@
> >  #include <string.h>
> >  #include <stdlib.h>
> >  #include <errno.h>
> > +#include <stdio.h>
> >  #include <sys/xattr.h>
> >  #include "selinux_internal.h"
> >  #include "policy.h"
> >
> > +static int fsetxattr_wrapper(int fd, const char* name, const void* value, size_t size, int flags) {
> > +       char buf[40];
> > +       int rc, fd_flag, saved_errno = errno;
> > +
> > +       rc = fsetxattr(fd, name, value, size, flags);
> > +       if (rc == 0 || errno != EBADF)
> > +               return rc;
> > +
> > +       /* Emulate O_PATH support */
> > +       fd_flag = fcntl(fd, F_GETFL);
> > +       if (fd_flag == -1 || (fd_flag & O_PATH) == 0) {
> > +               errno = EBADF;
> > +               return -1;
> > +       }
> > +
> > +       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
> > +       errno = saved_errno;
> > +       return setxattr(buf, name, value, size, flags);
> > +}
> > +
> >  int fsetfilecon_raw(int fd, const char * context)
> >  {
> > -       int rc = fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
> > +       int rc = fsetxattr_wrapper(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
> >                          0);
> >         if (rc < 0 && errno == ENOTSUP) {
> >                 char * ccontext = NULL;
> > --
> > 2.36.0
> >

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

* Re: [RFC PATCH 2/4] libselinux: restorecon: misc tweaks
  2022-05-12 17:38   ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks James Carter
@ 2022-05-16 17:10     ` James Carter
  0 siblings, 0 replies; 14+ messages in thread
From: James Carter @ 2022-05-16 17:10 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, May 12, 2022 at 1:38 PM James Carter <jwcart2@gmail.com> wrote:
>
> On Wed, May 11, 2022 at 7:58 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > * mark read-only parameters const
> > * check for overflow when adding exclude directory
> > * use 64 bit integer for file counting
> > * avoid implicit conversions
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
> Acked-by: James Carter <jwcart2@gmail.com>
>

Merged.
Thanks,
Jim


> > ---
> >  libselinux/src/selinux_restorecon.c | 26 +++++++++++++++++---------
> >  1 file changed, 17 insertions(+), 9 deletions(-)
> >
> > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> > index e6192912..c158ead8 100644
> > --- a/libselinux/src/selinux_restorecon.c
> > +++ b/libselinux/src/selinux_restorecon.c
> > @@ -44,7 +44,7 @@
> >  static struct selabel_handle *fc_sehandle = NULL;
> >  static bool selabel_no_digest;
> >  static char *rootpath = NULL;
> > -static int rootpathlen;
> > +static size_t rootpathlen;
> >
> >  /* Information on excluded fs and directories. */
> >  struct edir {
> > @@ -55,7 +55,7 @@ struct edir {
> >  };
> >  #define CALLER_EXCLUDED true
> >  static bool ignore_mounts;
> > -static int exclude_non_seclabel_mounts(void);
> > +static uint64_t exclude_non_seclabel_mounts(void);
> >  static int exclude_count = 0;
> >  static struct edir *exclude_lst = NULL;
> >  static uint64_t fc_count = 0;  /* Number of files processed so far */
> > @@ -169,6 +169,12 @@ static int add_exclude(const char *directory, bool who)
> >                 return -1;
> >         }
> >
> > +       if (exclude_count >= INT_MAX - 1) {
> > +               selinux_log(SELINUX_ERROR, "Too many directory excludes: %d.\n", exclude_count);
> > +               errno = EOVERFLOW;
> > +               return -1;
> > +       }
> > +
> >         tmp_list = realloc(exclude_lst,
> >                            sizeof(struct edir) * (exclude_count + 1));
> >         if (!tmp_list)
> > @@ -211,10 +217,10 @@ static int check_excluded(const char *file)
> >         return 0;
> >  }
> >
> > -static int file_system_count(char *name)
> > +static uint64_t file_system_count(const char *name)
> >  {
> >         struct statvfs statvfs_buf;
> > -       int nfile = 0;
> > +       uint64_t nfile = 0;
> >
> >         memset(&statvfs_buf, 0, sizeof(statvfs_buf));
> >         if (!statvfs(name, &statvfs_buf))
> > @@ -230,12 +236,13 @@ static int file_system_count(char *name)
> >   * that support security labels have the seclabel option, return
> >   * approximate total file count.
> >   */
> > -static int exclude_non_seclabel_mounts(void)
> > +static uint64_t exclude_non_seclabel_mounts(void)
> >  {
> >         struct utsname uts;
> >         FILE *fp;
> >         size_t len;
> > -       int index = 0, found = 0, nfile = 0;
> > +       int index = 0, found = 0;
> > +       uint64_t nfile = 0;
> >         char *mount_info[4];
> >         char *buf = NULL, *item;
> >
> > @@ -300,7 +307,8 @@ static int add_xattr_entry(const char *directory, bool delete_nonmatch,
> >  {
> >         char *sha1_buf = NULL;
> >         size_t i, digest_len = 0;
> > -       int rc, digest_result;
> > +       int rc;
> > +       enum digest_result digest_result;
> >         bool match;
> >         struct dir_xattr *new_entry;
> >         uint8_t *xattr_digest = NULL;
> > @@ -573,7 +581,7 @@ static void filespec_destroy(void)
> >   * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
> >   * the type components differ, updating newtypecon if so.
> >   */
> > -static int compare_types(char *curcon, char *newcon, char **newtypecon)
> > +static int compare_types(const char *curcon, const char *newcon, char **newtypecon)
> >  {
> >         int types_differ = 0;
> >         context_t cona;
> > @@ -1398,7 +1406,7 @@ void selinux_restorecon_set_exclude_list(const char **exclude_list)
> >  /* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
> >  int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
> >  {
> > -       int len;
> > +       size_t len;
> >
> >         /* This should be NULL on first use */
> >         if (rootpath)
> > --
> > 2.36.1
> >

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

* Re: [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT
  2022-05-12 17:39     ` James Carter
@ 2022-05-16 17:10       ` James Carter
  0 siblings, 0 replies; 14+ messages in thread
From: James Carter @ 2022-05-16 17:10 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, May 12, 2022 at 1:39 PM James Carter <jwcart2@gmail.com> wrote:
>
> On Thu, May 12, 2022 at 5:54 AM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > selabel_lookup_raw(3) can fail for other reasons than no corresponding
> > context found, e.g. ENOMEM or EINVAL for invalid key or type.
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
> Acked-by: James Carter <jwcart2@gmail.com>
>

Merged.
Thanks,
Jim


> > ---
> >  libselinux/src/selinux_restorecon.c | 14 +++++++++-----
> >  1 file changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> > index c158ead8..42ef30cb 100644
> > --- a/libselinux/src/selinux_restorecon.c
> > +++ b/libselinux/src/selinux_restorecon.c
> > @@ -651,12 +651,16 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >                                                     sb->st_mode);
> >
> >         if (rc < 0) {
> > -               if (errno == ENOENT && flags->warnonnomatch && first)
> > -                       selinux_log(SELINUX_INFO,
> > -                                   "Warning no default label for %s\n",
> > -                                   lookup_path);
> > +               if (errno == ENOENT) {
> > +                       if (flags->warnonnomatch && first)
> > +                               selinux_log(SELINUX_INFO,
> > +                                           "Warning no default label for %s\n",
> > +                                           lookup_path);
> >
> > -               return 0; /* no match, but not an error */
> > +                       return 0; /* no match, but not an error */
> > +               }
> > +
> > +               return -1;
> >         }
> >
> >         if (flags->progress) {
> > --
> > 2.36.1
> >

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

* Re: [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues
  2022-05-12 17:39     ` James Carter
@ 2022-05-16 17:12       ` James Carter
  2022-05-16 19:01         ` Christian Göttsche
  0 siblings, 1 reply; 14+ messages in thread
From: James Carter @ 2022-05-16 17:12 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Thu, May 12, 2022 at 1:39 PM James Carter <jwcart2@gmail.com> wrote:
>
> On Wed, May 11, 2022 at 3:32 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > Pin the file to operate on in restorecon_sb() to prevent symlink attacks
> > in between the label database lookup, the current context query and the
> > final context write.  Also don't use the file information from
> > fts_read(3), which might also be out of sync.
> >
> > Due to querying file information twice, one in fts_read(3) needed for
> > the cross device check and one on the pinned file descriptor for the
> > database lookup, there is a slight slowdown:
> >
> >     [current]
> >     Time (mean ± σ):     14.456 s ±  0.306 s    [User: 45.863 s, System: 4.463 s]
> >     Range (min … max):   14.275 s … 15.294 s    10 runs
> >
> >     [changed]
> >     Time (mean ± σ):     15.843 s ±  0.045 s    [User: 46.274 s, System: 9.495 s]
> >     Range (min … max):   15.787 s … 15.916 s    10 runs
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
> Acked-by: James Carter <jwcart2@gmail.com>
>

Merged.
Thanks,
Jim

> > ---
> >  libselinux/src/selinux_restorecon.c | 43 +++++++++++++++++------------
> >  1 file changed, 25 insertions(+), 18 deletions(-)
> >
> > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> > index 42ef30cb..12b85101 100644
> > --- a/libselinux/src/selinux_restorecon.c
> > +++ b/libselinux/src/selinux_restorecon.c
> > @@ -621,13 +621,13 @@ out:
> >         return rc;
> >  }
> >
> > -static int restorecon_sb(const char *pathname, const struct stat *sb,
> > -                           struct rest_flags *flags, bool first)
> > +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
> >  {
> >         char *newcon = NULL;
> >         char *curcon = NULL;
> >         char *newtypecon = NULL;
> > -       int rc;
> > +       int fd = -1, rc;
> > +       struct stat stat_buf;
> >         bool updated = false;
> >         const char *lookup_path = pathname;
> >         float pc;
> > @@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >                 lookup_path += rootpathlen;
> >         }
> >
> > +       fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL);
> > +       if (fd < 0)
> > +               goto err;
> > +
> > +       rc = fstat(fd, &stat_buf);
> > +       if (rc < 0)
> > +               goto err;
> > +
> >         if (rootpath != NULL && lookup_path[0] == '\0')
> >                 /* this is actually the root dir of the alt root. */
> >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
> > -                                                   sb->st_mode);
> > +                                                   stat_buf.st_mode);
> >         else
> >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
> > -                                                   sb->st_mode);
> > +                                                   stat_buf.st_mode);
> >
> >         if (rc < 0) {
> >                 if (errno == ENOENT) {
> > @@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >                                             "Warning no default label for %s\n",
> >                                             lookup_path);
> >
> > -                       return 0; /* no match, but not an error */
> > +                       goto out; /* no match, but not an error */
> >                 }
> >
> > -               return -1;
> > +               goto err;
> >         }
> >
> >         if (flags->progress) {
> > @@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >         }
> >
> >         if (flags->add_assoc) {
> > -               rc = filespec_add(sb->st_ino, newcon, pathname, flags);
> > +               rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
> >
> >                 if (rc < 0) {
> >                         selinux_log(SELINUX_ERROR,
> >                                     "filespec_add error: %s\n", pathname);
> > -                       freecon(newcon);
> > -                       return -1;
> > +                       goto out1;
> >                 }
> >
> >                 if (rc > 0) {
> >                         /* Already an association and it took precedence. */
> > -                       freecon(newcon);
> > -                       return 0;
> > +                       goto out;
> >                 }
> >         }
> >
> > @@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >                 selinux_log(SELINUX_INFO, "%s matched by %s\n",
> >                             pathname, newcon);
> >
> > -       if (lgetfilecon_raw(pathname, &curcon) < 0) {
> > +       if (fgetfilecon_raw(fd, &curcon) < 0) {
> >                 if (errno != ENODATA)
> >                         goto err;
> >
> > @@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >                 }
> >
> >                 if (!flags->nochange) {
> > -                       if (lsetfilecon(pathname, newcon) < 0)
> > +                       if (fsetfilecon(fd, newcon) < 0)
> >                                 goto err;
> >                         updated = true;
> >                 }
> > @@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> >  out:
> >         rc = 0;
> >  out1:
> > +       if (fd >= 0)
> > +               close(fd);
> >         freecon(curcon);
> >         freecon(newcon);
> >         return rc;
> > @@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg)
> >         FTSENT *ftsent;
> >         int error;
> >         char ent_path[PATH_MAX];
> > -       struct stat ent_st;
> >         bool first = false;
> >
> >         if (state->parallel)
> > @@ -953,11 +960,11 @@ loop_body:
> >                         /* fall through */
> >                 default:
> >                         strcpy(ent_path, ftsent->fts_path);
> > -                       ent_st = *ftsent->fts_statp;
> > +
> >                         if (state->parallel)
> >                                 pthread_mutex_unlock(&state->mutex);
> >
> > -                       error = restorecon_sb(ent_path, &ent_st, &state->flags,
> > +                       error = restorecon_sb(ent_path, &state->flags,
> >                                               first);
> >
> >                         if (state->parallel) {
> > @@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
> >                         goto cleanup;
> >                 }
> >
> > -               error = restorecon_sb(pathname, &sb, &state.flags, true);
> > +               error = restorecon_sb(pathname, &state.flags, true);
> >                 goto cleanup;
> >         }
> >
> > --
> > 2.36.1
> >

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

* Re: [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues
  2022-05-16 17:12       ` James Carter
@ 2022-05-16 19:01         ` Christian Göttsche
  2022-05-16 20:14           ` James Carter
  0 siblings, 1 reply; 14+ messages in thread
From: Christian Göttsche @ 2022-05-16 19:01 UTC (permalink / raw)
  To: James Carter; +Cc: SElinux list

On Mon, 16 May 2022 at 19:13, James Carter <jwcart2@gmail.com> wrote:
>
> On Thu, May 12, 2022 at 1:39 PM James Carter <jwcart2@gmail.com> wrote:
> >
> > On Wed, May 11, 2022 at 3:32 PM Christian Göttsche
> > <cgzones@googlemail.com> wrote:
> > >
> > > Pin the file to operate on in restorecon_sb() to prevent symlink attacks
> > > in between the label database lookup, the current context query and the
> > > final context write.  Also don't use the file information from
> > > fts_read(3), which might also be out of sync.
> > >
> > > Due to querying file information twice, one in fts_read(3) needed for
> > > the cross device check and one on the pinned file descriptor for the
> > > database lookup, there is a slight slowdown:
> > >
> > >     [current]
> > >     Time (mean ± σ):     14.456 s ±  0.306 s    [User: 45.863 s, System: 4.463 s]
> > >     Range (min … max):   14.275 s … 15.294 s    10 runs
> > >
> > >     [changed]
> > >     Time (mean ± σ):     15.843 s ±  0.045 s    [User: 46.274 s, System: 9.495 s]
> > >     Range (min … max):   15.787 s … 15.916 s    10 runs
> > >
> > > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> >
> > Acked-by: James Carter <jwcart2@gmail.com>
> >
>
> Merged.
> Thanks,
> Jim
>
> > > ---
> > >  libselinux/src/selinux_restorecon.c | 43 +++++++++++++++++------------
> > >  1 file changed, 25 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> > > index 42ef30cb..12b85101 100644
> > > --- a/libselinux/src/selinux_restorecon.c
> > > +++ b/libselinux/src/selinux_restorecon.c
> > > @@ -621,13 +621,13 @@ out:
> > >         return rc;
> > >  }
> > >
> > > -static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > -                           struct rest_flags *flags, bool first)
> > > +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
> > >  {
> > >         char *newcon = NULL;
> > >         char *curcon = NULL;
> > >         char *newtypecon = NULL;
> > > -       int rc;
> > > +       int fd = -1, rc;
> > > +       struct stat stat_buf;
> > >         bool updated = false;
> > >         const char *lookup_path = pathname;
> > >         float pc;
> > > @@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >                 lookup_path += rootpathlen;
> > >         }
> > >
> > > +       fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL);
> > > +       if (fd < 0)
> > > +               goto err;
> > > +
> > > +       rc = fstat(fd, &stat_buf);

According to man:open(2) fstat(2) on a file descriptor obtained via
O_PATH is only available since Linux 3.6.
What versions should be supported by libselinux?
Or should there exist a fallback, checked similarly at [1].


[1]: https://github.com/SELinuxProject/selinux/blob/9e096e6ef0a87b05c11ce57077ecb20a1b2a6995/libselinux/src/selinux_restorecon.c#L250

> > > +       if (rc < 0)
> > > +               goto err;
> > > +
> > >         if (rootpath != NULL && lookup_path[0] == '\0')
> > >                 /* this is actually the root dir of the alt root. */
> > >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
> > > -                                                   sb->st_mode);
> > > +                                                   stat_buf.st_mode);
> > >         else
> > >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
> > > -                                                   sb->st_mode);
> > > +                                                   stat_buf.st_mode);
> > >
> > >         if (rc < 0) {
> > >                 if (errno == ENOENT) {
> > > @@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >                                             "Warning no default label for %s\n",
> > >                                             lookup_path);
> > >
> > > -                       return 0; /* no match, but not an error */
> > > +                       goto out; /* no match, but not an error */
> > >                 }
> > >
> > > -               return -1;
> > > +               goto err;
> > >         }
> > >
> > >         if (flags->progress) {
> > > @@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >         }
> > >
> > >         if (flags->add_assoc) {
> > > -               rc = filespec_add(sb->st_ino, newcon, pathname, flags);
> > > +               rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
> > >
> > >                 if (rc < 0) {
> > >                         selinux_log(SELINUX_ERROR,
> > >                                     "filespec_add error: %s\n", pathname);
> > > -                       freecon(newcon);
> > > -                       return -1;
> > > +                       goto out1;
> > >                 }
> > >
> > >                 if (rc > 0) {
> > >                         /* Already an association and it took precedence. */
> > > -                       freecon(newcon);
> > > -                       return 0;
> > > +                       goto out;
> > >                 }
> > >         }
> > >
> > > @@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >                 selinux_log(SELINUX_INFO, "%s matched by %s\n",
> > >                             pathname, newcon);
> > >
> > > -       if (lgetfilecon_raw(pathname, &curcon) < 0) {
> > > +       if (fgetfilecon_raw(fd, &curcon) < 0) {
> > >                 if (errno != ENODATA)
> > >                         goto err;
> > >
> > > @@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >                 }
> > >
> > >                 if (!flags->nochange) {
> > > -                       if (lsetfilecon(pathname, newcon) < 0)
> > > +                       if (fsetfilecon(fd, newcon) < 0)
> > >                                 goto err;
> > >                         updated = true;
> > >                 }
> > > @@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > >  out:
> > >         rc = 0;
> > >  out1:
> > > +       if (fd >= 0)
> > > +               close(fd);
> > >         freecon(curcon);
> > >         freecon(newcon);
> > >         return rc;
> > > @@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg)
> > >         FTSENT *ftsent;
> > >         int error;
> > >         char ent_path[PATH_MAX];
> > > -       struct stat ent_st;
> > >         bool first = false;
> > >
> > >         if (state->parallel)
> > > @@ -953,11 +960,11 @@ loop_body:
> > >                         /* fall through */
> > >                 default:
> > >                         strcpy(ent_path, ftsent->fts_path);
> > > -                       ent_st = *ftsent->fts_statp;
> > > +
> > >                         if (state->parallel)
> > >                                 pthread_mutex_unlock(&state->mutex);
> > >
> > > -                       error = restorecon_sb(ent_path, &ent_st, &state->flags,
> > > +                       error = restorecon_sb(ent_path, &state->flags,
> > >                                               first);
> > >
> > >                         if (state->parallel) {
> > > @@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
> > >                         goto cleanup;
> > >                 }
> > >
> > > -               error = restorecon_sb(pathname, &sb, &state.flags, true);
> > > +               error = restorecon_sb(pathname, &state.flags, true);
> > >                 goto cleanup;
> > >         }
> > >
> > > --
> > > 2.36.1
> > >

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

* Re: [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues
  2022-05-16 19:01         ` Christian Göttsche
@ 2022-05-16 20:14           ` James Carter
  0 siblings, 0 replies; 14+ messages in thread
From: James Carter @ 2022-05-16 20:14 UTC (permalink / raw)
  To: Christian Göttsche; +Cc: SElinux list

On Mon, May 16, 2022 at 3:01 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> On Mon, 16 May 2022 at 19:13, James Carter <jwcart2@gmail.com> wrote:
> >
> > On Thu, May 12, 2022 at 1:39 PM James Carter <jwcart2@gmail.com> wrote:
> > >
> > > On Wed, May 11, 2022 at 3:32 PM Christian Göttsche
> > > <cgzones@googlemail.com> wrote:
> > > >
> > > > Pin the file to operate on in restorecon_sb() to prevent symlink attacks
> > > > in between the label database lookup, the current context query and the
> > > > final context write.  Also don't use the file information from
> > > > fts_read(3), which might also be out of sync.
> > > >
> > > > Due to querying file information twice, one in fts_read(3) needed for
> > > > the cross device check and one on the pinned file descriptor for the
> > > > database lookup, there is a slight slowdown:
> > > >
> > > >     [current]
> > > >     Time (mean ± σ):     14.456 s ±  0.306 s    [User: 45.863 s, System: 4.463 s]
> > > >     Range (min … max):   14.275 s … 15.294 s    10 runs
> > > >
> > > >     [changed]
> > > >     Time (mean ± σ):     15.843 s ±  0.045 s    [User: 46.274 s, System: 9.495 s]
> > > >     Range (min … max):   15.787 s … 15.916 s    10 runs
> > > >
> > > > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > >
> > > Acked-by: James Carter <jwcart2@gmail.com>
> > >
> >
> > Merged.
> > Thanks,
> > Jim
> >
> > > > ---
> > > >  libselinux/src/selinux_restorecon.c | 43 +++++++++++++++++------------
> > > >  1 file changed, 25 insertions(+), 18 deletions(-)
> > > >
> > > > diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> > > > index 42ef30cb..12b85101 100644
> > > > --- a/libselinux/src/selinux_restorecon.c
> > > > +++ b/libselinux/src/selinux_restorecon.c
> > > > @@ -621,13 +621,13 @@ out:
> > > >         return rc;
> > > >  }
> > > >
> > > > -static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > > -                           struct rest_flags *flags, bool first)
> > > > +static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool first)
> > > >  {
> > > >         char *newcon = NULL;
> > > >         char *curcon = NULL;
> > > >         char *newtypecon = NULL;
> > > > -       int rc;
> > > > +       int fd = -1, rc;
> > > > +       struct stat stat_buf;
> > > >         bool updated = false;
> > > >         const char *lookup_path = pathname;
> > > >         float pc;
> > > > @@ -642,13 +642,21 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >                 lookup_path += rootpathlen;
> > > >         }
> > > >
> > > > +       fd = open(pathname, O_PATH | O_NOFOLLOW | O_EXCL);
> > > > +       if (fd < 0)
> > > > +               goto err;
> > > > +
> > > > +       rc = fstat(fd, &stat_buf);
>
> According to man:open(2) fstat(2) on a file descriptor obtained via
> O_PATH is only available since Linux 3.6.
> What versions should be supported by libselinux?
> Or should there exist a fallback, checked similarly at [1].
>
>
> [1]: https://github.com/SELinuxProject/selinux/blob/9e096e6ef0a87b05c11ce57077ecb20a1b2a6995/libselinux/src/selinux_restorecon.c#L250
>

I didn't really think about that. Linux 3.6 was 10 years ago, so it
doesn't seem like it should be a problem, but it is probably better to
provide a fallback similar to the one you referenced.
Thanks,
Jim


> > > > +       if (rc < 0)
> > > > +               goto err;
> > > > +
> > > >         if (rootpath != NULL && lookup_path[0] == '\0')
> > > >                 /* this is actually the root dir of the alt root. */
> > > >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
> > > > -                                                   sb->st_mode);
> > > > +                                                   stat_buf.st_mode);
> > > >         else
> > > >                 rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
> > > > -                                                   sb->st_mode);
> > > > +                                                   stat_buf.st_mode);
> > > >
> > > >         if (rc < 0) {
> > > >                 if (errno == ENOENT) {
> > > > @@ -657,10 +665,10 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >                                             "Warning no default label for %s\n",
> > > >                                             lookup_path);
> > > >
> > > > -                       return 0; /* no match, but not an error */
> > > > +                       goto out; /* no match, but not an error */
> > > >                 }
> > > >
> > > > -               return -1;
> > > > +               goto err;
> > > >         }
> > > >
> > > >         if (flags->progress) {
> > > > @@ -680,19 +688,17 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >         }
> > > >
> > > >         if (flags->add_assoc) {
> > > > -               rc = filespec_add(sb->st_ino, newcon, pathname, flags);
> > > > +               rc = filespec_add(stat_buf.st_ino, newcon, pathname, flags);
> > > >
> > > >                 if (rc < 0) {
> > > >                         selinux_log(SELINUX_ERROR,
> > > >                                     "filespec_add error: %s\n", pathname);
> > > > -                       freecon(newcon);
> > > > -                       return -1;
> > > > +                       goto out1;
> > > >                 }
> > > >
> > > >                 if (rc > 0) {
> > > >                         /* Already an association and it took precedence. */
> > > > -                       freecon(newcon);
> > > > -                       return 0;
> > > > +                       goto out;
> > > >                 }
> > > >         }
> > > >
> > > > @@ -700,7 +706,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >                 selinux_log(SELINUX_INFO, "%s matched by %s\n",
> > > >                             pathname, newcon);
> > > >
> > > > -       if (lgetfilecon_raw(pathname, &curcon) < 0) {
> > > > +       if (fgetfilecon_raw(fd, &curcon) < 0) {
> > > >                 if (errno != ENODATA)
> > > >                         goto err;
> > > >
> > > > @@ -733,7 +739,7 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >                 }
> > > >
> > > >                 if (!flags->nochange) {
> > > > -                       if (lsetfilecon(pathname, newcon) < 0)
> > > > +                       if (fsetfilecon(fd, newcon) < 0)
> > > >                                 goto err;
> > > >                         updated = true;
> > > >                 }
> > > > @@ -758,6 +764,8 @@ static int restorecon_sb(const char *pathname, const struct stat *sb,
> > > >  out:
> > > >         rc = 0;
> > > >  out1:
> > > > +       if (fd >= 0)
> > > > +               close(fd);
> > > >         freecon(curcon);
> > > >         freecon(newcon);
> > > >         return rc;
> > > > @@ -855,7 +863,6 @@ static void *selinux_restorecon_thread(void *arg)
> > > >         FTSENT *ftsent;
> > > >         int error;
> > > >         char ent_path[PATH_MAX];
> > > > -       struct stat ent_st;
> > > >         bool first = false;
> > > >
> > > >         if (state->parallel)
> > > > @@ -953,11 +960,11 @@ loop_body:
> > > >                         /* fall through */
> > > >                 default:
> > > >                         strcpy(ent_path, ftsent->fts_path);
> > > > -                       ent_st = *ftsent->fts_statp;
> > > > +
> > > >                         if (state->parallel)
> > > >                                 pthread_mutex_unlock(&state->mutex);
> > > >
> > > > -                       error = restorecon_sb(ent_path, &ent_st, &state->flags,
> > > > +                       error = restorecon_sb(ent_path, &state->flags,
> > > >                                               first);
> > > >
> > > >                         if (state->parallel) {
> > > > @@ -1153,7 +1160,7 @@ static int selinux_restorecon_common(const char *pathname_orig,
> > > >                         goto cleanup;
> > > >                 }
> > > >
> > > > -               error = restorecon_sb(pathname, &sb, &state.flags, true);
> > > > +               error = restorecon_sb(pathname, &state.flags, true);
> > > >                 goto cleanup;
> > > >         }
> > > >
> > > > --
> > > > 2.36.1
> > > >

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

end of thread, other threads:[~2022-05-16 20:32 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-05 17:44 [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon Christian Göttsche
2022-05-11 18:42 ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks Christian Göttsche
2022-05-11 18:42   ` [RFC PATCH 3/4] libselinux: restorecon: forward error if not ENOENT Christian Göttsche
2022-05-12 17:39     ` James Carter
2022-05-16 17:10       ` James Carter
2022-05-11 18:42   ` [RFC PATCH 4/4] libselinux: restorecon: pin file to avoid TOCTOU issues Christian Göttsche
2022-05-12 17:39     ` James Carter
2022-05-16 17:12       ` James Carter
2022-05-16 19:01         ` Christian Göttsche
2022-05-16 20:14           ` James Carter
2022-05-12 17:38   ` [RFC PATCH 2/4] libselinux: restorecon: misc tweaks James Carter
2022-05-16 17:10     ` James Carter
2022-05-11 19:09 ` [RFC PATCH] libselinux: emulate O_PATH support in fgetfilecon/fsetfilecon James Carter
2022-05-16 17:07   ` James Carter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.