unistd: Improve fortify with clang
[glibc.git] / support / test-container.c
blobebcc722da5824d9f5c8811a485535d5a41a288ab
1 /* Run a test case in an isolated namespace.
2 Copyright (C) 2018-2024 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>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sched.h>
24 #include <sys/syscall.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <sys/fcntl.h>
31 #include <sys/file.h>
32 #include <sys/wait.h>
33 #include <stdarg.h>
34 #include <sys/sysmacros.h>
35 #include <ctype.h>
36 #include <utime.h>
37 #include <errno.h>
38 #include <error.h>
39 #include <libc-pointer-arith.h>
40 #include <ftw.h>
42 #ifdef __linux__
43 #include <sys/mount.h>
44 #endif
46 #include <support/support.h>
47 #include <support/xunistd.h>
48 #include <support/capture_subprocess.h>
49 #include "check.h"
50 #include "test-driver.h"
52 #ifndef __linux__
53 #define mount(s,t,fs,f,d) no_mount()
54 int no_mount (void)
56 FAIL_UNSUPPORTED("mount not supported; port needed");
58 #endif
60 int verbose = 0;
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
66 install into it.
68 2. "Per-test" actions, like copying in support files and
69 configuring the container.
72 "Once" actions:
74 * mkdir $buildroot/testroot.pristine/
75 * install into it
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/
82 "Per-test" actions:
83 * maybe rsync to $buildroot/testroot.root/
84 * copy support files and test binary
85 * chroot/unshare
86 * set up any mounts (like /proc)
87 * run ldconfig
89 Magic files:
91 For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root
92 and, if found...
94 * mytest.root/ is rsync'd into container
95 * mytest.root/preclean.req causes fresh rsync (with delete) before
96 test if present
97 * mytest.root/mytest.script has a list of "commands" to run:
98 syntax:
99 # comment
100 pidns <comment>
102 mv FILE FILE
103 cp FILE FILE
104 rm FILE
105 cwd PATH
106 exec FILE
107 mkdirp MODE DIR
109 variables:
110 $B/ build dir, equivalent to $(common-objpfx)
111 $S/ source dir, equivalent to $(srcdir)
112 $I/ install dir, equivalent to $(prefix)
113 $L/ library dir (in container), equivalent to $(libdir)
114 $complocaledir/ compiled locale dir, equivalent to $(complocaledir)
115 / container's root
117 If FILE begins with any of these variables then they will be
118 substituted for the described value.
120 The goal is to expose as many of the runtime's configured paths
121 via variables so they can be used to setup the container environment
122 before execution reaches the test.
124 details:
125 - '#': A comment.
126 - 'pidns': Require a separate PID namespace, prints comment if it can't
127 (default is a shared pid namespace)
128 - 'su': Enables running test as root in the container.
129 - 'mv': A minimal move files command.
130 - 'cp': A minimal copy files command.
131 - 'rm': A minimal remove files command.
132 - 'cwd': set test working directory
133 - 'exec': change test binary location (may end in /)
134 - 'mkdirp': A minimal "mkdir -p FILE" command.
136 * mytest.root/postclean.req causes fresh rsync (with delete) after
137 test if present
139 * mytest.root/ldconfig.run causes ldconfig to be issued prior
140 test execution (to setup the initial ld.so.cache).
142 Note that $srcdir/foo/mytest.script may be used instead of a
143 $srcdir/foo/mytest.root/mytest.script in the sysroot template, if
144 there is no other reason for a sysroot.
146 Design goals:
148 * independent of other packages which may not be installed (like
149 rsync or Docker, or even "cp")
151 * Simple, easy to review code (i.e. prefer simple naive code over
152 complex efficient code)
154 * The current implementation is parallel-make-safe, but only in
155 that it uses a lock to prevent parallel access to the testroot. */
158 /* Utility Functions */
160 /* Like xunlink, but it's OK if the file already doesn't exist. */
161 void
162 maybe_xunlink (const char *path)
164 int rv = unlink (path);
165 if (rv < 0 && errno != ENOENT)
166 FAIL_EXIT1 ("unlink (\"%s\"): %m", path);
169 /* Like xmkdir, but it's OK if the directory already exists. */
170 void
171 maybe_xmkdir (const char *path, mode_t mode)
173 struct stat st;
175 if (stat (path, &st) == 0
176 && S_ISDIR (st.st_mode))
177 return;
178 xmkdir (path, mode);
181 /* Temporarily concatenate multiple strings into one. Allows up to 10
182 temporary results; use xstrdup () if you need them to be
183 permanent. */
184 static char *
185 concat (const char *str, ...)
187 /* Assume initialized to NULL/zero. */
188 static char *bufs[10];
189 static size_t buflens[10];
190 static int bufn = 0;
191 int n;
192 size_t len;
193 va_list ap, ap2;
194 char *cp;
195 char *next;
197 va_start (ap, str);
198 va_copy (ap2, ap);
200 n = bufn;
201 bufn = (bufn + 1) % 10;
202 len = strlen (str);
204 while ((next = va_arg (ap, char *)) != NULL)
205 len = len + strlen (next);
207 va_end (ap);
209 if (bufs[n] == NULL)
211 bufs[n] = xmalloc (len + 1); /* NUL */
212 buflens[n] = len + 1;
214 else if (buflens[n] < len + 1)
216 bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */
217 buflens[n] = len + 1;
220 strcpy (bufs[n], str);
221 cp = strchr (bufs[n], '\0');
222 while ((next = va_arg (ap2, char *)) != NULL)
224 strcpy (cp, next);
225 cp = strchr (cp, '\0');
227 *cp = 0;
228 va_end (ap2);
230 return bufs[n];
233 #ifdef CLONE_NEWNS
234 /* Like the above, but put spaces between words. Caller frees. */
235 static char *
236 concat_words (char **words, int num_words)
238 int len = 0;
239 int i;
240 char *rv, *p;
242 for (i = 0; i < num_words; i ++)
244 len += strlen (words[i]);
245 len ++;
248 p = rv = (char *) xmalloc (len);
250 for (i = 0; i < num_words; i ++)
252 if (i > 0)
253 p = stpcpy (p, " ");
254 p = stpcpy (p, words[i]);
257 return rv;
259 #endif
261 /* Try to mount SRC onto DEST. */
262 static void
263 trymount (const char *src, const char *dest)
265 if (mount (src, dest, "", MS_BIND | MS_REC, NULL) < 0)
266 FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest);
269 /* Special case of above for devices like /dev/zero where we have to
270 mount a device over a device, not a directory over a directory. */
271 static void
272 devmount (const char *new_root_path, const char *which)
274 int fd;
275 fd = open (concat (new_root_path, "/dev/", which, NULL),
276 O_CREAT | O_TRUNC | O_RDWR, 0777);
277 xclose (fd);
279 trymount (concat ("/dev/", which, NULL),
280 concat (new_root_path, "/dev/", which, NULL));
283 /* Returns true if the string "looks like" an environment variable
284 being set. */
285 static int
286 is_env_setting (const char *a)
288 int count_name = 0;
290 while (*a)
292 if (isalnum (*a) || *a == '_')
293 ++count_name;
294 else if (*a == '=' && count_name > 0)
295 return 1;
296 else
297 return 0;
298 ++a;
300 return 0;
303 /* Break the_line into words and store in the_words. Max nwords,
304 returns actual count. */
305 static int
306 tokenize (char *the_line, char **the_words, int nwords)
308 int rv = 0;
310 while (nwords > 0)
312 /* Skip leading whitespace, if any. */
313 while (*the_line && isspace (*the_line))
314 ++the_line;
316 /* End of line? */
317 if (*the_line == 0)
318 return rv;
320 /* THE_LINE points to a non-whitespace character, so we have a
321 word. */
322 *the_words = the_line;
323 ++the_words;
324 nwords--;
325 ++rv;
327 /* Skip leading whitespace, if any. */
328 while (*the_line && ! isspace (*the_line))
329 ++the_line;
331 /* We now point at the trailing NUL *or* some whitespace. */
332 if (*the_line == 0)
333 return rv;
335 /* It was whitespace, skip and keep tokenizing. */
336 *the_line++ = 0;
339 /* We get here if we filled the words buffer. */
340 return rv;
344 /* Mini-RSYNC implementation. Optimize later. */
346 /* A few routines for an "rsync buffer" which stores the paths we're
347 working on. We continuously grow and shrink the paths in each
348 buffer so there's lot of re-use. */
350 /* We rely on "initialized to zero" to set these up. */
351 typedef struct
353 char *buf;
354 size_t len;
355 size_t size;
356 } path_buf;
358 static path_buf spath, dpath;
360 static void
361 r_setup (char *path, path_buf * pb)
363 size_t len = strlen (path);
364 if (pb->buf == NULL || pb->size < len + 1)
366 /* Round up. This is an arbitrary number, just to keep from
367 reallocing too often. */
368 size_t sz = ALIGN_UP (len + 1, 512);
369 if (pb->buf == NULL)
370 pb->buf = (char *) xmalloc (sz);
371 else
372 pb->buf = (char *) xrealloc (pb->buf, sz);
373 if (pb->buf == NULL)
374 FAIL_EXIT1 ("Out of memory while rsyncing\n");
376 pb->size = sz;
378 strcpy (pb->buf, path);
379 pb->len = len;
382 static void
383 r_append (const char *path, path_buf * pb)
385 size_t len = strlen (path) + pb->len;
386 if (pb->size < len + 1)
388 /* Round up */
389 size_t sz = ALIGN_UP (len + 1, 512);
390 pb->buf = (char *) xrealloc (pb->buf, sz);
391 if (pb->buf == NULL)
392 FAIL_EXIT1 ("Out of memory while rsyncing\n");
394 pb->size = sz;
396 strcpy (pb->buf + pb->len, path);
397 pb->len = len;
400 static int
401 file_exists (char *path)
403 struct stat st;
404 if (lstat (path, &st) == 0)
405 return 1;
406 return 0;
409 static int
410 unlink_cb (const char *fpath, const struct stat *sb, int typeflag,
411 struct FTW *ftwbuf)
413 return remove (fpath);
416 static void
417 recursive_remove (char *path)
419 int r = nftw (path, unlink_cb, 1000, FTW_DEPTH | FTW_PHYS);
420 if (r == -1)
421 FAIL_EXIT1 ("recursive_remove failed");
424 /* Used for both rsync and the mytest.script "cp" command. */
425 static void
426 copy_one_file (const char *sname, const char *dname)
428 int sfd, dfd;
429 struct stat st;
430 struct utimbuf times;
432 sfd = open (sname, O_RDONLY);
433 if (sfd < 0)
434 FAIL_EXIT1 ("unable to open %s for reading\n", sname);
436 if (fstat (sfd, &st) < 0)
437 FAIL_EXIT1 ("unable to fstat %s\n", sname);
439 dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600);
440 if (dfd < 0)
441 FAIL_EXIT1 ("unable to open %s for writing\n", dname);
443 xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0);
445 xclose (sfd);
446 xclose (dfd);
448 if (chmod (dname, st.st_mode & 0777) < 0)
449 FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno));
451 times.actime = st.st_atime;
452 times.modtime = st.st_mtime;
453 if (utime (dname, &times) < 0)
454 FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno));
457 /* We don't check *everything* about the two files to see if a copy is
458 needed, just the minimum to make sure we get the latest copy. */
459 static int
460 need_sync (char *ap, char *bp, struct stat *a, struct stat *b)
462 if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT))
463 return 1;
465 if (S_ISLNK (a->st_mode))
467 int rv;
468 char *al, *bl;
470 if (a->st_size != b->st_size)
471 return 1;
473 al = xreadlink (ap);
474 bl = xreadlink (bp);
475 rv = strcmp (al, bl);
476 free (al);
477 free (bl);
478 if (rv == 0)
479 return 0; /* links are same */
480 return 1; /* links differ */
483 if (verbose)
485 if (a->st_size != b->st_size)
486 printf ("SIZE\n");
487 if ((a->st_mode & 0777) != (b->st_mode & 0777))
488 printf ("MODE\n");
489 if (a->st_mtime != b->st_mtime)
490 printf ("TIME\n");
493 if (a->st_size == b->st_size
494 && ((a->st_mode & 0777) == (b->st_mode & 0777))
495 && a->st_mtime == b->st_mtime)
496 return 0;
498 return 1;
501 static void
502 rsync_1 (path_buf * src, path_buf * dest, int and_delete, int force_copies)
504 DIR *dir;
505 struct dirent *de;
506 struct stat s, d;
508 r_append ("/", src);
509 r_append ("/", dest);
511 if (verbose)
512 printf ("sync %s to %s%s%s\n", src->buf, dest->buf,
513 and_delete ? " and delete" : "",
514 force_copies ? " (forced)" : "");
516 size_t staillen = src->len;
518 size_t dtaillen = dest->len;
520 dir = opendir (src->buf);
522 while ((de = readdir (dir)) != NULL)
524 if (strcmp (de->d_name, ".") == 0
525 || strcmp (de->d_name, "..") == 0)
526 continue;
528 src->len = staillen;
529 r_append (de->d_name, src);
530 dest->len = dtaillen;
531 r_append (de->d_name, dest);
533 s.st_mode = ~0;
534 d.st_mode = ~0;
536 if (lstat (src->buf, &s) != 0)
537 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf);
539 /* It's OK if this one fails, since we know the file might be
540 missing. */
541 lstat (dest->buf, &d);
543 if (! force_copies && ! need_sync (src->buf, dest->buf, &s, &d))
545 if (S_ISDIR (s.st_mode))
546 rsync_1 (src, dest, and_delete, force_copies);
547 continue;
550 if (d.st_mode != ~0)
551 switch (d.st_mode & S_IFMT)
553 case S_IFDIR:
554 if (!S_ISDIR (s.st_mode))
556 if (verbose)
557 printf ("-D %s\n", dest->buf);
558 recursive_remove (dest->buf);
560 break;
562 default:
563 if (verbose)
564 printf ("-F %s\n", dest->buf);
565 maybe_xunlink (dest->buf);
566 break;
569 switch (s.st_mode & S_IFMT)
571 case S_IFREG:
572 if (verbose)
573 printf ("+F %s\n", dest->buf);
574 copy_one_file (src->buf, dest->buf);
575 break;
577 case S_IFDIR:
578 if (verbose)
579 printf ("+D %s\n", dest->buf);
580 maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700);
581 rsync_1 (src, dest, and_delete, force_copies);
582 break;
584 case S_IFLNK:
586 char *lp;
587 if (verbose)
588 printf ("+L %s\n", dest->buf);
589 lp = xreadlink (src->buf);
590 xsymlink (lp, dest->buf);
591 free (lp);
592 break;
595 default:
596 break;
600 closedir (dir);
601 src->len = staillen;
602 src->buf[staillen] = 0;
603 dest->len = dtaillen;
604 dest->buf[dtaillen] = 0;
606 if (!and_delete)
607 return;
609 /* The rest of this function removes any files/directories in DEST
610 that do not exist in SRC. This is triggered as part of a
611 preclean or postsclean step. */
613 dir = opendir (dest->buf);
615 while ((de = readdir (dir)) != NULL)
617 if (strcmp (de->d_name, ".") == 0
618 || strcmp (de->d_name, "..") == 0)
619 continue;
621 src->len = staillen;
622 r_append (de->d_name, src);
623 dest->len = dtaillen;
624 r_append (de->d_name, dest);
626 s.st_mode = ~0;
627 d.st_mode = ~0;
629 lstat (src->buf, &s);
631 if (lstat (dest->buf, &d) != 0)
632 FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf);
634 if (s.st_mode == ~0)
636 /* dest exists and src doesn't, clean it. */
637 switch (d.st_mode & S_IFMT)
639 case S_IFDIR:
640 if (!S_ISDIR (s.st_mode))
642 if (verbose)
643 printf ("-D %s\n", dest->buf);
644 recursive_remove (dest->buf);
646 break;
648 default:
649 if (verbose)
650 printf ("-F %s\n", dest->buf);
651 maybe_xunlink (dest->buf);
652 break;
657 closedir (dir);
660 static void
661 rsync (char *src, char *dest, int and_delete, int force_copies)
663 r_setup (src, &spath);
664 r_setup (dest, &dpath);
666 rsync_1 (&spath, &dpath, and_delete, force_copies);
671 /* See if we can detect what the user needs to do to get unshare
672 support working for us. */
673 void
674 check_for_unshare_hints (int require_pidns)
676 static struct {
677 const char *path;
678 int bad_value, good_value, for_pidns;
679 } files[] = {
680 /* Default Debian Linux disables user namespaces, but allows a way
681 to enable them. */
682 { "/proc/sys/kernel/unprivileged_userns_clone", 0, 1, 0 },
683 /* ALT Linux has an alternate way of doing the same. */
684 { "/proc/sys/kernel/userns_restrict", 1, 0, 0 },
685 /* AppArmor can also disable unprivileged user namespaces. */
686 { "/proc/sys/kernel/apparmor_restrict_unprivileged_userns", 1, 0, 0 },
687 /* Linux kernel >= 4.9 has a configurable limit on the number of
688 each namespace. Some distros set the limit to zero to disable the
689 corresponding namespace as a "security policy". */
690 { "/proc/sys/user/max_user_namespaces", 0, 1024, 0 },
691 { "/proc/sys/user/max_mnt_namespaces", 0, 1024, 0 },
692 { "/proc/sys/user/max_pid_namespaces", 0, 1024, 1 },
694 FILE *f;
695 int i, val;
697 for (i = 0; i < array_length (files); i++)
699 if (!require_pidns && files[i].for_pidns)
700 continue;
702 f = fopen (files[i].path, "r");
703 if (f == NULL)
704 continue;
706 val = -1; /* Sentinel. */
707 int cnt = fscanf (f, "%d", &val);
708 if (cnt == 1 && val != files[i].bad_value)
709 continue;
711 printf ("To enable test-container, please run this as root:\n");
712 printf (" echo %d > %s\n", files[i].good_value, files[i].path);
713 return;
717 static void
718 run_ldconfig (void *x __attribute__((unused)))
720 char *prog = xasprintf ("%s/ldconfig", support_install_rootsbindir);
721 char *args[] = { prog, NULL };
723 execv (args[0], args);
724 FAIL_EXIT1 ("execv: %m");
728 main (int argc, char **argv)
730 pid_t child;
731 char *pristine_root_path;
732 char *new_root_path;
733 char *new_cwd_path;
734 char *new_objdir_path;
735 char *new_srcdir_path;
736 char **new_child_proc;
737 char *new_child_exec;
738 char *command_root;
739 char *command_base;
740 char *command_basename;
741 char *so_base;
742 int do_postclean = 0;
743 bool do_ldconfig = false;
744 char *change_cwd = NULL;
746 int pipes[2];
747 char pid_buf[20];
749 uid_t original_uid;
750 gid_t original_gid;
751 /* If set, the test runs as root instead of the user running the testsuite. */
752 int be_su = 0;
753 int require_pidns = 0;
754 #ifdef CLONE_NEWNS
755 const char *pidns_comment = NULL;
756 #endif
757 int do_proc_mounts = 0;
758 int UMAP;
759 int GMAP;
760 /* Used for "%lld %lld 1" so need not be large. */
761 char tmp[100];
762 struct stat st;
763 int lock_fd;
765 setbuf (stdout, NULL);
767 /* The command line we're expecting looks like this:
768 env <set some vars> ld.so <library path> test-binary
770 We need to peel off any "env" or "ld.so" portion of the command
771 line, and keep track of which env vars we should preserve and
772 which we drop. */
774 if (argc < 2)
776 fprintf (stderr, "Usage: test-container <program to run> <args...>\n");
777 exit (1);
780 if (strcmp (argv[1], "-v") == 0)
782 verbose = 1;
783 ++argv;
784 --argc;
787 if (strcmp (argv[1], "env") == 0)
789 ++argv;
790 --argc;
791 while (is_env_setting (argv[1]))
793 /* If there are variables we do NOT want to propagate, this
794 is where the test for them goes. */
796 /* Need to keep these. Note that putenv stores a
797 pointer to our argv. */
798 putenv (argv[1]);
800 ++argv;
801 --argc;
805 if (strcmp (argv[1], support_objdir_elf_ldso) == 0)
807 ++argv;
808 --argc;
809 while (argv[1][0] == '-')
811 if (strcmp (argv[1], "--library-path") == 0)
813 ++argv;
814 --argc;
816 ++argv;
817 --argc;
821 pristine_root_path = xstrdup (concat (support_objdir_root,
822 "/testroot.pristine", NULL));
823 new_root_path = xstrdup (concat (support_objdir_root,
824 "/testroot.root", NULL));
825 new_cwd_path = get_current_dir_name ();
826 new_child_proc = argv + 1;
827 new_child_exec = argv[1];
829 lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL),
830 O_CREAT | O_TRUNC | O_RDWR, 0666);
831 if (lock_fd < 0)
832 FAIL_EXIT1 ("Cannot create testroot lock.\n");
834 while (flock (lock_fd, LOCK_EX) != 0)
836 if (errno != EINTR)
837 FAIL_EXIT1 ("Cannot lock testroot.\n");
840 xmkdirp (new_root_path, 0755);
842 /* We look for extra setup info in a subdir in the same spot as the
843 test, with the same name but a ".root" extension. This is that
844 directory. We try to look in the source tree if the path we're
845 given refers to the build tree, but we rely on the path to be
846 absolute. This is what the glibc makefiles do. */
847 command_root = concat (argv[1], ".root", NULL);
848 if (strncmp (command_root, support_objdir_root,
849 strlen (support_objdir_root)) == 0
850 && command_root[strlen (support_objdir_root)] == '/')
851 command_root = concat (support_srcdir_root,
852 argv[1] + strlen (support_objdir_root),
853 ".root", NULL);
854 command_root = xstrdup (command_root);
856 /* This cuts off the ".root" we appended above. */
857 command_base = xstrdup (command_root);
858 command_base[strlen (command_base) - 5] = 0;
860 /* This is the basename of the test we're running. */
861 command_basename = strrchr (command_base, '/');
862 if (command_basename == NULL)
863 command_basename = command_base;
864 else
865 ++command_basename;
867 /* Shared object base directory. */
868 so_base = xstrdup (argv[1]);
869 if (strrchr (so_base, '/') != NULL)
870 strrchr (so_base, '/')[1] = 0;
872 if (file_exists (concat (command_root, "/postclean.req", NULL)))
873 do_postclean = 1;
875 if (file_exists (concat (command_root, "/ldconfig.run", NULL)))
876 do_ldconfig = true;
878 rsync (pristine_root_path, new_root_path,
879 file_exists (concat (command_root, "/preclean.req", NULL)), 0);
881 if (stat (command_root, &st) >= 0
882 && S_ISDIR (st.st_mode))
883 rsync (command_root, new_root_path, 0, 1);
885 new_objdir_path = xstrdup (concat (new_root_path,
886 support_objdir_root, NULL));
887 new_srcdir_path = xstrdup (concat (new_root_path,
888 support_srcdir_root, NULL));
890 /* new_cwd_path starts with '/' so no "/" needed between the two. */
891 xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755);
892 xmkdirp (new_srcdir_path, 0755);
893 xmkdirp (new_objdir_path, 0755);
895 original_uid = getuid ();
896 original_gid = getgid ();
898 /* Handle the cp/mv/rm "script" here. */
900 char *the_line = NULL;
901 size_t line_len = 0;
902 char *fname = concat (command_root, "/",
903 command_basename, ".script", NULL);
904 char *the_words[3];
905 FILE *f = fopen (fname, "r");
907 if (verbose && f)
908 fprintf (stderr, "running %s\n", fname);
910 if (f == NULL)
912 /* Try foo.script instead of foo.root/foo.script, as a shortcut. */
913 fname = concat (command_base, ".script", NULL);
914 f = fopen (fname, "r");
915 if (verbose && f)
916 fprintf (stderr, "running %s\n", fname);
919 /* Note that we do NOT look for a Makefile-generated foo.script in
920 the build directory. If that is ever needed, this is the place
921 to add it. */
923 /* This is where we "interpret" the mini-script which is <test>.script. */
924 if (f != NULL)
926 while (getline (&the_line, &line_len, f) > 0)
928 int nt = tokenize (the_line, the_words, 3);
929 int i;
931 /* Expand variables. */
932 for (i = 1; i < nt; ++i)
934 if (memcmp (the_words[i], "$B/", 3) == 0)
935 the_words[i] = concat (support_objdir_root,
936 the_words[i] + 2, NULL);
937 else if (memcmp (the_words[i], "$S/", 3) == 0)
938 the_words[i] = concat (support_srcdir_root,
939 the_words[i] + 2, NULL);
940 else if (memcmp (the_words[i], "$I/", 3) == 0)
941 the_words[i] = concat (new_root_path,
942 support_install_prefix,
943 the_words[i] + 2, NULL);
944 else if (memcmp (the_words[i], "$L/", 3) == 0)
945 the_words[i] = concat (new_root_path,
946 support_libdir_prefix,
947 the_words[i] + 2, NULL);
948 else if (memcmp (the_words[i], "$complocaledir/", 15) == 0)
949 the_words[i] = concat (new_root_path,
950 support_complocaledir_prefix,
951 the_words[i] + 14, NULL);
952 /* "exec" and "cwd" use inside-root paths. */
953 else if (strcmp (the_words[0], "exec") != 0
954 && strcmp (the_words[0], "cwd") != 0
955 && the_words[i][0] == '/')
956 the_words[i] = concat (new_root_path,
957 the_words[i], NULL);
960 if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/')
962 char *r = strrchr (the_words[1], '/');
963 if (r)
964 the_words[2] = concat (the_words[2], r + 1, NULL);
965 else
966 the_words[2] = concat (the_words[2], the_words[1], NULL);
969 /* Run the following commands in the_words[0] with NT number of
970 arguments (including the command). */
972 if (nt == 2 && strcmp (the_words[0], "so") == 0)
974 the_words[2] = concat (new_root_path, support_libdir_prefix,
975 "/", the_words[1], NULL);
976 the_words[1] = concat (so_base, the_words[1], NULL);
977 copy_one_file (the_words[1], the_words[2]);
979 else if (nt == 3 && strcmp (the_words[0], "cp") == 0)
981 copy_one_file (the_words[1], the_words[2]);
983 else if (nt == 3 && strcmp (the_words[0], "mv") == 0)
985 if (rename (the_words[1], the_words[2]) < 0)
986 FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1],
987 the_words[2], strerror (errno));
989 else if (nt == 3 && strcmp (the_words[0], "chmod") == 0)
991 long int m;
992 errno = 0;
993 m = strtol (the_words[1], NULL, 0);
994 TEST_COMPARE (errno, 0);
995 if (chmod (the_words[2], m) < 0)
996 FAIL_EXIT1 ("chmod %s: %s\n",
997 the_words[2], strerror (errno));
1000 else if (nt == 2 && strcmp (the_words[0], "rm") == 0)
1002 maybe_xunlink (the_words[1]);
1004 else if (nt >= 2 && strcmp (the_words[0], "exec") == 0)
1006 /* The first argument is the desired location and name
1007 of the test binary as we wish to exec it; we will
1008 copy the binary there. The second (optional)
1009 argument is the value to pass as argv[0], it
1010 defaults to the same as the first argument. */
1011 char *new_exec_path = the_words[1];
1013 /* If the new exec path ends with a slash, that's the
1014 * directory, and use the old test base name. */
1015 if (new_exec_path [strlen(new_exec_path) - 1] == '/')
1016 new_exec_path = concat (new_exec_path,
1017 basename (new_child_proc[0]),
1018 NULL);
1021 /* new_child_proc is in the build tree, so has the
1022 same path inside the chroot as outside. The new
1023 exec path is, by definition, relative to the
1024 chroot. */
1025 copy_one_file (new_child_proc[0], concat (new_root_path,
1026 new_exec_path,
1027 NULL));
1029 new_child_exec = xstrdup (new_exec_path);
1030 if (the_words[2])
1031 new_child_proc[0] = xstrdup (the_words[2]);
1032 else
1033 new_child_proc[0] = new_child_exec;
1035 else if (nt == 2 && strcmp (the_words[0], "cwd") == 0)
1037 change_cwd = xstrdup (the_words[1]);
1039 else if (nt == 1 && strcmp (the_words[0], "su") == 0)
1041 be_su = 1;
1043 else if (nt >= 1 && strcmp (the_words[0], "pidns") == 0)
1045 require_pidns = 1;
1046 #ifdef CLONE_NEWNS
1047 if (nt > 1)
1048 pidns_comment = concat_words (the_words + 1, nt - 1);
1049 #endif
1051 else if (nt == 3 && strcmp (the_words[0], "mkdirp") == 0)
1053 long int m;
1054 errno = 0;
1055 m = strtol (the_words[1], NULL, 0);
1056 TEST_COMPARE (errno, 0);
1057 xmkdirp (the_words[2], m);
1059 else if (nt > 0 && the_words[0][0] != '#')
1061 fprintf (stderr, "\033[31minvalid [%s]\033[0m\n", the_words[0]);
1062 exit (1);
1065 fclose (f);
1069 if (do_postclean)
1071 pid_t pc_pid = fork ();
1073 if (pc_pid < 0)
1075 FAIL_EXIT1 ("Can't fork for post-clean");
1077 else if (pc_pid > 0)
1079 /* Parent. */
1080 int status;
1081 waitpid (pc_pid, &status, 0);
1083 /* Child has exited, we can post-clean the test root. */
1084 printf("running post-clean rsync\n");
1085 rsync (pristine_root_path, new_root_path, 1, 0);
1087 if (WIFEXITED (status))
1088 exit (WEXITSTATUS (status));
1090 if (WIFSIGNALED (status))
1092 printf ("%%SIGNALLED%%\n");
1093 exit (77);
1096 printf ("%%EXITERROR%%\n");
1097 exit (78);
1100 /* Child continues. */
1103 /* This is the last point in the program where we're still in the
1104 "normal" namespace. */
1106 #ifdef CLONE_NEWNS
1107 /* The unshare here gives us our own spaces and capabilities. */
1108 if (unshare (CLONE_NEWUSER | CLONE_NEWNS
1109 | (require_pidns ? CLONE_NEWPID : 0)) < 0)
1111 /* Older kernels may not support all the options, or security
1112 policy may block this call. */
1113 if (errno == EINVAL || errno == EPERM
1114 || errno == ENOSPC || errno == EACCES)
1116 int saved_errno = errno;
1117 if (errno == EPERM || errno == ENOSPC || errno == EACCES)
1118 check_for_unshare_hints (require_pidns);
1119 FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (saved_errno));
1121 /* We're about to exit anyway, it's "safe" to call unshare again
1122 just to see if the CLONE_NEWPID caused the error. */
1123 else if (require_pidns && unshare (CLONE_NEWUSER | CLONE_NEWNS) >= 0)
1124 FAIL_EXIT1 ("unable to unshare pid ns: %s : %s", strerror (errno),
1125 pidns_comment ? pidns_comment : "required by test");
1126 else
1127 FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno));
1129 #else
1130 /* Some targets may not support unshare at all. */
1131 FAIL_UNSUPPORTED ("unshare support missing");
1132 #endif
1134 /* Some systems, by default, all mounts leak out of the namespace. */
1135 if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
1136 FAIL_EXIT1 ("could not create a private mount namespace\n");
1138 trymount (support_srcdir_root, new_srcdir_path);
1139 trymount (support_objdir_root, new_objdir_path);
1141 /* It may not be possible to mount /proc directly. */
1142 if (! require_pidns)
1144 char *new_proc = concat (new_root_path, "/proc", NULL);
1145 xmkdirp (new_proc, 0755);
1146 trymount ("/proc", new_proc);
1147 do_proc_mounts = 1;
1150 xmkdirp (concat (new_root_path, "/dev", NULL), 0755);
1151 devmount (new_root_path, "null");
1152 devmount (new_root_path, "zero");
1153 devmount (new_root_path, "urandom");
1155 /* We're done with the "old" root, switch to the new one. */
1156 if (chroot (new_root_path) < 0)
1157 FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path);
1159 if (chdir (new_cwd_path) < 0)
1160 FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path);
1162 /* This is to pass the "outside" PID to the child, which will be PID
1163 1. */
1164 if (pipe2 (pipes, O_CLOEXEC) < 0)
1165 FAIL_EXIT1 ("Can't create pid pipe");
1167 /* To complete the containerization, we need to fork () at least
1168 once. We can't exec, nor can we somehow link the new child to
1169 our parent. So we run the child and propagate it's exit status
1170 up. */
1171 child = fork ();
1172 if (child < 0)
1173 FAIL_EXIT1 ("Unable to fork");
1174 else if (child > 0)
1176 /* Parent. */
1177 int status;
1179 /* Send the child's "outside" pid to it. */
1180 xwrite (pipes[1], &child, sizeof(child));
1181 close (pipes[0]);
1182 close (pipes[1]);
1184 waitpid (child, &status, 0);
1186 if (WIFEXITED (status))
1187 exit (WEXITSTATUS (status));
1189 if (WIFSIGNALED (status))
1191 printf ("%%SIGNALLED%%\n");
1192 exit (77);
1195 printf ("%%EXITERROR%%\n");
1196 exit (78);
1199 /* The rest is the child process, which is now PID 1 and "in" the
1200 new root. */
1202 if (do_ldconfig)
1204 struct support_capture_subprocess result =
1205 support_capture_subprocess (run_ldconfig, NULL);
1206 support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
1209 /* Get our "outside" pid from our parent. We use this to help with
1210 debugging from outside the container. */
1211 xread (pipes[0], &child, sizeof(child));
1213 close (pipes[0]);
1214 close (pipes[1]);
1215 sprintf (pid_buf, "%lu", (long unsigned)child);
1216 setenv ("PID_OUTSIDE_CONTAINER", pid_buf, 0);
1218 maybe_xmkdir ("/tmp", 0755);
1220 if (require_pidns)
1222 /* Now that we're pid 1 (effectively "root") we can mount /proc */
1223 maybe_xmkdir ("/proc", 0777);
1224 if (mount ("proc", "/proc", "proc", 0, NULL) != 0)
1226 /* This happens if we're trying to create a nested container,
1227 like if the build is running under podman, and we lack
1228 privileges.
1230 Ideally we would WARN here, but that would just add noise to
1231 *every* test-container test, and the ones that care should
1232 have their own relevant diagnostics.
1234 FAIL_EXIT1 ("Unable to mount /proc: "); */
1236 else
1237 do_proc_mounts = 1;
1240 if (do_proc_mounts)
1242 /* We map our original UID to the same UID in the container so we
1243 can own our own files normally. */
1244 UMAP = open ("/proc/self/uid_map", O_WRONLY);
1245 if (UMAP < 0)
1246 FAIL_EXIT1 ("can't write to /proc/self/uid_map\n");
1248 sprintf (tmp, "%lld %lld 1\n",
1249 (long long) (be_su ? 0 : original_uid), (long long) original_uid);
1250 xwrite (UMAP, tmp, strlen (tmp));
1251 xclose (UMAP);
1253 /* We must disable setgroups () before we can map our groups, else we
1254 get EPERM. */
1255 GMAP = open ("/proc/self/setgroups", O_WRONLY);
1256 if (GMAP >= 0)
1258 /* We support kernels old enough to not have this. */
1259 xwrite (GMAP, "deny\n", 5);
1260 xclose (GMAP);
1263 /* We map our original GID to the same GID in the container so we
1264 can own our own files normally. */
1265 GMAP = open ("/proc/self/gid_map", O_WRONLY);
1266 if (GMAP < 0)
1267 FAIL_EXIT1 ("can't write to /proc/self/gid_map\n");
1269 sprintf (tmp, "%lld %lld 1\n",
1270 (long long) (be_su ? 0 : original_gid), (long long) original_gid);
1271 xwrite (GMAP, tmp, strlen (tmp));
1272 xclose (GMAP);
1275 if (change_cwd)
1277 if (chdir (change_cwd) < 0)
1278 FAIL_EXIT1 ("Can't cd to %s inside container - ", change_cwd);
1281 /* Now run the child. */
1282 execvp (new_child_exec, new_child_proc);
1284 /* Or don't run the child? */
1285 FAIL_EXIT1 ("Unable to exec %s: %s\n", new_child_exec, strerror (errno));
1287 /* Because gcc won't know error () never returns... */
1288 exit (EXIT_UNSUPPORTED);