diff mbox series

[1/2] libselinux: restorecon: add fallback for pre 3.6 Linux

Message ID 20220517140748.24238-1-cgzones@googlemail.com (mailing list archive)
State New
Headers show
Series [1/2] libselinux: restorecon: add fallback for pre 3.6 Linux | expand

Commit Message

Christian Göttsche May 17, 2022, 2:07 p.m. UTC
fstat(2) on file descriptors obtained via O_PATH is supported since
Linux 3.6. Fallback on older systems to lstat(2).

Fixes: 7e979b56 ("libselinux: restorecon: pin file to avoid TOCTOU issues")

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

Comments

James Carter May 18, 2022, 1:57 p.m. UTC | #1
On Tue, May 17, 2022 at 12:58 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> fstat(2) on file descriptors obtained via O_PATH is supported since
> Linux 3.6. Fallback on older systems to lstat(2).
>
> Fixes: 7e979b56 ("libselinux: restorecon: pin file to avoid TOCTOU issues")
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  libselinux/src/selinux_restorecon.c | 29 +++++++++++++++++++++++++----
>  1 file changed, 25 insertions(+), 4 deletions(-)
>
> diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
> index 9dd6be81..1a185ced 100644
> --- a/libselinux/src/selinux_restorecon.c
> +++ b/libselinux/src/selinux_restorecon.c
> @@ -89,10 +89,22 @@ struct rest_flags {
>         bool count_errors;
>  };
>
> +/* Linux version for availability tests. */
> +static struct utsname uts;
> +
>  static void restorecon_init(void)
>  {
>         struct selabel_handle *sehandle = NULL;
>
> +       if (uname(&uts) < 0) {
> +               /*
> +                * utsname(2) should never fail, but assume oldest supported

Should be "uname(2) should ..."

> +                * LTS release as backup
> +                */
> +               strncpy(uts.release, "4.9", sizeof(uts.release));

I don't know. Using 4.9 seems arbitrary. I think that I would prefer
just using "3.6" and note that only behavior is only changed for
kernels prior to 3.6 or something like that.

Thanks,
Jim


> +               uts.release[sizeof(uts.release) - 1] = '\0';
> +       }
> +
>         if (!fc_sehandle) {
>                 sehandle = selinux_restorecon_default_handle();
>                 selinux_restorecon_set_sehandle(sehandle);
> @@ -238,7 +250,6 @@ static uint64_t file_system_count(const char *name)
>   */
>  static uint64_t exclude_non_seclabel_mounts(void)
>  {
> -       struct utsname uts;
>         FILE *fp;
>         size_t len;
>         int index = 0, found = 0;
> @@ -247,7 +258,7 @@ static uint64_t exclude_non_seclabel_mounts(void)
>         char *buf = NULL, *item;
>
>         /* Check to see if the kernel supports seclabel */
> -       if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
> +       if (strverscmp(uts.release, "2.6.30") < 0)
>                 return 0;
>         if (is_selinux_enabled() <= 0)
>                 return 0;
> @@ -648,9 +659,19 @@ static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
>         if (fd < 0)
>                 goto err;
>
> +       /*
> +        * fstat(2) on file descriptors obtained via O_PATH are supported
> +        * since Linux 3.6, see man:open(2).
> +        * Test fstat(2) first, support might have been backported.
> +        */
>         rc = fstat(fd, &stat_buf);
> -       if (rc < 0)
> -               goto err;
> +       if (rc < 0) {
> +               if (errno == EBADF && strverscmp(uts.release, "3.6") < 0)
> +                       rc = lstat(pathname, &stat_buf);
> +
> +               if (rc < 0)
> +                       goto err;
> +       }
>
>         if (rootpath != NULL && lookup_path[0] == '\0')
>                 /* this is actually the root dir of the alt root. */
> --
> 2.36.1
>
diff mbox series

Patch

diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 9dd6be81..1a185ced 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -89,10 +89,22 @@  struct rest_flags {
 	bool count_errors;
 };
 
+/* Linux version for availability tests. */
+static struct utsname uts;
+
 static void restorecon_init(void)
 {
 	struct selabel_handle *sehandle = NULL;
 
+	if (uname(&uts) < 0) {
+		/*
+		 * utsname(2) should never fail, but assume oldest supported
+		 * LTS release as backup
+		 */
+		strncpy(uts.release, "4.9", sizeof(uts.release));
+		uts.release[sizeof(uts.release) - 1] = '\0';
+	}
+
 	if (!fc_sehandle) {
 		sehandle = selinux_restorecon_default_handle();
 		selinux_restorecon_set_sehandle(sehandle);
@@ -238,7 +250,6 @@  static uint64_t file_system_count(const char *name)
  */
 static uint64_t exclude_non_seclabel_mounts(void)
 {
-	struct utsname uts;
 	FILE *fp;
 	size_t len;
 	int index = 0, found = 0;
@@ -247,7 +258,7 @@  static uint64_t exclude_non_seclabel_mounts(void)
 	char *buf = NULL, *item;
 
 	/* Check to see if the kernel supports seclabel */
-	if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
+	if (strverscmp(uts.release, "2.6.30") < 0)
 		return 0;
 	if (is_selinux_enabled() <= 0)
 		return 0;
@@ -648,9 +659,19 @@  static int restorecon_sb(const char *pathname, struct rest_flags *flags, bool fi
 	if (fd < 0)
 		goto err;
 
+	/*
+	 * fstat(2) on file descriptors obtained via O_PATH are supported
+	 * since Linux 3.6, see man:open(2).
+	 * Test fstat(2) first, support might have been backported.
+	 */
 	rc = fstat(fd, &stat_buf);
-	if (rc < 0)
-		goto err;
+	if (rc < 0) {
+		if (errno == EBADF && strverscmp(uts.release, "3.6") < 0)
+			rc = lstat(pathname, &stat_buf);
+
+		if (rc < 0)
+			goto err;
+	}
 
 	if (rootpath != NULL && lookup_path[0] == '\0')
 		/* this is actually the root dir of the alt root. */