public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] test-container: return UNSUPPORTED for ENOSPC on clone()
@ 2022-06-21 11:30 Xi Ruoyao
  2022-06-27 18:57 ` DJ Delorie
  0 siblings, 1 reply; 5+ messages in thread
From: Xi Ruoyao @ 2022-06-21 11:30 UTC (permalink / raw)
  To: libc-alpha

Since Linux 4.9, the kernel provides
/proc/sys/user/max_{mnt,pid,user}_namespace as a limitation of number of
namespaces.  Some distros (for example, Slint Linux 14.2.1) set them (or
only max_user_namespace) to zero as a "security policy" for disabling
namespaces.

The clone() call will set errno to ENOSPC under such a limitation.  We
didn't check ENOSPC in the code so the test will FAIL, and report:

    unable to unshare user/fs: No space left on device

This message is, unfortunately, very unhelpful.  It leads people to
check the memory or disk space, instead of finding the real issue.

To improve the situation, we should check for ENOSPC and return
UNSUPPORTED as the test result.  Also refactor check_for_unshare_hints()
to emit a proper message telling people how to make the test work, if
they really need to run the namespaced tests.

Reported-by: Philippe Delavalade <philippe.delavalade@orange.fr>
URL: https://lists.linuxfromscratch.org/sympa/arc/lfs-support/2022-06/msg00022.html
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 support/test-container.c | 67 +++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/support/test-container.c b/support/test-container.c
index 7557aac441..b186b75146 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -18,6 +18,7 @@
 
 #define _FILE_OFFSET_BITS 64
 
+#include <array_length.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -684,39 +685,43 @@ rsync (char *src, char *dest, int and_delete, int force_copies)
 /* See if we can detect what the user needs to do to get unshare
    support working for us.  */
 void
-check_for_unshare_hints (void)
+check_for_unshare_hints (int require_pidns)
 {
+  static struct {
+    const char *path;
+    int bad_value, good_value, for_pidns;
+  } files[] = {
+    /* Default Debian Linux disables user namespaces, but allows a way
+       to enable them.  */
+    /* ALT Linux has an alternate way of doing the same.  */
+    { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
+    { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
+    /* Linux kernel >= 4.9 has a configurable limit on the number of
+       each namespace.  Some distros set the limit to zero to disable the
+       corresponding namespace as a "security policy".  */
+    { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
+    { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
+    { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
+  };
   FILE *f;
-  int i;
+  int i, val;
 
-  /* Default Debian Linux disables user namespaces, but allows a way
-     to enable them.  */
-  f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
-  if (f != NULL)
+  for (i = 0; i < array_length (files); i++)
     {
-      i = 99; /* Sentinel.  */
-      fscanf (f, "%d", &i);
-      if (i == 0)
-	{
-	  printf ("To enable test-container, please run this as root:\n");
-	  printf ("  echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
-	}
-      fclose (f);
-      return;
-    }
+      if (!require_pidns && files[i].for_pidns)
+        continue;
 
-  /* ALT Linux has an alternate way of doing the same.  */
-  f = fopen ("/proc/sys/kernel/userns_restrict", "r");
-  if (f != NULL)
-    {
-      i = 99; /* Sentinel.  */
-      fscanf (f, "%d", &i);
-      if (i == 1)
-	{
-	  printf ("To enable test-container, please run this as root:\n");
-	  printf ("  echo 0 > /proc/sys/kernel/userns_restrict\n");
-	}
-      fclose (f);
+      f = fopen (files[i].path, "r");
+      if (f == NULL)
+        continue;
+
+      val = -1; /* Sentinel.  */
+      fscanf (f, "%d", &val);
+      if (val != files[i].bad_value)
+	continue;
+
+      printf ("To enable test-container, please run this as root:\n");
+      printf ("  echo %d > %s\n", files[i].good_value, files[i].path);
       return;
     }
 }
@@ -1117,11 +1122,11 @@ main (int argc, char **argv)
     {
       /* Older kernels may not support all the options, or security
 	 policy may block this call.  */
-      if (errno == EINVAL || errno == EPERM)
+      if (errno == EINVAL || errno == EPERM || errno == ENOSPC)
 	{
 	  int saved_errno = errno;
-	  if (errno == EPERM)
-	    check_for_unshare_hints ();
+	  if (errno == EPERM || errno == ENOSPC)
+	    check_for_unshare_hints (require_pidns);
 	  FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
 	}
       /* We're about to exit anyway, it's "safe" to call unshare again
-- 
2.36.1



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

* Re: [PATCH] test-container: return UNSUPPORTED for ENOSPC on clone()
  2022-06-21 11:30 [PATCH] test-container: return UNSUPPORTED for ENOSPC on clone() Xi Ruoyao
@ 2022-06-27 18:57 ` DJ Delorie
  2022-06-28 10:44   ` [PATCH v2] " Xi Ruoyao
  0 siblings, 1 reply; 5+ messages in thread
From: DJ Delorie @ 2022-06-27 18:57 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: libc-alpha


> +    /* ALT Linux has an alternate way of doing the same.  */
> +    { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },

Those two lines should be swapped, as the comment refers to this
following line:

> +    { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },

LGTM to commit with that change.

Reviewed-by: DJ Delorie <dj@redhat.com>


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

* [PATCH v2] test-container: return UNSUPPORTED for ENOSPC on clone()
  2022-06-27 18:57 ` DJ Delorie
@ 2022-06-28 10:44   ` Xi Ruoyao
  2022-07-05  3:02     ` PING: " Xi Ruoyao
  2022-07-06  2:35     ` DJ Delorie
  0 siblings, 2 replies; 5+ messages in thread
From: Xi Ruoyao @ 2022-06-28 10:44 UTC (permalink / raw)
  To: DJ Delorie; +Cc: libc-alpha

Hi DJ,

Revised patch following.  I don't have write access to glibc.git so I
guess you need to push the patch.

-- >8 --

Since Linux 4.9, the kernel provides
/proc/sys/user/max_{mnt,pid,user}_namespace as a limitation of number of
namespaces.  Some distros (for example, Slint Linux 14.2.1) set them (or
only max_user_namespace) to zero as a "security policy" for disabling
namespaces.

The clone() call will set errno to ENOSPC under such a limitation.  We
didn't check ENOSPC in the code so the test will FAIL, and report:

    unable to unshare user/fs: No space left on device

This message is, unfortunately, very unhelpful.  It leads people to
check the memory or disk space, instead of finding the real issue.

To improve the situation, we should check for ENOSPC and return
UNSUPPORTED as the test result.  Also refactor check_for_unshare_hints()
to emit a proper message telling people how to make the test work, if
they really need to run the namespaced tests.

Reported-by: Philippe Delavalade <philippe.delavalade@orange.fr>
URL: https://lists.linuxfromscratch.org/sympa/arc/lfs-support/2022-06/msg00022.html
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: DJ Delorie <dj@redhat.com>
---
 support/test-container.c | 67 +++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/support/test-container.c b/support/test-container.c
index 7557aac441..b6a1158ae1 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -18,6 +18,7 @@
 
 #define _FILE_OFFSET_BITS 64
 
+#include <array_length.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -684,39 +685,43 @@ rsync (char *src, char *dest, int and_delete, int force_copies)
 /* See if we can detect what the user needs to do to get unshare
    support working for us.  */
 void
-check_for_unshare_hints (void)
+check_for_unshare_hints (int require_pidns)
 {
+  static struct {
+    const char *path;
+    int bad_value, good_value, for_pidns;
+  } files[] = {
+    /* Default Debian Linux disables user namespaces, but allows a way
+       to enable them.  */
+    { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
+    /* ALT Linux has an alternate way of doing the same.  */
+    { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
+    /* Linux kernel >= 4.9 has a configurable limit on the number of
+       each namespace.  Some distros set the limit to zero to disable the
+       corresponding namespace as a "security policy".  */
+    { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
+    { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
+    { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
+  };
   FILE *f;
-  int i;
+  int i, val;
 
-  /* Default Debian Linux disables user namespaces, but allows a way
-     to enable them.  */
-  f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
-  if (f != NULL)
+  for (i = 0; i < array_length (files); i++)
     {
-      i = 99; /* Sentinel.  */
-      fscanf (f, "%d", &i);
-      if (i == 0)
-	{
-	  printf ("To enable test-container, please run this as root:\n");
-	  printf ("  echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
-	}
-      fclose (f);
-      return;
-    }
+      if (!require_pidns && files[i].for_pidns)
+        continue;
 
-  /* ALT Linux has an alternate way of doing the same.  */
-  f = fopen ("/proc/sys/kernel/userns_restrict", "r");
-  if (f != NULL)
-    {
-      i = 99; /* Sentinel.  */
-      fscanf (f, "%d", &i);
-      if (i == 1)
-	{
-	  printf ("To enable test-container, please run this as root:\n");
-	  printf ("  echo 0 > /proc/sys/kernel/userns_restrict\n");
-	}
-      fclose (f);
+      f = fopen (files[i].path, "r");
+      if (f == NULL)
+        continue;
+
+      val = -1; /* Sentinel.  */
+      fscanf (f, "%d", &val);
+      if (val != files[i].bad_value)
+	continue;
+
+      printf ("To enable test-container, please run this as root:\n");
+      printf ("  echo %d > %s\n", files[i].good_value, files[i].path);
       return;
     }
 }
@@ -1117,11 +1122,11 @@ main (int argc, char **argv)
     {
       /* Older kernels may not support all the options, or security
 	 policy may block this call.  */
-      if (errno == EINVAL || errno == EPERM)
+      if (errno == EINVAL || errno == EPERM || errno == ENOSPC)
 	{
 	  int saved_errno = errno;
-	  if (errno == EPERM)
-	    check_for_unshare_hints ();
+	  if (errno == EPERM || errno == ENOSPC)
+	    check_for_unshare_hints (require_pidns);
 	  FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
 	}
       /* We're about to exit anyway, it's "safe" to call unshare again
-- 
2.37.0



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

* PING: [PATCH v2] test-container: return UNSUPPORTED for ENOSPC on clone()
  2022-06-28 10:44   ` [PATCH v2] " Xi Ruoyao
@ 2022-07-05  3:02     ` Xi Ruoyao
  2022-07-06  2:35     ` DJ Delorie
  1 sibling, 0 replies; 5+ messages in thread
From: Xi Ruoyao @ 2022-07-05  3:02 UTC (permalink / raw)
  To: DJ Delorie; +Cc: libc-alpha

On Tue, 2022-06-28 at 18:44 +0800, Xi Ruoyao wrote:
> Hi DJ,
> 
> Revised patch following.  I don't have write access to glibc.git so I
> guess you need to push the patch.

Gentle ping as we are collecting patches for 2.36 :).

> -- >8 --
> 
> Since Linux 4.9, the kernel provides
> /proc/sys/user/max_{mnt,pid,user}_namespace as a limitation of number
> of
> namespaces.  Some distros (for example, Slint Linux 14.2.1) set them
> (or
> only max_user_namespace) to zero as a "security policy" for disabling
> namespaces.
> 
> The clone() call will set errno to ENOSPC under such a limitation.  We
> didn't check ENOSPC in the code so the test will FAIL, and report:
> 
>     unable to unshare user/fs: No space left on device
> 
> This message is, unfortunately, very unhelpful.  It leads people to
> check the memory or disk space, instead of finding the real issue.
> 
> To improve the situation, we should check for ENOSPC and return
> UNSUPPORTED as the test result.  Also refactor
> check_for_unshare_hints()
> to emit a proper message telling people how to make the test work, if
> they really need to run the namespaced tests.
> 
> Reported-by: Philippe Delavalade <philippe.delavalade@orange.fr>
> URL:
> https://lists.linuxfromscratch.org/sympa/arc/lfs-support/2022-06/msg00022.html
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  support/test-container.c | 67 +++++++++++++++++++++------------------
> -
>  1 file changed, 36 insertions(+), 31 deletions(-)
> 
> diff --git a/support/test-container.c b/support/test-container.c
> index 7557aac441..b6a1158ae1 100644
> --- a/support/test-container.c
> +++ b/support/test-container.c
> @@ -18,6 +18,7 @@
>  
>  #define _FILE_OFFSET_BITS 64
>  
> +#include <array_length.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> @@ -684,39 +685,43 @@ rsync (char *src, char *dest, int and_delete,
> int force_copies)
>  /* See if we can detect what the user needs to do to get unshare
>     support working for us.  */
>  void
> -check_for_unshare_hints (void)
> +check_for_unshare_hints (int require_pidns)
>  {
> +  static struct {
> +    const char *path;
> +    int bad_value, good_value, for_pidns;
> +  } files[] = {
> +    /* Default Debian Linux disables user namespaces, but allows a
> way
> +       to enable them.  */
> +    { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
> +    /* ALT Linux has an alternate way of doing the same.  */
> +    { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
> +    /* Linux kernel >= 4.9 has a configurable limit on the number of
> +       each namespace.  Some distros set the limit to zero to disable
> the
> +       corresponding namespace as a "security policy".  */
> +    { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
> +    { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
> +    { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
> +  };
>    FILE *f;
> -  int i;
> +  int i, val;
>  
> -  /* Default Debian Linux disables user namespaces, but allows a way
> -     to enable them.  */
> -  f = fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
> -  if (f != NULL)
> +  for (i = 0; i < array_length (files); i++)
>      {
> -      i = 99; /* Sentinel.  */
> -      fscanf (f, "%d", &i);
> -      if (i == 0)
> -       {
> -         printf ("To enable test-container, please run this as
> root:\n");
> -         printf ("  echo 1 >
> /proc/sys/kernel/unprivileged_userns_clone\n");
> -       }
> -      fclose (f);
> -      return;
> -    }
> +      if (!require_pidns && files[i].for_pidns)
> +        continue;
>  
> -  /* ALT Linux has an alternate way of doing the same.  */
> -  f = fopen ("/proc/sys/kernel/userns_restrict", "r");
> -  if (f != NULL)
> -    {
> -      i = 99; /* Sentinel.  */
> -      fscanf (f, "%d", &i);
> -      if (i == 1)
> -       {
> -         printf ("To enable test-container, please run this as
> root:\n");
> -         printf ("  echo 0 > /proc/sys/kernel/userns_restrict\n");
> -       }
> -      fclose (f);
> +      f = fopen (files[i].path, "r");
> +      if (f == NULL)
> +        continue;
> +
> +      val = -1; /* Sentinel.  */
> +      fscanf (f, "%d", &val);
> +      if (val != files[i].bad_value)
> +       continue;
> +
> +      printf ("To enable test-container, please run this as
> root:\n");
> +      printf ("  echo %d > %s\n", files[i].good_value,
> files[i].path);
>        return;
>      }
>  }
> @@ -1117,11 +1122,11 @@ main (int argc, char **argv)
>      {
>        /* Older kernels may not support all the options, or security
>          policy may block this call.  */
> -      if (errno == EINVAL || errno == EPERM)
> +      if (errno == EINVAL || errno == EPERM || errno == ENOSPC)
>         {
>           int saved_errno = errno;
> -         if (errno == EPERM)
> -           check_for_unshare_hints ();
> +         if (errno == EPERM || errno == ENOSPC)
> +           check_for_unshare_hints (require_pidns);
>           FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror
> (saved_errno));
>         }
>        /* We're about to exit anyway, it's "safe" to call unshare
> again

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2] test-container: return UNSUPPORTED for ENOSPC on clone()
  2022-06-28 10:44   ` [PATCH v2] " Xi Ruoyao
  2022-07-05  3:02     ` PING: " Xi Ruoyao
@ 2022-07-06  2:35     ` DJ Delorie
  1 sibling, 0 replies; 5+ messages in thread
From: DJ Delorie @ 2022-07-06  2:35 UTC (permalink / raw)
  To: Xi Ruoyao; +Cc: libc-alpha


Xi Ruoyao <xry111@xry111.site> writes:
> Revised patch following.  I don't have write access to glibc.git so I
> guess you need to push the patch.

LGTM.  Pushed.  Thanks!


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

end of thread, other threads:[~2022-07-06  2:35 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-21 11:30 [PATCH] test-container: return UNSUPPORTED for ENOSPC on clone() Xi Ruoyao
2022-06-27 18:57 ` DJ Delorie
2022-06-28 10:44   ` [PATCH v2] " Xi Ruoyao
2022-07-05  3:02     ` PING: " Xi Ruoyao
2022-07-06  2:35     ` DJ Delorie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).