1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <array_length.h>
24 #include <sys/syscall.h>
26 #include <sys/types.h>
30 #include <sys/fcntl.h>
34 #include <sys/sysmacros.h>
39 #include <libc-pointer-arith.h>
42 #include <sys/mount.h>
45 #include <support/support.h>
46 #include <support/xunistd.h>
47 #include <support/capture_subprocess.h>
49 #include "test-driver.h"
52 #define mount(s,t,fs,f,d) no_mount()
55 FAIL_UNSUPPORTED("mount not supported; port needed");
61 /* Running a test in a container is tricky. There are two main
62 categories of things to do:
64 1. "Once" actions, like setting up the container and doing an
67 2. "Per-test" actions, like copying in support files and
68 configuring the container.
73 * mkdir $buildroot/testroot.pristine/
75 * default glibc install
76 * create /bin for /bin/sh
77 * create $(complocaledir) so localedef tests work with default paths.
78 * install /bin/sh, /bin/echo, and /bin/true.
79 * rsync to $buildroot/testroot.root/
82 * maybe rsync to $buildroot/testroot.root/
83 * copy support files and test binary
85 * set up any mounts (like /proc)
90 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
93 * mytest.root/ is rsync'd into container
94 * mytest.root/preclean.req causes fresh rsync (with delete) before
96 * mytest.root/mytest.script has a list of "commands" to run:
109 $B/ build dir, equivalent to $(common-objpfx)
110 $S/ source dir, equivalent to $(srcdir)
111 $I/ install dir, equivalent to $(prefix)
112 $L/ library dir (in container), equivalent to $(libdir)
113 $complocaledir/ compiled locale dir, equivalent to $(complocaledir)
116 If FILE begins with any of these variables then they will be
117 substituted for the described value.
119 The goal is to expose as many of the runtime's configured paths
120 via variables so they can be used to setup the container environment
121 before execution reaches the test.
125 - 'pidns': Require a separate PID namespace, prints comment if it can't
126 (default is a shared pid namespace)
127 - 'su': Enables running test as root in the container.
128 - 'mv': A minimal move files command.
129 - 'cp': A minimal copy files command.
130 - 'rm': A minimal remove files command.
131 - 'cwd': set test working directory
132 - 'exec': change test binary location (may end in /)
133 - 'mkdirp': A minimal "mkdir -p FILE" command.
135 * mytest.root/postclean.req causes fresh rsync (with delete) after
138 * mytest.root/ldconfig.run causes ldconfig to be issued prior
139 test execution (to setup the initial ld.so.cache).
141 Note that $srcdir/foo/mytest.script may be used instead of a
142 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
143 there is no other reason for a sysroot.
147 * independent of other packages which may not be installed (like
148 rsync or Docker, or even "cp")
150 * Simple, easy to review code (i.e. prefer simple naive code over
151 complex efficient code)
153 * The current implementation is parallel-make-safe, but only in
154 that it uses a lock to prevent parallel access to the testroot. */
157 /* Utility Functions */
159 /* Like xunlink, but it's OK if the file already doesn't exist. */
161 maybe_xunlink (const char *path
)
163 int rv
= unlink (path
);
164 if (rv
< 0 && errno
!= ENOENT
)
165 FAIL_EXIT1 ("unlink (\"%s\"): %m", path
);
168 /* Like xmkdir, but it's OK if the directory already exists. */
170 maybe_xmkdir (const char *path
, mode_t mode
)
174 if (stat (path
, &st
) == 0
175 && S_ISDIR (st
.st_mode
))
180 /* Temporarily concatenate multiple strings into one. Allows up to 10
181 temporary results; use xstrdup () if you need them to be
184 concat (const char *str
, ...)
186 /* Assume initialized to NULL/zero. */
187 static char *bufs
[10];
188 static size_t buflens
[10];
200 bufn
= (bufn
+ 1) % 10;
203 while ((next
= va_arg (ap
, char *)) != NULL
)
204 len
= len
+ strlen (next
);
210 bufs
[n
] = xmalloc (len
+ 1); /* NUL */
211 buflens
[n
] = len
+ 1;
213 else if (buflens
[n
] < len
+ 1)
215 bufs
[n
] = xrealloc (bufs
[n
], len
+ 1); /* NUL */
216 buflens
[n
] = len
+ 1;
219 strcpy (bufs
[n
], str
);
220 cp
= strchr (bufs
[n
], '\0');
221 while ((next
= va_arg (ap2
, char *)) != NULL
)
224 cp
= strchr (cp
, '\0');
233 /* Like the above, but put spaces between words. Caller frees. */
235 concat_words (char **words
, int num_words
)
241 for (i
= 0; i
< num_words
; i
++)
243 len
+= strlen (words
[i
]);
247 p
= rv
= (char *) xmalloc (len
);
249 for (i
= 0; i
< num_words
; i
++)
253 p
= stpcpy (p
, words
[i
]);
260 /* Try to mount SRC onto DEST. */
262 trymount (const char *src
, const char *dest
)
264 if (mount (src
, dest
, "", MS_BIND
| MS_REC
, NULL
) < 0)
265 FAIL_EXIT1 ("can't mount %s onto %s\n", src
, dest
);
268 /* Special case of above for devices like /dev/zero where we have to
269 mount a device over a device, not a directory over a directory. */
271 devmount (const char *new_root_path
, const char *which
)
274 fd
= open (concat (new_root_path
, "/dev/", which
, NULL
),
275 O_CREAT
| O_TRUNC
| O_RDWR
, 0777);
278 trymount (concat ("/dev/", which
, NULL
),
279 concat (new_root_path
, "/dev/", which
, NULL
));
282 /* Returns true if the string "looks like" an environement variable
285 is_env_setting (const char *a
)
291 if (isalnum (*a
) || *a
== '_')
293 else if (*a
== '=' && count_name
> 0)
302 /* Break the_line into words and store in the_words. Max nwords,
303 returns actual count. */
305 tokenize (char *the_line
, char **the_words
, int nwords
)
311 /* Skip leading whitespace, if any. */
312 while (*the_line
&& isspace (*the_line
))
319 /* THE_LINE points to a non-whitespace character, so we have a
321 *the_words
= the_line
;
326 /* Skip leading whitespace, if any. */
327 while (*the_line
&& ! isspace (*the_line
))
330 /* We now point at the trailing NUL *or* some whitespace. */
334 /* It was whitespace, skip and keep tokenizing. */
338 /* We get here if we filled the words buffer. */
343 /* Mini-RSYNC implementation. Optimize later. */
345 /* A few routines for an "rsync buffer" which stores the paths we're
346 working on. We continuously grow and shrink the paths in each
347 buffer so there's lot of re-use. */
349 /* We rely on "initialized to zero" to set these up. */
357 static path_buf spath
, dpath
;
360 r_setup (char *path
, path_buf
* pb
)
362 size_t len
= strlen (path
);
363 if (pb
->buf
== NULL
|| pb
->size
< len
+ 1)
365 /* Round up. This is an arbitrary number, just to keep from
366 reallocing too often. */
367 size_t sz
= ALIGN_UP (len
+ 1, 512);
369 pb
->buf
= (char *) xmalloc (sz
);
371 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
373 FAIL_EXIT1 ("Out of memory while rsyncing\n");
377 strcpy (pb
->buf
, path
);
382 r_append (const char *path
, path_buf
* pb
)
384 size_t len
= strlen (path
) + pb
->len
;
385 if (pb
->size
< len
+ 1)
388 size_t sz
= ALIGN_UP (len
+ 1, 512);
389 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
391 FAIL_EXIT1 ("Out of memory while rsyncing\n");
395 strcpy (pb
->buf
+ pb
->len
, path
);
400 file_exists (char *path
)
403 if (lstat (path
, &st
) == 0)
409 recursive_remove (char *path
)
419 FAIL_EXIT1 ("Unable to fork");
422 execlp ("rm", "rm", "-rf", path
, NULL
);
423 FAIL_EXIT1 ("exec rm: %m");
426 waitpid (child
, &status
, 0);
427 /* "rm" would have already printed a suitable error message. */
428 if (! WIFEXITED (status
)
429 || WEXITSTATUS (status
) != 0)
430 FAIL_EXIT1 ("exec child returned status: %d", status
);
436 /* Used for both rsync and the mytest.script "cp" command. */
438 copy_one_file (const char *sname
, const char *dname
)
442 struct utimbuf times
;
444 sfd
= open (sname
, O_RDONLY
);
446 FAIL_EXIT1 ("unable to open %s for reading\n", sname
);
448 if (fstat (sfd
, &st
) < 0)
449 FAIL_EXIT1 ("unable to fstat %s\n", sname
);
451 dfd
= open (dname
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0600);
453 FAIL_EXIT1 ("unable to open %s for writing\n", dname
);
455 xcopy_file_range (sfd
, 0, dfd
, 0, st
.st_size
, 0);
460 if (chmod (dname
, st
.st_mode
& 0777) < 0)
461 FAIL_EXIT1 ("chmod %s: %s\n", dname
, strerror (errno
));
463 times
.actime
= st
.st_atime
;
464 times
.modtime
= st
.st_mtime
;
465 if (utime (dname
, ×
) < 0)
466 FAIL_EXIT1 ("utime %s: %s\n", dname
, strerror (errno
));
469 /* We don't check *everything* about the two files to see if a copy is
470 needed, just the minimum to make sure we get the latest copy. */
472 need_sync (char *ap
, char *bp
, struct stat
*a
, struct stat
*b
)
474 if ((a
->st_mode
& S_IFMT
) != (b
->st_mode
& S_IFMT
))
477 if (S_ISLNK (a
->st_mode
))
482 if (a
->st_size
!= b
->st_size
)
487 rv
= strcmp (al
, bl
);
491 return 0; /* links are same */
492 return 1; /* links differ */
497 if (a
->st_size
!= b
->st_size
)
499 if ((a
->st_mode
& 0777) != (b
->st_mode
& 0777))
501 if (a
->st_mtime
!= b
->st_mtime
)
505 if (a
->st_size
== b
->st_size
506 && ((a
->st_mode
& 0777) == (b
->st_mode
& 0777))
507 && a
->st_mtime
== b
->st_mtime
)
514 rsync_1 (path_buf
* src
, path_buf
* dest
, int and_delete
, int force_copies
)
521 r_append ("/", dest
);
524 printf ("sync %s to %s%s%s\n", src
->buf
, dest
->buf
,
525 and_delete
? " and delete" : "",
526 force_copies
? " (forced)" : "");
528 size_t staillen
= src
->len
;
530 size_t dtaillen
= dest
->len
;
532 dir
= opendir (src
->buf
);
534 while ((de
= readdir (dir
)) != NULL
)
536 if (strcmp (de
->d_name
, ".") == 0
537 || strcmp (de
->d_name
, "..") == 0)
541 r_append (de
->d_name
, src
);
542 dest
->len
= dtaillen
;
543 r_append (de
->d_name
, dest
);
548 if (lstat (src
->buf
, &s
) != 0)
549 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src
->buf
);
551 /* It's OK if this one fails, since we know the file might be
553 lstat (dest
->buf
, &d
);
555 if (! force_copies
&& ! need_sync (src
->buf
, dest
->buf
, &s
, &d
))
557 if (S_ISDIR (s
.st_mode
))
558 rsync_1 (src
, dest
, and_delete
, force_copies
);
563 switch (d
.st_mode
& S_IFMT
)
566 if (!S_ISDIR (s
.st_mode
))
569 printf ("-D %s\n", dest
->buf
);
570 recursive_remove (dest
->buf
);
576 printf ("-F %s\n", dest
->buf
);
577 maybe_xunlink (dest
->buf
);
581 switch (s
.st_mode
& S_IFMT
)
585 printf ("+F %s\n", dest
->buf
);
586 copy_one_file (src
->buf
, dest
->buf
);
591 printf ("+D %s\n", dest
->buf
);
592 maybe_xmkdir (dest
->buf
, (s
.st_mode
& 0777) | 0700);
593 rsync_1 (src
, dest
, and_delete
, force_copies
);
600 printf ("+L %s\n", dest
->buf
);
601 lp
= xreadlink (src
->buf
);
602 xsymlink (lp
, dest
->buf
);
614 src
->buf
[staillen
] = 0;
615 dest
->len
= dtaillen
;
616 dest
->buf
[dtaillen
] = 0;
621 /* The rest of this function removes any files/directories in DEST
622 that do not exist in SRC. This is triggered as part of a
623 preclean or postsclean step. */
625 dir
= opendir (dest
->buf
);
627 while ((de
= readdir (dir
)) != NULL
)
629 if (strcmp (de
->d_name
, ".") == 0
630 || strcmp (de
->d_name
, "..") == 0)
634 r_append (de
->d_name
, src
);
635 dest
->len
= dtaillen
;
636 r_append (de
->d_name
, dest
);
641 lstat (src
->buf
, &s
);
643 if (lstat (dest
->buf
, &d
) != 0)
644 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest
->buf
);
648 /* dest exists and src doesn't, clean it. */
649 switch (d
.st_mode
& S_IFMT
)
652 if (!S_ISDIR (s
.st_mode
))
655 printf ("-D %s\n", dest
->buf
);
656 recursive_remove (dest
->buf
);
662 printf ("-F %s\n", dest
->buf
);
663 maybe_xunlink (dest
->buf
);
673 rsync (char *src
, char *dest
, int and_delete
, int force_copies
)
675 r_setup (src
, &spath
);
676 r_setup (dest
, &dpath
);
678 rsync_1 (&spath
, &dpath
, and_delete
, force_copies
);
683 /* See if we can detect what the user needs to do to get unshare
684 support working for us. */
686 check_for_unshare_hints (int require_pidns
)
690 int bad_value
, good_value
, for_pidns
;
692 /* Default Debian Linux disables user namespaces, but allows a way
694 { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
695 /* ALT Linux has an alternate way of doing the same. */
696 { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
697 /* Linux kernel >= 4.9 has a configurable limit on the number of
698 each namespace. Some distros set the limit to zero to disable the
699 corresponding namespace as a "security policy". */
700 { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
701 { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
702 { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
707 for (i
= 0; i
< array_length (files
); i
++)
709 if (!require_pidns
&& files
[i
].for_pidns
)
712 f
= fopen (files
[i
].path
, "r");
716 val
= -1; /* Sentinel. */
717 fscanf (f
, "%d", &val
);
718 if (val
!= files
[i
].bad_value
)
721 printf ("To enable test-container, please run this as root:\n");
722 printf (" echo %d > %s\n", files
[i
].good_value
, files
[i
].path
);
728 run_ldconfig (void *x
__attribute__((unused
)))
730 char *prog
= xasprintf ("%s/ldconfig", support_install_rootsbindir
);
731 char *args
[] = { prog
, NULL
};
733 execv (args
[0], args
);
734 FAIL_EXIT1 ("execv: %m");
738 main (int argc
, char **argv
)
741 char *pristine_root_path
;
744 char *new_objdir_path
;
745 char *new_srcdir_path
;
746 char **new_child_proc
;
747 char *new_child_exec
;
750 char *command_basename
;
752 int do_postclean
= 0;
753 bool do_ldconfig
= false;
754 char *change_cwd
= NULL
;
761 /* If set, the test runs as root instead of the user running the testsuite. */
763 int require_pidns
= 0;
765 const char *pidns_comment
= NULL
;
767 int do_proc_mounts
= 0;
770 /* Used for "%lld %lld 1" so need not be large. */
775 setbuf (stdout
, NULL
);
777 /* The command line we're expecting looks like this:
778 env <set some vars> ld.so <library path> test-binary
780 We need to peel off any "env" or "ld.so" portion of the command
781 line, and keep track of which env vars we should preserve and
786 fprintf (stderr
, "Usage: test-container <program to run> <args...>\n");
790 if (strcmp (argv
[1], "-v") == 0)
797 if (strcmp (argv
[1], "env") == 0)
801 while (is_env_setting (argv
[1]))
803 /* If there are variables we do NOT want to propogate, this
804 is where the test for them goes. */
806 /* Need to keep these. Note that putenv stores a
807 pointer to our argv. */
815 if (strcmp (argv
[1], support_objdir_elf_ldso
) == 0)
819 while (argv
[1][0] == '-')
821 if (strcmp (argv
[1], "--library-path") == 0)
831 pristine_root_path
= xstrdup (concat (support_objdir_root
,
832 "/testroot.pristine", NULL
));
833 new_root_path
= xstrdup (concat (support_objdir_root
,
834 "/testroot.root", NULL
));
835 new_cwd_path
= get_current_dir_name ();
836 new_child_proc
= argv
+ 1;
837 new_child_exec
= argv
[1];
839 lock_fd
= open (concat (pristine_root_path
, "/lock.fd", NULL
),
840 O_CREAT
| O_TRUNC
| O_RDWR
, 0666);
842 FAIL_EXIT1 ("Cannot create testroot lock.\n");
844 while (flock (lock_fd
, LOCK_EX
) != 0)
847 FAIL_EXIT1 ("Cannot lock testroot.\n");
850 xmkdirp (new_root_path
, 0755);
852 /* We look for extra setup info in a subdir in the same spot as the
853 test, with the same name but a ".root" extension. This is that
854 directory. We try to look in the source tree if the path we're
855 given refers to the build tree, but we rely on the path to be
856 absolute. This is what the glibc makefiles do. */
857 command_root
= concat (argv
[1], ".root", NULL
);
858 if (strncmp (command_root
, support_objdir_root
,
859 strlen (support_objdir_root
)) == 0
860 && command_root
[strlen (support_objdir_root
)] == '/')
861 command_root
= concat (support_srcdir_root
,
862 argv
[1] + strlen (support_objdir_root
),
864 command_root
= xstrdup (command_root
);
866 /* This cuts off the ".root" we appended above. */
867 command_base
= xstrdup (command_root
);
868 command_base
[strlen (command_base
) - 5] = 0;
870 /* This is the basename of the test we're running. */
871 command_basename
= strrchr (command_base
, '/');
872 if (command_basename
== NULL
)
873 command_basename
= command_base
;
877 /* Shared object base directory. */
878 so_base
= xstrdup (argv
[1]);
879 if (strrchr (so_base
, '/') != NULL
)
880 strrchr (so_base
, '/')[1] = 0;
882 if (file_exists (concat (command_root
, "/postclean.req", NULL
)))
885 if (file_exists (concat (command_root
, "/ldconfig.run", NULL
)))
888 rsync (pristine_root_path
, new_root_path
,
889 file_exists (concat (command_root
, "/preclean.req", NULL
)), 0);
891 if (stat (command_root
, &st
) >= 0
892 && S_ISDIR (st
.st_mode
))
893 rsync (command_root
, new_root_path
, 0, 1);
895 new_objdir_path
= xstrdup (concat (new_root_path
,
896 support_objdir_root
, NULL
));
897 new_srcdir_path
= xstrdup (concat (new_root_path
,
898 support_srcdir_root
, NULL
));
900 /* new_cwd_path starts with '/' so no "/" needed between the two. */
901 xmkdirp (concat (new_root_path
, new_cwd_path
, NULL
), 0755);
902 xmkdirp (new_srcdir_path
, 0755);
903 xmkdirp (new_objdir_path
, 0755);
905 original_uid
= getuid ();
906 original_gid
= getgid ();
908 /* Handle the cp/mv/rm "script" here. */
910 char *the_line
= NULL
;
912 char *fname
= concat (command_root
, "/",
913 command_basename
, ".script", NULL
);
915 FILE *f
= fopen (fname
, "r");
918 fprintf (stderr
, "running %s\n", fname
);
922 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
923 fname
= concat (command_base
, ".script", NULL
);
924 f
= fopen (fname
, "r");
926 fprintf (stderr
, "running %s\n", fname
);
929 /* Note that we do NOT look for a Makefile-generated foo.script in
930 the build directory. If that is ever needed, this is the place
933 /* This is where we "interpret" the mini-script which is <test>.script. */
936 while (getline (&the_line
, &line_len
, f
) > 0)
938 int nt
= tokenize (the_line
, the_words
, 3);
941 /* Expand variables. */
942 for (i
= 1; i
< nt
; ++i
)
944 if (memcmp (the_words
[i
], "$B/", 3) == 0)
945 the_words
[i
] = concat (support_objdir_root
,
946 the_words
[i
] + 2, NULL
);
947 else if (memcmp (the_words
[i
], "$S/", 3) == 0)
948 the_words
[i
] = concat (support_srcdir_root
,
949 the_words
[i
] + 2, NULL
);
950 else if (memcmp (the_words
[i
], "$I/", 3) == 0)
951 the_words
[i
] = concat (new_root_path
,
952 support_install_prefix
,
953 the_words
[i
] + 2, NULL
);
954 else if (memcmp (the_words
[i
], "$L/", 3) == 0)
955 the_words
[i
] = concat (new_root_path
,
956 support_libdir_prefix
,
957 the_words
[i
] + 2, NULL
);
958 else if (memcmp (the_words
[i
], "$complocaledir/", 15) == 0)
959 the_words
[i
] = concat (new_root_path
,
960 support_complocaledir_prefix
,
961 the_words
[i
] + 14, NULL
);
962 /* "exec" and "cwd" use inside-root paths. */
963 else if (strcmp (the_words
[0], "exec") != 0
964 && strcmp (the_words
[0], "cwd") != 0
965 && the_words
[i
][0] == '/')
966 the_words
[i
] = concat (new_root_path
,
970 if (nt
== 3 && the_words
[2][strlen (the_words
[2]) - 1] == '/')
972 char *r
= strrchr (the_words
[1], '/');
974 the_words
[2] = concat (the_words
[2], r
+ 1, NULL
);
976 the_words
[2] = concat (the_words
[2], the_words
[1], NULL
);
979 /* Run the following commands in the_words[0] with NT number of
980 arguments (including the command). */
982 if (nt
== 2 && strcmp (the_words
[0], "so") == 0)
984 the_words
[2] = concat (new_root_path
, support_libdir_prefix
,
985 "/", the_words
[1], NULL
);
986 the_words
[1] = concat (so_base
, the_words
[1], NULL
);
987 copy_one_file (the_words
[1], the_words
[2]);
989 else if (nt
== 3 && strcmp (the_words
[0], "cp") == 0)
991 copy_one_file (the_words
[1], the_words
[2]);
993 else if (nt
== 3 && strcmp (the_words
[0], "mv") == 0)
995 if (rename (the_words
[1], the_words
[2]) < 0)
996 FAIL_EXIT1 ("rename %s -> %s: %s", the_words
[1],
997 the_words
[2], strerror (errno
));
999 else if (nt
== 3 && strcmp (the_words
[0], "chmod") == 0)
1003 m
= strtol (the_words
[1], NULL
, 0);
1004 TEST_COMPARE (errno
, 0);
1005 if (chmod (the_words
[2], m
) < 0)
1006 FAIL_EXIT1 ("chmod %s: %s\n",
1007 the_words
[2], strerror (errno
));
1010 else if (nt
== 2 && strcmp (the_words
[0], "rm") == 0)
1012 maybe_xunlink (the_words
[1]);
1014 else if (nt
>= 2 && strcmp (the_words
[0], "exec") == 0)
1016 /* The first argument is the desired location and name
1017 of the test binary as we wish to exec it; we will
1018 copy the binary there. The second (optional)
1019 argument is the value to pass as argv[0], it
1020 defaults to the same as the first argument. */
1021 char *new_exec_path
= the_words
[1];
1023 /* If the new exec path ends with a slash, that's the
1024 * directory, and use the old test base name. */
1025 if (new_exec_path
[strlen(new_exec_path
) - 1] == '/')
1026 new_exec_path
= concat (new_exec_path
,
1027 basename (new_child_proc
[0]),
1031 /* new_child_proc is in the build tree, so has the
1032 same path inside the chroot as outside. The new
1033 exec path is, by definition, relative to the
1035 copy_one_file (new_child_proc
[0], concat (new_root_path
,
1039 new_child_exec
= xstrdup (new_exec_path
);
1041 new_child_proc
[0] = xstrdup (the_words
[2]);
1043 new_child_proc
[0] = new_child_exec
;
1045 else if (nt
== 2 && strcmp (the_words
[0], "cwd") == 0)
1047 change_cwd
= xstrdup (the_words
[1]);
1049 else if (nt
== 1 && strcmp (the_words
[0], "su") == 0)
1053 else if (nt
>= 1 && strcmp (the_words
[0], "pidns") == 0)
1058 pidns_comment
= concat_words (the_words
+ 1, nt
- 1);
1061 else if (nt
== 3 && strcmp (the_words
[0], "mkdirp") == 0)
1065 m
= strtol (the_words
[1], NULL
, 0);
1066 TEST_COMPARE (errno
, 0);
1067 xmkdirp (the_words
[2], m
);
1069 else if (nt
> 0 && the_words
[0][0] != '#')
1071 fprintf (stderr
, "\033[31minvalid [%s]\033[0m\n", the_words
[0]);
1081 pid_t pc_pid
= fork ();
1085 FAIL_EXIT1 ("Can't fork for post-clean");
1087 else if (pc_pid
> 0)
1091 waitpid (pc_pid
, &status
, 0);
1093 /* Child has exited, we can post-clean the test root. */
1094 printf("running post-clean rsync\n");
1095 rsync (pristine_root_path
, new_root_path
, 1, 0);
1097 if (WIFEXITED (status
))
1098 exit (WEXITSTATUS (status
));
1100 if (WIFSIGNALED (status
))
1102 printf ("%%SIGNALLED%%\n");
1106 printf ("%%EXITERROR%%\n");
1110 /* Child continues. */
1113 /* This is the last point in the program where we're still in the
1114 "normal" namespace. */
1117 /* The unshare here gives us our own spaces and capabilities. */
1118 if (unshare (CLONE_NEWUSER
| CLONE_NEWNS
1119 | (require_pidns
? CLONE_NEWPID
: 0)) < 0)
1121 /* Older kernels may not support all the options, or security
1122 policy may block this call. */
1123 if (errno
== EINVAL
|| errno
== EPERM
|| errno
== ENOSPC
)
1125 int saved_errno
= errno
;
1126 if (errno
== EPERM
|| errno
== ENOSPC
)
1127 check_for_unshare_hints (require_pidns
);
1128 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno
));
1130 /* We're about to exit anyway, it's "safe" to call unshare again
1131 just to see if the CLONE_NEWPID caused the error. */
1132 else if (require_pidns
&& unshare (CLONE_NEWUSER
| CLONE_NEWNS
) >= 0)
1133 FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno
),
1134 pidns_comment
? pidns_comment
: "required by test");
1136 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno
));
1139 /* Some targets may not support unshare at all. */
1140 FAIL_UNSUPPORTED ("unshare support missing");
1143 /* Some systems, by default, all mounts leak out of the namespace. */
1144 if (mount ("none", "/", NULL
, MS_REC
| MS_PRIVATE
, NULL
) != 0)
1145 FAIL_EXIT1 ("could not create a private mount namespace\n");
1147 trymount (support_srcdir_root
, new_srcdir_path
);
1148 trymount (support_objdir_root
, new_objdir_path
);
1150 /* It may not be possible to mount /proc directly. */
1151 if (! require_pidns
)
1153 char *new_proc
= concat (new_root_path
, "/proc", NULL
);
1154 xmkdirp (new_proc
, 0755);
1155 trymount ("/proc", new_proc
);
1159 xmkdirp (concat (new_root_path
, "/dev", NULL
), 0755);
1160 devmount (new_root_path
, "null");
1161 devmount (new_root_path
, "zero");
1162 devmount (new_root_path
, "urandom");
1164 /* We're done with the "old" root, switch to the new one. */
1165 if (chroot (new_root_path
) < 0)
1166 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path
);
1168 if (chdir (new_cwd_path
) < 0)
1169 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path
);
1171 /* This is to pass the "outside" PID to the child, which will be PID
1173 if (pipe2 (pipes
, O_CLOEXEC
) < 0)
1174 FAIL_EXIT1 ("Can't create pid pipe");
1176 /* To complete the containerization, we need to fork () at least
1177 once. We can't exec, nor can we somehow link the new child to
1178 our parent. So we run the child and propogate it's exit status
1182 FAIL_EXIT1 ("Unable to fork");
1188 /* Send the child's "outside" pid to it. */
1189 xwrite (pipes
[1], &child
, sizeof(child
));
1193 waitpid (child
, &status
, 0);
1195 if (WIFEXITED (status
))
1196 exit (WEXITSTATUS (status
));
1198 if (WIFSIGNALED (status
))
1200 printf ("%%SIGNALLED%%\n");
1204 printf ("%%EXITERROR%%\n");
1208 /* The rest is the child process, which is now PID 1 and "in" the
1213 struct support_capture_subprocess result
=
1214 support_capture_subprocess (run_ldconfig
, NULL
);
1215 support_capture_subprocess_check (&result
, "execv", 0, sc_allow_none
);
1218 /* Get our "outside" pid from our parent. We use this to help with
1219 debugging from outside the container. */
1220 read (pipes
[0], &child
, sizeof(child
));
1223 sprintf (pid_buf
, "%lu", (long unsigned)child
);
1224 setenv ("PID_OUTSIDE_CONTAINER", pid_buf
, 0);
1226 maybe_xmkdir ("/tmp", 0755);
1230 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1231 maybe_xmkdir ("/proc", 0777);
1232 if (mount ("proc", "/proc", "proc", 0, NULL
) != 0)
1234 /* This happens if we're trying to create a nested container,
1235 like if the build is running under podman, and we lack
1238 Ideally we would WARN here, but that would just add noise to
1239 *every* test-container test, and the ones that care should
1240 have their own relevent diagnostics.
1242 FAIL_EXIT1 ("Unable to mount /proc: "); */
1250 /* We map our original UID to the same UID in the container so we
1251 can own our own files normally. */
1252 UMAP
= open ("/proc/self/uid_map", O_WRONLY
);
1254 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1256 sprintf (tmp
, "%lld %lld 1\n",
1257 (long long) (be_su
? 0 : original_uid
), (long long) original_uid
);
1258 xwrite (UMAP
, tmp
, strlen (tmp
));
1261 /* We must disable setgroups () before we can map our groups, else we
1263 GMAP
= open ("/proc/self/setgroups", O_WRONLY
);
1266 /* We support kernels old enough to not have this. */
1267 xwrite (GMAP
, "deny\n", 5);
1271 /* We map our original GID to the same GID in the container so we
1272 can own our own files normally. */
1273 GMAP
= open ("/proc/self/gid_map", O_WRONLY
);
1275 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1277 sprintf (tmp
, "%lld %lld 1\n",
1278 (long long) (be_su
? 0 : original_gid
), (long long) original_gid
);
1279 xwrite (GMAP
, tmp
, strlen (tmp
));
1285 if (chdir (change_cwd
) < 0)
1286 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd
);
1289 /* Now run the child. */
1290 execvp (new_child_exec
, new_child_proc
);
1292 /* Or don't run the child? */
1293 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec
, strerror (errno
));
1295 /* Because gcc won't know error () never returns... */
1296 exit (EXIT_UNSUPPORTED
);