1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2021 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
25 #include <sys/syscall.h>
27 #include <sys/types.h>
31 #include <sys/fcntl.h>
35 #include <sys/sysmacros.h>
40 #include <libc-pointer-arith.h>
43 #include <sys/mount.h>
46 #include <support/support.h>
47 #include <support/xunistd.h>
48 #include <support/capture_subprocess.h>
50 #include "test-driver.h"
53 #define mount(s,t,fs,f,d) no_mount()
56 FAIL_UNSUPPORTED("mount not supported; port needed");
62 /* Running a test in a container is tricky. There are two main
63 categories of things to do:
65 1. "Once" actions, like setting up the container and doing an
68 2. "Per-test" actions, like copying in support files and
69 configuring the container.
74 * mkdir $buildroot/testroot.pristine/
76 * default glibc install
77 * create /bin for /bin/sh
78 * create $(complocaledir) so localedef tests work with default paths.
79 * install /bin/sh, /bin/echo, and /bin/true.
80 * rsync to $buildroot/testroot.root/
83 * maybe rsync to $buildroot/testroot.root/
84 * copy support files and test binary
86 * set up any mounts (like /proc)
91 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
94 * mytest.root/ is rsync'd into container
95 * mytest.root/preclean.req causes fresh rsync (with delete) before
97 * 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 - 'su': Enables running test as root in the container.
126 - 'mv': A minimal move files command.
127 - 'cp': A minimal copy files command.
128 - 'rm': A minimal remove files command.
129 - 'cwd': set test working directory
130 - 'exec': change test binary location (may end in /)
131 - 'mkdirp': A minimal "mkdir -p FILE" command.
133 * mytest.root/postclean.req causes fresh rsync (with delete) after
136 * mytest.root/ldconfig.run causes ldconfig to be issued prior
137 test execution (to setup the initial ld.so.cache).
139 Note that $srcdir/foo/mytest.script may be used instead of a
140 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
141 there is no other reason for a sysroot.
145 * independent of other packages which may not be installed (like
146 rsync or Docker, or even "cp")
148 * Simple, easy to review code (i.e. prefer simple naive code over
149 complex efficient code)
151 * The current implementation ist parallel-make-safe, but only in
152 that it uses a lock to prevent parallel access to the testroot. */
155 /* Utility Functions */
157 /* Like xunlink, but it's OK if the file already doesn't exist. */
159 maybe_xunlink (const char *path
)
161 int rv
= unlink (path
);
162 if (rv
< 0 && errno
!= ENOENT
)
163 FAIL_EXIT1 ("unlink (\"%s\"): %m", path
);
166 /* Like xmkdir, but it's OK if the directory already exists. */
168 maybe_xmkdir (const char *path
, mode_t mode
)
172 if (stat (path
, &st
) == 0
173 && S_ISDIR (st
.st_mode
))
178 /* Temporarily concatenate multiple strings into one. Allows up to 10
179 temporary results; use xstrdup () if you need them to be
182 concat (const char *str
, ...)
184 /* Assume initialized to NULL/zero. */
185 static char *bufs
[10];
186 static size_t buflens
[10];
198 bufn
= (bufn
+ 1) % 10;
201 while ((next
= va_arg (ap
, char *)) != NULL
)
202 len
= len
+ strlen (next
);
208 bufs
[n
] = xmalloc (len
+ 1); /* NUL */
209 buflens
[n
] = len
+ 1;
211 else if (buflens
[n
] < len
+ 1)
213 bufs
[n
] = xrealloc (bufs
[n
], len
+ 1); /* NUL */
214 buflens
[n
] = len
+ 1;
217 strcpy (bufs
[n
], str
);
218 cp
= strchr (bufs
[n
], '\0');
219 while ((next
= va_arg (ap2
, char *)) != NULL
)
222 cp
= strchr (cp
, '\0');
230 /* Try to mount SRC onto DEST. */
232 trymount (const char *src
, const char *dest
)
234 if (mount (src
, dest
, "", MS_BIND
, NULL
) < 0)
235 FAIL_EXIT1 ("can't mount %s onto %s\n", src
, dest
);
238 /* Special case of above for devices like /dev/zero where we have to
239 mount a device over a device, not a directory over a directory. */
241 devmount (const char *new_root_path
, const char *which
)
244 fd
= open (concat (new_root_path
, "/dev/", which
, NULL
),
245 O_CREAT
| O_TRUNC
| O_RDWR
, 0777);
248 trymount (concat ("/dev/", which
, NULL
),
249 concat (new_root_path
, "/dev/", which
, NULL
));
252 /* Returns true if the string "looks like" an environement variable
255 is_env_setting (const char *a
)
261 if (isalnum (*a
) || *a
== '_')
263 else if (*a
== '=' && count_name
> 0)
272 /* Break the_line into words and store in the_words. Max nwords,
273 returns actual count. */
275 tokenize (char *the_line
, char **the_words
, int nwords
)
281 /* Skip leading whitespace, if any. */
282 while (*the_line
&& isspace (*the_line
))
289 /* THE_LINE points to a non-whitespace character, so we have a
291 *the_words
= the_line
;
296 /* Skip leading whitespace, if any. */
297 while (*the_line
&& ! isspace (*the_line
))
300 /* We now point at the trailing NUL *or* some whitespace. */
304 /* It was whitespace, skip and keep tokenizing. */
308 /* We get here if we filled the words buffer. */
313 /* Mini-RSYNC implementation. Optimize later. */
315 /* A few routines for an "rsync buffer" which stores the paths we're
316 working on. We continuously grow and shrink the paths in each
317 buffer so there's lot of re-use. */
319 /* We rely on "initialized to zero" to set these up. */
327 static path_buf spath
, dpath
;
330 r_setup (char *path
, path_buf
* pb
)
332 size_t len
= strlen (path
);
333 if (pb
->buf
== NULL
|| pb
->size
< len
+ 1)
335 /* Round up. This is an arbitrary number, just to keep from
336 reallocing too often. */
337 size_t sz
= ALIGN_UP (len
+ 1, 512);
339 pb
->buf
= (char *) xmalloc (sz
);
341 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
343 FAIL_EXIT1 ("Out of memory while rsyncing\n");
347 strcpy (pb
->buf
, path
);
352 r_append (const char *path
, path_buf
* pb
)
354 size_t len
= strlen (path
) + pb
->len
;
355 if (pb
->size
< len
+ 1)
358 size_t sz
= ALIGN_UP (len
+ 1, 512);
359 pb
->buf
= (char *) xrealloc (pb
->buf
, sz
);
361 FAIL_EXIT1 ("Out of memory while rsyncing\n");
365 strcpy (pb
->buf
+ pb
->len
, path
);
370 file_exists (char *path
)
373 if (lstat (path
, &st
) == 0)
379 recursive_remove (char *path
)
389 FAIL_EXIT1 ("Unable to fork");
392 execlp ("rm", "rm", "-rf", path
, NULL
);
393 FAIL_EXIT1 ("exec rm: %m");
396 waitpid (child
, &status
, 0);
397 /* "rm" would have already printed a suitable error message. */
398 if (! WIFEXITED (status
)
399 || WEXITSTATUS (status
) != 0)
400 FAIL_EXIT1 ("exec child returned status: %d", status
);
406 /* Used for both rsync and the mytest.script "cp" command. */
408 copy_one_file (const char *sname
, const char *dname
)
412 struct utimbuf times
;
414 sfd
= open (sname
, O_RDONLY
);
416 FAIL_EXIT1 ("unable to open %s for reading\n", sname
);
418 if (fstat (sfd
, &st
) < 0)
419 FAIL_EXIT1 ("unable to fstat %s\n", sname
);
421 dfd
= open (dname
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0600);
423 FAIL_EXIT1 ("unable to open %s for writing\n", dname
);
425 xcopy_file_range (sfd
, 0, dfd
, 0, st
.st_size
, 0);
430 if (chmod (dname
, st
.st_mode
& 0777) < 0)
431 FAIL_EXIT1 ("chmod %s: %s\n", dname
, strerror (errno
));
433 times
.actime
= st
.st_atime
;
434 times
.modtime
= st
.st_mtime
;
435 if (utime (dname
, ×
) < 0)
436 FAIL_EXIT1 ("utime %s: %s\n", dname
, strerror (errno
));
439 /* We don't check *everything* about the two files to see if a copy is
440 needed, just the minimum to make sure we get the latest copy. */
442 need_sync (char *ap
, char *bp
, struct stat
*a
, struct stat
*b
)
444 if ((a
->st_mode
& S_IFMT
) != (b
->st_mode
& S_IFMT
))
447 if (S_ISLNK (a
->st_mode
))
452 if (a
->st_size
!= b
->st_size
)
457 rv
= strcmp (al
, bl
);
461 return 0; /* links are same */
462 return 1; /* links differ */
467 if (a
->st_size
!= b
->st_size
)
469 if ((a
->st_mode
& 0777) != (b
->st_mode
& 0777))
471 if (a
->st_mtime
!= b
->st_mtime
)
475 if (a
->st_size
== b
->st_size
476 && ((a
->st_mode
& 0777) == (b
->st_mode
& 0777))
477 && a
->st_mtime
== b
->st_mtime
)
484 rsync_1 (path_buf
* src
, path_buf
* dest
, int and_delete
)
491 r_append ("/", dest
);
494 printf ("sync %s to %s %s\n", src
->buf
, dest
->buf
,
495 and_delete
? "and delete" : "");
497 size_t staillen
= src
->len
;
499 size_t dtaillen
= dest
->len
;
501 dir
= opendir (src
->buf
);
503 while ((de
= readdir (dir
)) != NULL
)
505 if (strcmp (de
->d_name
, ".") == 0
506 || strcmp (de
->d_name
, "..") == 0)
510 r_append (de
->d_name
, src
);
511 dest
->len
= dtaillen
;
512 r_append (de
->d_name
, dest
);
517 if (lstat (src
->buf
, &s
) != 0)
518 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src
->buf
);
520 /* It's OK if this one fails, since we know the file might be
522 lstat (dest
->buf
, &d
);
524 if (! need_sync (src
->buf
, dest
->buf
, &s
, &d
))
526 if (S_ISDIR (s
.st_mode
))
527 rsync_1 (src
, dest
, and_delete
);
532 switch (d
.st_mode
& S_IFMT
)
535 if (!S_ISDIR (s
.st_mode
))
538 printf ("-D %s\n", dest
->buf
);
539 recursive_remove (dest
->buf
);
545 printf ("-F %s\n", dest
->buf
);
546 maybe_xunlink (dest
->buf
);
550 switch (s
.st_mode
& S_IFMT
)
554 printf ("+F %s\n", dest
->buf
);
555 copy_one_file (src
->buf
, dest
->buf
);
560 printf ("+D %s\n", dest
->buf
);
561 maybe_xmkdir (dest
->buf
, (s
.st_mode
& 0777) | 0700);
562 rsync_1 (src
, dest
, and_delete
);
569 printf ("+L %s\n", dest
->buf
);
570 lp
= xreadlink (src
->buf
);
571 xsymlink (lp
, dest
->buf
);
583 src
->buf
[staillen
] = 0;
584 dest
->len
= dtaillen
;
585 dest
->buf
[dtaillen
] = 0;
590 /* The rest of this function removes any files/directories in DEST
591 that do not exist in SRC. This is triggered as part of a
592 preclean or postsclean step. */
594 dir
= opendir (dest
->buf
);
596 while ((de
= readdir (dir
)) != NULL
)
598 if (strcmp (de
->d_name
, ".") == 0
599 || strcmp (de
->d_name
, "..") == 0)
603 r_append (de
->d_name
, src
);
604 dest
->len
= dtaillen
;
605 r_append (de
->d_name
, dest
);
610 lstat (src
->buf
, &s
);
612 if (lstat (dest
->buf
, &d
) != 0)
613 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest
->buf
);
617 /* dest exists and src doesn't, clean it. */
618 switch (d
.st_mode
& S_IFMT
)
621 if (!S_ISDIR (s
.st_mode
))
624 printf ("-D %s\n", dest
->buf
);
625 recursive_remove (dest
->buf
);
631 printf ("-F %s\n", dest
->buf
);
632 maybe_xunlink (dest
->buf
);
642 rsync (char *src
, char *dest
, int and_delete
)
644 r_setup (src
, &spath
);
645 r_setup (dest
, &dpath
);
647 rsync_1 (&spath
, &dpath
, and_delete
);
652 /* See if we can detect what the user needs to do to get unshare
653 support working for us. */
655 check_for_unshare_hints (void)
660 /* Default Debian Linux disables user namespaces, but allows a way
662 f
= fopen ("/proc/sys/kernel/unprivileged_userns_clone", "r");
665 i
= 99; /* Sentinel. */
666 fscanf (f
, "%d", &i
);
669 printf ("To enable test-container, please run this as root:\n");
670 printf (" echo 1 > /proc/sys/kernel/unprivileged_userns_clone\n");
676 /* ALT Linux has an alternate way of doing the same. */
677 f
= fopen ("/proc/sys/kernel/userns_restrict", "r");
680 i
= 99; /* Sentinel. */
681 fscanf (f
, "%d", &i
);
684 printf ("To enable test-container, please run this as root:\n");
685 printf (" echo 0 > /proc/sys/kernel/userns_restrict\n");
693 run_ldconfig (void *x
__attribute__((unused
)))
695 char *prog
= xasprintf ("%s/ldconfig", support_install_rootsbindir
);
696 char *args
[] = { prog
, NULL
};
698 execv (args
[0], args
);
699 FAIL_EXIT1 ("execv: %m");
703 main (int argc
, char **argv
)
706 char *pristine_root_path
;
709 char *new_objdir_path
;
710 char *new_srcdir_path
;
711 char **new_child_proc
;
712 char *new_child_exec
;
715 char *command_basename
;
717 int do_postclean
= 0;
718 bool do_ldconfig
= false;
719 char *change_cwd
= NULL
;
726 /* If set, the test runs as root instead of the user running the testsuite. */
730 /* Used for "%lld %lld 1" so need not be large. */
735 setbuf (stdout
, NULL
);
737 /* The command line we're expecting looks like this:
738 env <set some vars> ld.so <library path> test-binary
740 We need to peel off any "env" or "ld.so" portion of the command
741 line, and keep track of which env vars we should preserve and
746 fprintf (stderr
, "Usage: test-container <program to run> <args...>\n");
750 if (strcmp (argv
[1], "-v") == 0)
757 if (strcmp (argv
[1], "env") == 0)
761 while (is_env_setting (argv
[1]))
763 /* If there are variables we do NOT want to propogate, this
764 is where the test for them goes. */
766 /* Need to keep these. Note that putenv stores a
767 pointer to our argv. */
775 if (strcmp (argv
[1], support_objdir_elf_ldso
) == 0)
779 while (argv
[1][0] == '-')
781 if (strcmp (argv
[1], "--library-path") == 0)
791 pristine_root_path
= xstrdup (concat (support_objdir_root
,
792 "/testroot.pristine", NULL
));
793 new_root_path
= xstrdup (concat (support_objdir_root
,
794 "/testroot.root", NULL
));
795 new_cwd_path
= get_current_dir_name ();
796 new_child_proc
= argv
+ 1;
797 new_child_exec
= argv
[1];
799 lock_fd
= open (concat (pristine_root_path
, "/lock.fd", NULL
),
800 O_CREAT
| O_TRUNC
| O_RDWR
, 0666);
802 FAIL_EXIT1 ("Cannot create testroot lock.\n");
804 while (flock (lock_fd
, LOCK_EX
) != 0)
807 FAIL_EXIT1 ("Cannot lock testroot.\n");
810 xmkdirp (new_root_path
, 0755);
812 /* We look for extra setup info in a subdir in the same spot as the
813 test, with the same name but a ".root" extension. This is that
814 directory. We try to look in the source tree if the path we're
815 given refers to the build tree, but we rely on the path to be
816 absolute. This is what the glibc makefiles do. */
817 command_root
= concat (argv
[1], ".root", NULL
);
818 if (strncmp (command_root
, support_objdir_root
,
819 strlen (support_objdir_root
)) == 0
820 && command_root
[strlen (support_objdir_root
)] == '/')
821 command_root
= concat (support_srcdir_root
,
822 argv
[1] + strlen (support_objdir_root
),
824 command_root
= xstrdup (command_root
);
826 /* This cuts off the ".root" we appended above. */
827 command_base
= xstrdup (command_root
);
828 command_base
[strlen (command_base
) - 5] = 0;
830 /* This is the basename of the test we're running. */
831 command_basename
= strrchr (command_base
, '/');
832 if (command_basename
== NULL
)
833 command_basename
= command_base
;
837 /* Shared object base directory. */
838 so_base
= xstrdup (argv
[1]);
839 if (strrchr (so_base
, '/') != NULL
)
840 strrchr (so_base
, '/')[1] = 0;
842 if (file_exists (concat (command_root
, "/postclean.req", NULL
)))
845 if (file_exists (concat (command_root
, "/ldconfig.run", NULL
)))
848 rsync (pristine_root_path
, new_root_path
,
849 file_exists (concat (command_root
, "/preclean.req", NULL
)));
851 if (stat (command_root
, &st
) >= 0
852 && S_ISDIR (st
.st_mode
))
853 rsync (command_root
, new_root_path
, 0);
855 new_objdir_path
= xstrdup (concat (new_root_path
,
856 support_objdir_root
, NULL
));
857 new_srcdir_path
= xstrdup (concat (new_root_path
,
858 support_srcdir_root
, NULL
));
860 /* new_cwd_path starts with '/' so no "/" needed between the two. */
861 xmkdirp (concat (new_root_path
, new_cwd_path
, NULL
), 0755);
862 xmkdirp (new_srcdir_path
, 0755);
863 xmkdirp (new_objdir_path
, 0755);
865 original_uid
= getuid ();
866 original_gid
= getgid ();
868 /* Handle the cp/mv/rm "script" here. */
870 char *the_line
= NULL
;
872 char *fname
= concat (command_root
, "/",
873 command_basename
, ".script", NULL
);
875 FILE *f
= fopen (fname
, "r");
878 fprintf (stderr
, "running %s\n", fname
);
882 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
883 fname
= concat (command_base
, ".script", NULL
);
884 f
= fopen (fname
, "r");
886 fprintf (stderr
, "running %s\n", fname
);
889 /* Note that we do NOT look for a Makefile-generated foo.script in
890 the build directory. If that is ever needed, this is the place
893 /* This is where we "interpret" the mini-script which is <test>.script. */
896 while (getline (&the_line
, &line_len
, f
) > 0)
898 int nt
= tokenize (the_line
, the_words
, 3);
901 /* Expand variables. */
902 for (i
= 1; i
< nt
; ++i
)
904 if (memcmp (the_words
[i
], "$B/", 3) == 0)
905 the_words
[i
] = concat (support_objdir_root
,
906 the_words
[i
] + 2, NULL
);
907 else if (memcmp (the_words
[i
], "$S/", 3) == 0)
908 the_words
[i
] = concat (support_srcdir_root
,
909 the_words
[i
] + 2, NULL
);
910 else if (memcmp (the_words
[i
], "$I/", 3) == 0)
911 the_words
[i
] = concat (new_root_path
,
912 support_install_prefix
,
913 the_words
[i
] + 2, NULL
);
914 else if (memcmp (the_words
[i
], "$L/", 3) == 0)
915 the_words
[i
] = concat (new_root_path
,
916 support_libdir_prefix
,
917 the_words
[i
] + 2, NULL
);
918 else if (memcmp (the_words
[i
], "$complocaledir/", 15) == 0)
919 the_words
[i
] = concat (new_root_path
,
920 support_complocaledir_prefix
,
921 the_words
[i
] + 14, NULL
);
922 /* "exec" and "cwd" use inside-root paths. */
923 else if (strcmp (the_words
[0], "exec") != 0
924 && strcmp (the_words
[0], "cwd") != 0
925 && the_words
[i
][0] == '/')
926 the_words
[i
] = concat (new_root_path
,
930 if (nt
== 3 && the_words
[2][strlen (the_words
[2]) - 1] == '/')
932 char *r
= strrchr (the_words
[1], '/');
934 the_words
[2] = concat (the_words
[2], r
+ 1, NULL
);
936 the_words
[2] = concat (the_words
[2], the_words
[1], NULL
);
939 /* Run the following commands in the_words[0] with NT number of
940 arguments (including the command). */
942 if (nt
== 2 && strcmp (the_words
[0], "so") == 0)
944 the_words
[2] = concat (new_root_path
, support_libdir_prefix
,
945 "/", the_words
[1], NULL
);
946 the_words
[1] = concat (so_base
, the_words
[1], NULL
);
947 copy_one_file (the_words
[1], the_words
[2]);
949 else if (nt
== 3 && strcmp (the_words
[0], "cp") == 0)
951 copy_one_file (the_words
[1], the_words
[2]);
953 else if (nt
== 3 && strcmp (the_words
[0], "mv") == 0)
955 if (rename (the_words
[1], the_words
[2]) < 0)
956 FAIL_EXIT1 ("rename %s -> %s: %s", the_words
[1],
957 the_words
[2], strerror (errno
));
959 else if (nt
== 3 && strcmp (the_words
[0], "chmod") == 0)
963 m
= strtol (the_words
[1], NULL
, 0);
964 TEST_COMPARE (errno
, 0);
965 if (chmod (the_words
[2], m
) < 0)
966 FAIL_EXIT1 ("chmod %s: %s\n",
967 the_words
[2], strerror (errno
));
970 else if (nt
== 2 && strcmp (the_words
[0], "rm") == 0)
972 maybe_xunlink (the_words
[1]);
974 else if (nt
>= 2 && strcmp (the_words
[0], "exec") == 0)
976 /* The first argument is the desired location and name
977 of the test binary as we wish to exec it; we will
978 copy the binary there. The second (optional)
979 argument is the value to pass as argv[0], it
980 defaults to the same as the first argument. */
981 char *new_exec_path
= the_words
[1];
983 /* If the new exec path ends with a slash, that's the
984 * directory, and use the old test base name. */
985 if (new_exec_path
[strlen(new_exec_path
) - 1] == '/')
986 new_exec_path
= concat (new_exec_path
,
987 basename (new_child_proc
[0]),
991 /* new_child_proc is in the build tree, so has the
992 same path inside the chroot as outside. The new
993 exec path is, by definition, relative to the
995 copy_one_file (new_child_proc
[0], concat (new_root_path
,
999 new_child_exec
= xstrdup (new_exec_path
);
1001 new_child_proc
[0] = xstrdup (the_words
[2]);
1003 new_child_proc
[0] = new_child_exec
;
1005 else if (nt
== 2 && strcmp (the_words
[0], "cwd") == 0)
1007 change_cwd
= xstrdup (the_words
[1]);
1009 else if (nt
== 1 && strcmp (the_words
[0], "su") == 0)
1013 else if (nt
== 3 && strcmp (the_words
[0], "mkdirp") == 0)
1017 m
= strtol (the_words
[1], NULL
, 0);
1018 TEST_COMPARE (errno
, 0);
1019 xmkdirp (the_words
[2], m
);
1021 else if (nt
> 0 && the_words
[0][0] != '#')
1023 fprintf (stderr
, "\033[31minvalid [%s]\033[0m\n", the_words
[0]);
1033 pid_t pc_pid
= fork ();
1037 FAIL_EXIT1 ("Can't fork for post-clean");
1039 else if (pc_pid
> 0)
1043 waitpid (pc_pid
, &status
, 0);
1045 /* Child has exited, we can post-clean the test root. */
1046 printf("running post-clean rsync\n");
1047 rsync (pristine_root_path
, new_root_path
, 1);
1049 if (WIFEXITED (status
))
1050 exit (WEXITSTATUS (status
));
1052 if (WIFSIGNALED (status
))
1054 printf ("%%SIGNALLED%%\n");
1058 printf ("%%EXITERROR%%\n");
1062 /* Child continues. */
1065 /* This is the last point in the program where we're still in the
1066 "normal" namespace. */
1069 /* The unshare here gives us our own spaces and capabilities. */
1070 if (unshare (CLONE_NEWUSER
| CLONE_NEWPID
| CLONE_NEWNS
) < 0)
1072 /* Older kernels may not support all the options, or security
1073 policy may block this call. */
1074 if (errno
== EINVAL
|| errno
== EPERM
)
1076 int saved_errno
= errno
;
1078 check_for_unshare_hints ();
1079 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno
));
1082 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno
));
1085 /* Some targets may not support unshare at all. */
1086 FAIL_UNSUPPORTED ("unshare support missing");
1089 /* Some systems, by default, all mounts leak out of the namespace. */
1090 if (mount ("none", "/", NULL
, MS_REC
| MS_PRIVATE
, NULL
) != 0)
1091 FAIL_EXIT1 ("could not create a private mount namespace\n");
1093 trymount (support_srcdir_root
, new_srcdir_path
);
1094 trymount (support_objdir_root
, new_objdir_path
);
1096 xmkdirp (concat (new_root_path
, "/dev", NULL
), 0755);
1097 devmount (new_root_path
, "null");
1098 devmount (new_root_path
, "zero");
1099 devmount (new_root_path
, "urandom");
1101 /* We're done with the "old" root, switch to the new one. */
1102 if (chroot (new_root_path
) < 0)
1103 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path
);
1105 if (chdir (new_cwd_path
) < 0)
1106 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path
);
1108 /* This is to pass the "outside" PID to the child, which will be PID
1110 if (pipe2 (pipes
, O_CLOEXEC
) < 0)
1111 FAIL_EXIT1 ("Can't create pid pipe");
1113 /* To complete the containerization, we need to fork () at least
1114 once. We can't exec, nor can we somehow link the new child to
1115 our parent. So we run the child and propogate it's exit status
1119 FAIL_EXIT1 ("Unable to fork");
1125 /* Send the child's "outside" pid to it. */
1126 write (pipes
[1], &child
, sizeof(child
));
1130 waitpid (child
, &status
, 0);
1132 if (WIFEXITED (status
))
1133 exit (WEXITSTATUS (status
));
1135 if (WIFSIGNALED (status
))
1137 printf ("%%SIGNALLED%%\n");
1141 printf ("%%EXITERROR%%\n");
1145 /* The rest is the child process, which is now PID 1 and "in" the
1150 struct support_capture_subprocess result
=
1151 support_capture_subprocess (run_ldconfig
, NULL
);
1152 support_capture_subprocess_check (&result
, "execv", 0, sc_allow_none
);
1155 /* Get our "outside" pid from our parent. We use this to help with
1156 debugging from outside the container. */
1157 read (pipes
[0], &child
, sizeof(child
));
1160 sprintf (pid_buf
, "%lu", (long unsigned)child
);
1161 setenv ("PID_OUTSIDE_CONTAINER", pid_buf
, 0);
1163 maybe_xmkdir ("/tmp", 0755);
1165 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1166 maybe_xmkdir ("/proc", 0777);
1167 if (mount ("proc", "/proc", "proc", 0, NULL
) < 0)
1168 FAIL_EXIT1 ("Unable to mount /proc: ");
1170 /* We map our original UID to the same UID in the container so we
1171 can own our own files normally. */
1172 UMAP
= open ("/proc/self/uid_map", O_WRONLY
);
1174 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1176 sprintf (tmp
, "%lld %lld 1\n",
1177 (long long) (be_su
? 0 : original_uid
), (long long) original_uid
);
1178 write (UMAP
, tmp
, strlen (tmp
));
1181 /* We must disable setgroups () before we can map our groups, else we
1183 GMAP
= open ("/proc/self/setgroups", O_WRONLY
);
1186 /* We support kernels old enough to not have this. */
1187 write (GMAP
, "deny\n", 5);
1191 /* We map our original GID to the same GID in the container so we
1192 can own our own files normally. */
1193 GMAP
= open ("/proc/self/gid_map", O_WRONLY
);
1195 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1197 sprintf (tmp
, "%lld %lld 1\n",
1198 (long long) (be_su
? 0 : original_gid
), (long long) original_gid
);
1199 write (GMAP
, tmp
, strlen (tmp
));
1204 if (chdir (change_cwd
) < 0)
1205 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd
);
1208 /* Now run the child. */
1209 execvp (new_child_exec
, new_child_proc
);
1211 /* Or don't run the child? */
1212 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec
, strerror (errno
));
1214 /* Because gcc won't know error () never returns... */
1215 exit (EXIT_UNSUPPORTED
);