1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2022 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 #define _FILE_OFFSET_BITS 64
21 #include <array_length.h>
26 #include <sys/syscall.h>
28 #include <sys/types.h>
32 #include <sys/fcntl.h>
36 #include <sys/sysmacros.h>
41 #include <libc-pointer-arith.h>
44 #include <sys/mount.h>
47 #include <support/support.h>
48 #include <support/xunistd.h>
49 #include <support/capture_subprocess.h>
51 #include "test-driver.h"
54 #define mount(s,t,fs,f,d) no_mount()
57 FAIL_UNSUPPORTED("mount not supported; port needed");
63 /* Running a test in a container is tricky. There are two main
64 categories of things to do:
66 1. "Once" actions, like setting up the container and doing an
69 2. "Per-test" actions, like copying in support files and
70 configuring the container.
75 * mkdir $buildroot/testroot.pristine/
77 * default glibc install
78 * create /bin for /bin/sh
79 * create $(complocaledir) so localedef tests work with default paths.
80 * install /bin/sh, /bin/echo, and /bin/true.
81 * rsync to $buildroot/testroot.root/
84 * maybe rsync to $buildroot/testroot.root/
85 * copy support files and test binary
87 * set up any mounts (like /proc)
92 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
95 * mytest.root/ is rsync'd into container
96 * mytest.root/preclean.req causes fresh rsync (with delete) before
98 * mytest.root/mytest.script has a list of "commands" to run:
111 $B/ build dir, equivalent to $(common-objpfx)
112 $S/ source dir, equivalent to $(srcdir)
113 $I/ install dir, equivalent to $(prefix)
114 $L/ library dir (in container), equivalent to $(libdir)
115 $complocaledir/ compiled locale dir, equivalent to $(complocaledir)
118 If FILE begins with any of these variables then they will be
119 substituted for the described value.
121 The goal is to expose as many of the runtime's configured paths
122 via variables so they can be used to setup the container environment
123 before execution reaches the test.
127 - 'pidns': Require a separate PID namespace, prints comment if it can't
128 (default is a shared pid namespace)
129 - 'su': Enables running test as root in the container.
130 - 'mv': A minimal move files command.
131 - 'cp': A minimal copy files command.
132 - 'rm': A minimal remove files command.
133 - 'cwd': set test working directory
134 - 'exec': change test binary location (may end in /)
135 - 'mkdirp': A minimal "mkdir -p FILE" command.
137 * mytest.root/postclean.req causes fresh rsync (with delete) after
140 * mytest.root/ldconfig.run causes ldconfig to be issued prior
141 test execution (to setup the initial ld.so.cache).
143 Note that $srcdir/foo/mytest.script may be used instead of a
144 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
145 there is no other reason for a sysroot.
149 * independent of other packages which may not be installed (like
150 rsync or Docker, or even "cp")
152 * Simple, easy to review code (i.e. prefer simple naive code over
153 complex efficient code)
155 * The current implementation is parallel-make-safe, but only in
156 that it uses a lock to prevent parallel access to the testroot. */
159 /* Utility Functions */
161 /* Like xunlink, but it's OK if the file already doesn't exist. */
163 maybe_xunlink (const char *path
)
165 int rv
= unlink (path
);
166 if (rv
< 0 && errno
!= ENOENT
)
167 FAIL_EXIT1 ("unlink (\"%s\"): %m", path
);
170 /* Like xmkdir, but it's OK if the directory already exists. */
172 maybe_xmkdir (const char *path
, mode_t mode
)
176 if (stat (path
, &st
) == 0
177 && S_ISDIR (st
.st_mode
))
182 /* Temporarily concatenate multiple strings into one. Allows up to 10
183 temporary results; use xstrdup () if you need them to be
186 concat (const char *str
, ...)
188 /* Assume initialized to NULL/zero. */
189 static char *bufs
[10];
190 static size_t buflens
[10];
202 bufn
= (bufn
+ 1) % 10;
205 while ((next
= va_arg (ap
, char *)) != NULL
)
206 len
= len
+ strlen (next
);
212 bufs
[n
] = xmalloc (len
+ 1); /* NUL */
213 buflens
[n
] = len
+ 1;
215 else if (buflens
[n
] < len
+ 1)
217 bufs
[n
] = xrealloc (bufs
[n
], len
+ 1); /* NUL */
218 buflens
[n
] = len
+ 1;
221 strcpy (bufs
[n
], str
);
222 cp
= strchr (bufs
[n
], '\0');
223 while ((next
= va_arg (ap2
, char *)) != NULL
)
226 cp
= strchr (cp
, '\0');
235 /* Like the above, but put spaces between words. Caller frees. */
237 concat_words (char **words
, int num_words
)
243 for (i
= 0; i
< num_words
; i
++)
245 len
+= strlen (words
[i
]);
249 p
= rv
= (char *) xmalloc (len
);
251 for (i
= 0; i
< num_words
; i
++)
255 p
= stpcpy (p
, words
[i
]);
262 /* Try to mount SRC onto DEST. */
264 trymount (const char *src
, const char *dest
)
266 if (mount (src
, dest
, "", MS_BIND
| MS_REC
, NULL
) < 0)
267 FAIL_EXIT1 ("can't mount %s onto %s\n", src
, dest
);
270 /* Special case of above for devices like /dev/zero where we have to
271 mount a device over a device, not a directory over a directory. */
273 devmount (const char *new_root_path
, const char *which
)
276 fd
= open (concat (new_root_path
, "/dev/", which
, NULL
),
277 O_CREAT
| O_TRUNC
| O_RDWR
, 0777);
280 trymount (concat ("/dev/", which
, NULL
),
281 concat (new_root_path
, "/dev/", which
, NULL
));
284 /* Returns true if the string "looks like" an environement variable
287 is_env_setting (const char *a
)
293 if (isalnum (*a
) || *a
== '_')
295 else if (*a
== '=' && count_name
> 0)
304 /* Break the_line into words and store in the_words. Max nwords,
305 returns actual count. */
307 tokenize (char *the_line
, char **the_words
, int nwords
)
313 /* Skip leading whitespace, if any. */
314 while (*the_line
&& isspace (*the_line
))
321 /* THE_LINE points to a non-whitespace character, so we have a
323 *the_words
= the_line
;
328 /* Skip leading whitespace, if any. */
329 while (*the_line
&& ! isspace (*the_line
))
332 /* We now point at the trailing NUL *or* some whitespace. */
336 /* It was whitespace, skip and keep tokenizing. */
340 /* We get here if we filled the words buffer. */
345 /* Mini-RSYNC implementation. Optimize later. */
347 /* A few routines for an "rsync buffer" which stores the paths we're
348 working on. We continuously grow and shrink the paths in each
349 buffer so there's lot of re-use. */
351 /* We rely on "initialized to zero" to set these up. */
359 static path_buf spath
, dpath
;
362 r_setup (char *path
, path_buf
* pb
)
364 size_t len
= strlen (path
);
365 if (pb
->buf
== NULL
|| pb
->size
< len
+ 1)
367 /* Round up. This is an arbitrary number, just to keep from
368 reallocing too often. */
369 size_t sz
= ALIGN_UP (len
+ 1, 512);
371 pb
->buf
= (char *) xmalloc (sz
);
373 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
375 FAIL_EXIT1 ("Out of memory while rsyncing\n");
379 strcpy (pb
->buf
, path
);
384 r_append (const char *path
, path_buf
* pb
)
386 size_t len
= strlen (path
) + pb
->len
;
387 if (pb
->size
< len
+ 1)
390 size_t sz
= ALIGN_UP (len
+ 1, 512);
391 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
393 FAIL_EXIT1 ("Out of memory while rsyncing\n");
397 strcpy (pb
->buf
+ pb
->len
, path
);
402 file_exists (char *path
)
405 if (lstat (path
, &st
) == 0)
411 recursive_remove (char *path
)
421 FAIL_EXIT1 ("Unable to fork");
424 execlp ("rm", "rm", "-rf", path
, NULL
);
425 FAIL_EXIT1 ("exec rm: %m");
428 waitpid (child
, &status
, 0);
429 /* "rm" would have already printed a suitable error message. */
430 if (! WIFEXITED (status
)
431 || WEXITSTATUS (status
) != 0)
432 FAIL_EXIT1 ("exec child returned status: %d", status
);
438 /* Used for both rsync and the mytest.script "cp" command. */
440 copy_one_file (const char *sname
, const char *dname
)
444 struct utimbuf times
;
446 sfd
= open (sname
, O_RDONLY
);
448 FAIL_EXIT1 ("unable to open %s for reading\n", sname
);
450 if (fstat (sfd
, &st
) < 0)
451 FAIL_EXIT1 ("unable to fstat %s\n", sname
);
453 dfd
= open (dname
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0600);
455 FAIL_EXIT1 ("unable to open %s for writing\n", dname
);
457 xcopy_file_range (sfd
, 0, dfd
, 0, st
.st_size
, 0);
462 if (chmod (dname
, st
.st_mode
& 0777) < 0)
463 FAIL_EXIT1 ("chmod %s: %s\n", dname
, strerror (errno
));
465 times
.actime
= st
.st_atime
;
466 times
.modtime
= st
.st_mtime
;
467 if (utime (dname
, ×
) < 0)
468 FAIL_EXIT1 ("utime %s: %s\n", dname
, strerror (errno
));
471 /* We don't check *everything* about the two files to see if a copy is
472 needed, just the minimum to make sure we get the latest copy. */
474 need_sync (char *ap
, char *bp
, struct stat
*a
, struct stat
*b
)
476 if ((a
->st_mode
& S_IFMT
) != (b
->st_mode
& S_IFMT
))
479 if (S_ISLNK (a
->st_mode
))
484 if (a
->st_size
!= b
->st_size
)
489 rv
= strcmp (al
, bl
);
493 return 0; /* links are same */
494 return 1; /* links differ */
499 if (a
->st_size
!= b
->st_size
)
501 if ((a
->st_mode
& 0777) != (b
->st_mode
& 0777))
503 if (a
->st_mtime
!= b
->st_mtime
)
507 if (a
->st_size
== b
->st_size
508 && ((a
->st_mode
& 0777) == (b
->st_mode
& 0777))
509 && a
->st_mtime
== b
->st_mtime
)
516 rsync_1 (path_buf
* src
, path_buf
* dest
, int and_delete
, int force_copies
)
523 r_append ("/", dest
);
526 printf ("sync %s to %s%s%s\n", src
->buf
, dest
->buf
,
527 and_delete
? " and delete" : "",
528 force_copies
? " (forced)" : "");
530 size_t staillen
= src
->len
;
532 size_t dtaillen
= dest
->len
;
534 dir
= opendir (src
->buf
);
536 while ((de
= readdir (dir
)) != NULL
)
538 if (strcmp (de
->d_name
, ".") == 0
539 || strcmp (de
->d_name
, "..") == 0)
543 r_append (de
->d_name
, src
);
544 dest
->len
= dtaillen
;
545 r_append (de
->d_name
, dest
);
550 if (lstat (src
->buf
, &s
) != 0)
551 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src
->buf
);
553 /* It's OK if this one fails, since we know the file might be
555 lstat (dest
->buf
, &d
);
557 if (! force_copies
&& ! need_sync (src
->buf
, dest
->buf
, &s
, &d
))
559 if (S_ISDIR (s
.st_mode
))
560 rsync_1 (src
, dest
, and_delete
, force_copies
);
565 switch (d
.st_mode
& S_IFMT
)
568 if (!S_ISDIR (s
.st_mode
))
571 printf ("-D %s\n", dest
->buf
);
572 recursive_remove (dest
->buf
);
578 printf ("-F %s\n", dest
->buf
);
579 maybe_xunlink (dest
->buf
);
583 switch (s
.st_mode
& S_IFMT
)
587 printf ("+F %s\n", dest
->buf
);
588 copy_one_file (src
->buf
, dest
->buf
);
593 printf ("+D %s\n", dest
->buf
);
594 maybe_xmkdir (dest
->buf
, (s
.st_mode
& 0777) | 0700);
595 rsync_1 (src
, dest
, and_delete
, force_copies
);
602 printf ("+L %s\n", dest
->buf
);
603 lp
= xreadlink (src
->buf
);
604 xsymlink (lp
, dest
->buf
);
616 src
->buf
[staillen
] = 0;
617 dest
->len
= dtaillen
;
618 dest
->buf
[dtaillen
] = 0;
623 /* The rest of this function removes any files/directories in DEST
624 that do not exist in SRC. This is triggered as part of a
625 preclean or postsclean step. */
627 dir
= opendir (dest
->buf
);
629 while ((de
= readdir (dir
)) != NULL
)
631 if (strcmp (de
->d_name
, ".") == 0
632 || strcmp (de
->d_name
, "..") == 0)
636 r_append (de
->d_name
, src
);
637 dest
->len
= dtaillen
;
638 r_append (de
->d_name
, dest
);
643 lstat (src
->buf
, &s
);
645 if (lstat (dest
->buf
, &d
) != 0)
646 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest
->buf
);
650 /* dest exists and src doesn't, clean it. */
651 switch (d
.st_mode
& S_IFMT
)
654 if (!S_ISDIR (s
.st_mode
))
657 printf ("-D %s\n", dest
->buf
);
658 recursive_remove (dest
->buf
);
664 printf ("-F %s\n", dest
->buf
);
665 maybe_xunlink (dest
->buf
);
675 rsync (char *src
, char *dest
, int and_delete
, int force_copies
)
677 r_setup (src
, &spath
);
678 r_setup (dest
, &dpath
);
680 rsync_1 (&spath
, &dpath
, and_delete
, force_copies
);
685 /* See if we can detect what the user needs to do to get unshare
686 support working for us. */
688 check_for_unshare_hints (int require_pidns
)
692 int bad_value
, good_value
, for_pidns
;
694 /* Default Debian Linux disables user namespaces, but allows a way
696 { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
697 /* ALT Linux has an alternate way of doing the same. */
698 { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
699 /* Linux kernel >= 4.9 has a configurable limit on the number of
700 each namespace. Some distros set the limit to zero to disable the
701 corresponding namespace as a "security policy". */
702 { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
703 { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
704 { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
709 for (i
= 0; i
< array_length (files
); i
++)
711 if (!require_pidns
&& files
[i
].for_pidns
)
714 f
= fopen (files
[i
].path
, "r");
718 val
= -1; /* Sentinel. */
719 fscanf (f
, "%d", &val
);
720 if (val
!= files
[i
].bad_value
)
723 printf ("To enable test-container, please run this as root:\n");
724 printf (" echo %d > %s\n", files
[i
].good_value
, files
[i
].path
);
730 run_ldconfig (void *x
__attribute__((unused
)))
732 char *prog
= xasprintf ("%s/ldconfig", support_install_rootsbindir
);
733 char *args
[] = { prog
, NULL
};
735 execv (args
[0], args
);
736 FAIL_EXIT1 ("execv: %m");
740 main (int argc
, char **argv
)
743 char *pristine_root_path
;
746 char *new_objdir_path
;
747 char *new_srcdir_path
;
748 char **new_child_proc
;
749 char *new_child_exec
;
752 char *command_basename
;
754 int do_postclean
= 0;
755 bool do_ldconfig
= false;
756 char *change_cwd
= NULL
;
763 /* If set, the test runs as root instead of the user running the testsuite. */
765 int require_pidns
= 0;
767 const char *pidns_comment
= NULL
;
769 int do_proc_mounts
= 0;
772 /* Used for "%lld %lld 1" so need not be large. */
777 setbuf (stdout
, NULL
);
779 /* The command line we're expecting looks like this:
780 env <set some vars> ld.so <library path> test-binary
782 We need to peel off any "env" or "ld.so" portion of the command
783 line, and keep track of which env vars we should preserve and
788 fprintf (stderr
, "Usage: test-container <program to run> <args...>\n");
792 if (strcmp (argv
[1], "-v") == 0)
799 if (strcmp (argv
[1], "env") == 0)
803 while (is_env_setting (argv
[1]))
805 /* If there are variables we do NOT want to propogate, this
806 is where the test for them goes. */
808 /* Need to keep these. Note that putenv stores a
809 pointer to our argv. */
817 if (strcmp (argv
[1], support_objdir_elf_ldso
) == 0)
821 while (argv
[1][0] == '-')
823 if (strcmp (argv
[1], "--library-path") == 0)
833 pristine_root_path
= xstrdup (concat (support_objdir_root
,
834 "/testroot.pristine", NULL
));
835 new_root_path
= xstrdup (concat (support_objdir_root
,
836 "/testroot.root", NULL
));
837 new_cwd_path
= get_current_dir_name ();
838 new_child_proc
= argv
+ 1;
839 new_child_exec
= argv
[1];
841 lock_fd
= open (concat (pristine_root_path
, "/lock.fd", NULL
),
842 O_CREAT
| O_TRUNC
| O_RDWR
, 0666);
844 FAIL_EXIT1 ("Cannot create testroot lock.\n");
846 while (flock (lock_fd
, LOCK_EX
) != 0)
849 FAIL_EXIT1 ("Cannot lock testroot.\n");
852 xmkdirp (new_root_path
, 0755);
854 /* We look for extra setup info in a subdir in the same spot as the
855 test, with the same name but a ".root" extension. This is that
856 directory. We try to look in the source tree if the path we're
857 given refers to the build tree, but we rely on the path to be
858 absolute. This is what the glibc makefiles do. */
859 command_root
= concat (argv
[1], ".root", NULL
);
860 if (strncmp (command_root
, support_objdir_root
,
861 strlen (support_objdir_root
)) == 0
862 && command_root
[strlen (support_objdir_root
)] == '/')
863 command_root
= concat (support_srcdir_root
,
864 argv
[1] + strlen (support_objdir_root
),
866 command_root
= xstrdup (command_root
);
868 /* This cuts off the ".root" we appended above. */
869 command_base
= xstrdup (command_root
);
870 command_base
[strlen (command_base
) - 5] = 0;
872 /* This is the basename of the test we're running. */
873 command_basename
= strrchr (command_base
, '/');
874 if (command_basename
== NULL
)
875 command_basename
= command_base
;
879 /* Shared object base directory. */
880 so_base
= xstrdup (argv
[1]);
881 if (strrchr (so_base
, '/') != NULL
)
882 strrchr (so_base
, '/')[1] = 0;
884 if (file_exists (concat (command_root
, "/postclean.req", NULL
)))
887 if (file_exists (concat (command_root
, "/ldconfig.run", NULL
)))
890 rsync (pristine_root_path
, new_root_path
,
891 file_exists (concat (command_root
, "/preclean.req", NULL
)), 0);
893 if (stat (command_root
, &st
) >= 0
894 && S_ISDIR (st
.st_mode
))
895 rsync (command_root
, new_root_path
, 0, 1);
897 new_objdir_path
= xstrdup (concat (new_root_path
,
898 support_objdir_root
, NULL
));
899 new_srcdir_path
= xstrdup (concat (new_root_path
,
900 support_srcdir_root
, NULL
));
902 /* new_cwd_path starts with '/' so no "/" needed between the two. */
903 xmkdirp (concat (new_root_path
, new_cwd_path
, NULL
), 0755);
904 xmkdirp (new_srcdir_path
, 0755);
905 xmkdirp (new_objdir_path
, 0755);
907 original_uid
= getuid ();
908 original_gid
= getgid ();
910 /* Handle the cp/mv/rm "script" here. */
912 char *the_line
= NULL
;
914 char *fname
= concat (command_root
, "/",
915 command_basename
, ".script", NULL
);
917 FILE *f
= fopen (fname
, "r");
920 fprintf (stderr
, "running %s\n", fname
);
924 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
925 fname
= concat (command_base
, ".script", NULL
);
926 f
= fopen (fname
, "r");
928 fprintf (stderr
, "running %s\n", fname
);
931 /* Note that we do NOT look for a Makefile-generated foo.script in
932 the build directory. If that is ever needed, this is the place
935 /* This is where we "interpret" the mini-script which is <test>.script. */
938 while (getline (&the_line
, &line_len
, f
) > 0)
940 int nt
= tokenize (the_line
, the_words
, 3);
943 /* Expand variables. */
944 for (i
= 1; i
< nt
; ++i
)
946 if (memcmp (the_words
[i
], "$B/", 3) == 0)
947 the_words
[i
] = concat (support_objdir_root
,
948 the_words
[i
] + 2, NULL
);
949 else if (memcmp (the_words
[i
], "$S/", 3) == 0)
950 the_words
[i
] = concat (support_srcdir_root
,
951 the_words
[i
] + 2, NULL
);
952 else if (memcmp (the_words
[i
], "$I/", 3) == 0)
953 the_words
[i
] = concat (new_root_path
,
954 support_install_prefix
,
955 the_words
[i
] + 2, NULL
);
956 else if (memcmp (the_words
[i
], "$L/", 3) == 0)
957 the_words
[i
] = concat (new_root_path
,
958 support_libdir_prefix
,
959 the_words
[i
] + 2, NULL
);
960 else if (memcmp (the_words
[i
], "$complocaledir/", 15) == 0)
961 the_words
[i
] = concat (new_root_path
,
962 support_complocaledir_prefix
,
963 the_words
[i
] + 14, NULL
);
964 /* "exec" and "cwd" use inside-root paths. */
965 else if (strcmp (the_words
[0], "exec") != 0
966 && strcmp (the_words
[0], "cwd") != 0
967 && the_words
[i
][0] == '/')
968 the_words
[i
] = concat (new_root_path
,
972 if (nt
== 3 && the_words
[2][strlen (the_words
[2]) - 1] == '/')
974 char *r
= strrchr (the_words
[1], '/');
976 the_words
[2] = concat (the_words
[2], r
+ 1, NULL
);
978 the_words
[2] = concat (the_words
[2], the_words
[1], NULL
);
981 /* Run the following commands in the_words[0] with NT number of
982 arguments (including the command). */
984 if (nt
== 2 && strcmp (the_words
[0], "so") == 0)
986 the_words
[2] = concat (new_root_path
, support_libdir_prefix
,
987 "/", the_words
[1], NULL
);
988 the_words
[1] = concat (so_base
, the_words
[1], NULL
);
989 copy_one_file (the_words
[1], the_words
[2]);
991 else if (nt
== 3 && strcmp (the_words
[0], "cp") == 0)
993 copy_one_file (the_words
[1], the_words
[2]);
995 else if (nt
== 3 && strcmp (the_words
[0], "mv") == 0)
997 if (rename (the_words
[1], the_words
[2]) < 0)
998 FAIL_EXIT1 ("rename %s -> %s: %s", the_words
[1],
999 the_words
[2], strerror (errno
));
1001 else if (nt
== 3 && strcmp (the_words
[0], "chmod") == 0)
1005 m
= strtol (the_words
[1], NULL
, 0);
1006 TEST_COMPARE (errno
, 0);
1007 if (chmod (the_words
[2], m
) < 0)
1008 FAIL_EXIT1 ("chmod %s: %s\n",
1009 the_words
[2], strerror (errno
));
1012 else if (nt
== 2 && strcmp (the_words
[0], "rm") == 0)
1014 maybe_xunlink (the_words
[1]);
1016 else if (nt
>= 2 && strcmp (the_words
[0], "exec") == 0)
1018 /* The first argument is the desired location and name
1019 of the test binary as we wish to exec it; we will
1020 copy the binary there. The second (optional)
1021 argument is the value to pass as argv[0], it
1022 defaults to the same as the first argument. */
1023 char *new_exec_path
= the_words
[1];
1025 /* If the new exec path ends with a slash, that's the
1026 * directory, and use the old test base name. */
1027 if (new_exec_path
[strlen(new_exec_path
) - 1] == '/')
1028 new_exec_path
= concat (new_exec_path
,
1029 basename (new_child_proc
[0]),
1033 /* new_child_proc is in the build tree, so has the
1034 same path inside the chroot as outside. The new
1035 exec path is, by definition, relative to the
1037 copy_one_file (new_child_proc
[0], concat (new_root_path
,
1041 new_child_exec
= xstrdup (new_exec_path
);
1043 new_child_proc
[0] = xstrdup (the_words
[2]);
1045 new_child_proc
[0] = new_child_exec
;
1047 else if (nt
== 2 && strcmp (the_words
[0], "cwd") == 0)
1049 change_cwd
= xstrdup (the_words
[1]);
1051 else if (nt
== 1 && strcmp (the_words
[0], "su") == 0)
1055 else if (nt
>= 1 && strcmp (the_words
[0], "pidns") == 0)
1060 pidns_comment
= concat_words (the_words
+ 1, nt
- 1);
1063 else if (nt
== 3 && strcmp (the_words
[0], "mkdirp") == 0)
1067 m
= strtol (the_words
[1], NULL
, 0);
1068 TEST_COMPARE (errno
, 0);
1069 xmkdirp (the_words
[2], m
);
1071 else if (nt
> 0 && the_words
[0][0] != '#')
1073 fprintf (stderr
, "\033[31minvalid [%s]\033[0m\n", the_words
[0]);
1083 pid_t pc_pid
= fork ();
1087 FAIL_EXIT1 ("Can't fork for post-clean");
1089 else if (pc_pid
> 0)
1093 waitpid (pc_pid
, &status
, 0);
1095 /* Child has exited, we can post-clean the test root. */
1096 printf("running post-clean rsync\n");
1097 rsync (pristine_root_path
, new_root_path
, 1, 0);
1099 if (WIFEXITED (status
))
1100 exit (WEXITSTATUS (status
));
1102 if (WIFSIGNALED (status
))
1104 printf ("%%SIGNALLED%%\n");
1108 printf ("%%EXITERROR%%\n");
1112 /* Child continues. */
1115 /* This is the last point in the program where we're still in the
1116 "normal" namespace. */
1119 /* The unshare here gives us our own spaces and capabilities. */
1120 if (unshare (CLONE_NEWUSER
| CLONE_NEWNS
1121 | (require_pidns
? CLONE_NEWPID
: 0)) < 0)
1123 /* Older kernels may not support all the options, or security
1124 policy may block this call. */
1125 if (errno
== EINVAL
|| errno
== EPERM
|| errno
== ENOSPC
)
1127 int saved_errno
= errno
;
1128 if (errno
== EPERM
|| errno
== ENOSPC
)
1129 check_for_unshare_hints (require_pidns
);
1130 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno
));
1132 /* We're about to exit anyway, it's "safe" to call unshare again
1133 just to see if the CLONE_NEWPID caused the error. */
1134 else if (require_pidns
&& unshare (CLONE_NEWUSER
| CLONE_NEWNS
) >= 0)
1135 FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno
),
1136 pidns_comment
? pidns_comment
: "required by test");
1138 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno
));
1141 /* Some targets may not support unshare at all. */
1142 FAIL_UNSUPPORTED ("unshare support missing");
1145 /* Some systems, by default, all mounts leak out of the namespace. */
1146 if (mount ("none", "/", NULL
, MS_REC
| MS_PRIVATE
, NULL
) != 0)
1147 FAIL_EXIT1 ("could not create a private mount namespace\n");
1149 trymount (support_srcdir_root
, new_srcdir_path
);
1150 trymount (support_objdir_root
, new_objdir_path
);
1152 /* It may not be possible to mount /proc directly. */
1153 if (! require_pidns
)
1155 char *new_proc
= concat (new_root_path
, "/proc", NULL
);
1156 xmkdirp (new_proc
, 0755);
1157 trymount ("/proc", new_proc
);
1161 xmkdirp (concat (new_root_path
, "/dev", NULL
), 0755);
1162 devmount (new_root_path
, "null");
1163 devmount (new_root_path
, "zero");
1164 devmount (new_root_path
, "urandom");
1166 /* We're done with the "old" root, switch to the new one. */
1167 if (chroot (new_root_path
) < 0)
1168 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path
);
1170 if (chdir (new_cwd_path
) < 0)
1171 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path
);
1173 /* This is to pass the "outside" PID to the child, which will be PID
1175 if (pipe2 (pipes
, O_CLOEXEC
) < 0)
1176 FAIL_EXIT1 ("Can't create pid pipe");
1178 /* To complete the containerization, we need to fork () at least
1179 once. We can't exec, nor can we somehow link the new child to
1180 our parent. So we run the child and propogate it's exit status
1184 FAIL_EXIT1 ("Unable to fork");
1190 /* Send the child's "outside" pid to it. */
1191 write (pipes
[1], &child
, sizeof(child
));
1195 waitpid (child
, &status
, 0);
1197 if (WIFEXITED (status
))
1198 exit (WEXITSTATUS (status
));
1200 if (WIFSIGNALED (status
))
1202 printf ("%%SIGNALLED%%\n");
1206 printf ("%%EXITERROR%%\n");
1210 /* The rest is the child process, which is now PID 1 and "in" the
1215 struct support_capture_subprocess result
=
1216 support_capture_subprocess (run_ldconfig
, NULL
);
1217 support_capture_subprocess_check (&result
, "execv", 0, sc_allow_none
);
1220 /* Get our "outside" pid from our parent. We use this to help with
1221 debugging from outside the container. */
1222 read (pipes
[0], &child
, sizeof(child
));
1225 sprintf (pid_buf
, "%lu", (long unsigned)child
);
1226 setenv ("PID_OUTSIDE_CONTAINER", pid_buf
, 0);
1228 maybe_xmkdir ("/tmp", 0755);
1232 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1233 maybe_xmkdir ("/proc", 0777);
1234 if (mount ("proc", "/proc", "proc", 0, NULL
) != 0)
1236 /* This happens if we're trying to create a nested container,
1237 like if the build is running under podman, and we lack
1240 Ideally we would WARN here, but that would just add noise to
1241 *every* test-container test, and the ones that care should
1242 have their own relevent diagnostics.
1244 FAIL_EXIT1 ("Unable to mount /proc: "); */
1252 /* We map our original UID to the same UID in the container so we
1253 can own our own files normally. */
1254 UMAP
= open ("/proc/self/uid_map", O_WRONLY
);
1256 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1258 sprintf (tmp
, "%lld %lld 1\n",
1259 (long long) (be_su
? 0 : original_uid
), (long long) original_uid
);
1260 write (UMAP
, tmp
, strlen (tmp
));
1263 /* We must disable setgroups () before we can map our groups, else we
1265 GMAP
= open ("/proc/self/setgroups", O_WRONLY
);
1268 /* We support kernels old enough to not have this. */
1269 write (GMAP
, "deny\n", 5);
1273 /* We map our original GID to the same GID in the container so we
1274 can own our own files normally. */
1275 GMAP
= open ("/proc/self/gid_map", O_WRONLY
);
1277 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1279 sprintf (tmp
, "%lld %lld 1\n",
1280 (long long) (be_su
? 0 : original_gid
), (long long) original_gid
);
1281 write (GMAP
, tmp
, strlen (tmp
));
1287 if (chdir (change_cwd
) < 0)
1288 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd
);
1291 /* Now run the child. */
1292 execvp (new_child_exec
, new_child_proc
);
1294 /* Or don't run the child? */
1295 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec
, strerror (errno
));
1297 /* Because gcc won't know error () never returns... */
1298 exit (EXIT_UNSUPPORTED
);