@@ -85,6 +85,9 @@ in_str_list (const char *libname, const char *const strlist[])
static int
do_test (void)
{
+ /* needs /proc/sys/kernel/yama/ptrace_scope and /proc/$child */
+ support_need_proc ();
+
/* Check if our subprocess can be debugged with ptrace. */
{
int ptrace_scope = support_ptrace_scope ();
@@ -28,6 +28,8 @@
#include <unistd.h>
#include <inttypes.h>
+#include <support/support.h>
+
/* There is an obscure bug in the kernel due to which RLIMIT_STACK is sometimes
returned as unlimited when it is not, which may cause this test to fail.
There is also the other case where RLIMIT_STACK is intentionally set as
@@ -153,6 +155,9 @@ check_stack_top (void)
static int
do_test (void)
{
+ /* Reads /proc/self/maps to get stack size. */
+ support_need_proc ();
+
pagesize = sysconf (_SC_PAGESIZE);
return check_stack_top ();
}
@@ -95,6 +95,9 @@ do_test (void)
char buf1[PATH_MAX];
char buf2[PATH_MAX];
+ /* The xmkdirp below fails if we can't map our uid, which requires /proc. */
+ support_need_proc ();
+
sprintf (buf1, "/subdir%s", support_slibdir_prefix);
xmkdirp (buf1, 0777);
@@ -64,6 +64,7 @@ libsupport-routines = \
support_format_netent \
support_isolate_in_subprocess \
support_mutex_pi_monotonic \
+ support_need_proc \
support_path_support_time64 \
support_process_state \
support_ptrace \
@@ -91,6 +91,10 @@ char *support_quote_string (const char *);
regular file open for writing, and initially empty. */
int support_descriptor_supports_holes (int fd);
+/* Predicates that a test requires a working /proc filesystem. This
+ call will exit with UNSUPPORTED if /proc is not available. */
+void support_need_proc (void);
+
/* Error-checking wrapper functions which terminate the process on
error. */
new file mode 100644
@@ -0,0 +1,33 @@
+/* Indicate that a test requires a working /proc.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <unistd.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* We test for /proc/self/maps since that's one of the files that one
+ of our tests actually uses, but the general idea is if Linux's
+ /proc/ (procfs) filesystem is mounted. If not, the process exits
+ with an UNSUPPORTED result code. */
+
+void
+support_need_proc (void)
+{
+ if (access ("/proc/self/maps", R_OK))
+ FAIL_UNSUPPORTED ("/proc is not available");
+}
@@ -49,6 +49,20 @@
#include "check.h"
#include "test-driver.h"
+/* If set to 0, we bind mount the parent's /proc and re-use the
+ paren't pids (i.e. test runs as the user). If set to 1, we enter a
+ new pid namespace and mount our own /proc (i.e. test runs as root).
+ I was tired of swapping the code back and forth during testing, so
+ you get both ;-) */
+#define SEPARATE_PID_NS 1
+#define SHARED_PID_NS (!SEPARATE_PID_NS)
+
+#if SEPARATE_PID_NS
+#define MAYBE_CLONE_NEWPID CLONE_NEWPID
+#else
+#define MAYBE_CLONE_NEWPID 0
+#endif
+
#ifndef __linux__
#define mount(s,t,fs,f,d) no_mount()
int no_mount (void)
@@ -231,7 +245,7 @@ concat (const char *str, ...)
static void
trymount (const char *src, const char *dest)
{
- if (mount (src, dest, "", MS_BIND, NULL) < 0)
+ if (mount (src, dest, "", MS_BIND | MS_REC, NULL) < 0)
FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
}
@@ -1068,7 +1082,7 @@ main (int argc, char **argv)
#ifdef CLONE_NEWNS
/* The unshare here gives us our own spaces and capabilities. */
- if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0)
+ if (unshare (CLONE_NEWUSER | MAYBE_CLONE_NEWPID | CLONE_NEWNS) < 0)
{
/* Older kernels may not support all the options, or security
policy may block this call. */
@@ -1094,6 +1108,15 @@ main (int argc, char **argv)
trymount (support_srcdir_root, new_srcdir_path);
trymount (support_objdir_root, new_objdir_path);
+#if SHARED_PID_NS
+ /* It may not be possible to mount /proc directly. */
+ {
+ char *new_proc = concat (new_root_path, "/proc", NULL);
+ xmkdirp (new_proc, 0755);
+ trymount ("/proc", new_proc);
+ }
+#endif
+
xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
devmount (new_root_path, "null");
devmount (new_root_path, "zero");
@@ -1163,42 +1186,57 @@ main (int argc, char **argv)
maybe_xmkdir ("/tmp", 0755);
+#if SEPARATE_PID_NS
/* Now that we're pid 1 (effectively "root") we can mount /proc */
maybe_xmkdir ("/proc", 0777);
- if (mount ("proc", "/proc", "proc", 0, NULL) < 0)
- FAIL_EXIT1 ("Unable to mount /proc: ");
-
- /* We map our original UID to the same UID in the container so we
- can own our own files normally. */
- UMAP = open ("/proc/self/uid_map", O_WRONLY);
- if (UMAP < 0)
- FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
-
- sprintf (tmp, "%lld %lld 1\n",
- (long long) (be_su ? 0 : original_uid), (long long) original_uid);
- write (UMAP, tmp, strlen (tmp));
- xclose (UMAP);
-
- /* We must disable setgroups () before we can map our groups, else we
- get EPERM. */
- GMAP = open ("/proc/self/setgroups", O_WRONLY);
- if (GMAP >= 0)
+ if (mount ("proc", "/proc", "proc", 0, NULL) != 0)
{
- /* We support kernels old enough to not have this. */
- write (GMAP, "deny\n", 5);
- xclose (GMAP);
+ // This happens if we're trying to create a nested container,
+ // like if the build is running under podman, and we lack
+ // priviledges.
+
+ // Ideally we would WARN here, but that would just add noise to
+ // *every* test-container test, and the ones that care should
+ // have their own relevent diagnostics.
+
+ // FAIL_EXIT1 ("Unable to mount /proc: ");
}
+ else
+ /* The shared pid namespace case will always run the following block... */
+#endif
+ {
+ /* We map our original UID to the same UID in the container so we
+ can own our own files normally. */
+ UMAP = open ("/proc/self/uid_map", O_WRONLY);
+ if (UMAP < 0)
+ FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
+
+ sprintf (tmp, "%lld %lld 1\n",
+ (long long) (be_su ? 0 : original_uid), (long long) original_uid);
+ write (UMAP, tmp, strlen (tmp));
+ xclose (UMAP);
+
+ /* We must disable setgroups () before we can map our groups, else we
+ get EPERM. */
+ GMAP = open ("/proc/self/setgroups", O_WRONLY);
+ if (GMAP >= 0)
+ {
+ /* We support kernels old enough to not have this. */
+ write (GMAP, "deny\n", 5);
+ xclose (GMAP);
+ }
- /* We map our original GID to the same GID in the container so we
- can own our own files normally. */
- GMAP = open ("/proc/self/gid_map", O_WRONLY);
- if (GMAP < 0)
- FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
+ /* We map our original GID to the same GID in the container so we
+ can own our own files normally. */
+ GMAP = open ("/proc/self/gid_map", O_WRONLY);
+ if (GMAP < 0)
+ FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
- sprintf (tmp, "%lld %lld 1\n",
- (long long) (be_su ? 0 : original_gid), (long long) original_gid);
- write (GMAP, tmp, strlen (tmp));
- xclose (GMAP);
+ sprintf (tmp, "%lld %lld 1\n",
+ (long long) (be_su ? 0 : original_gid), (long long) original_gid);
+ write (GMAP, tmp, strlen (tmp));
+ xclose (GMAP);
+ }
if (change_cwd)
{