1 /* Test execveat at the various corner cases.
2 Copyright (C) 2021-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/>. */
22 #include <sys/types.h>
24 #include <support/check.h>
25 #include <support/support.h>
26 #include <support/temp_file.h>
27 #include <support/xdlfcn.h>
28 #include <support/xstdio.h>
29 #include <support/xunistd.h>
31 #include <support/test-driver.h>
34 call_execveat (int fd
, const char *pathname
, int flags
, int expected_fail
,
37 char *envp
[] = { (char *) "FOO=3", NULL
};
38 char *argv
[] = { (char *) "sh", (char *) "-c", (char *) "exit $FOO", NULL
};
43 printf ("call line number: %d\n", num
);
48 TEST_COMPARE (execveat (fd
, pathname
, argv
, envp
, flags
), -1);
50 exit (EXIT_UNSUPPORTED
);
51 else if (errno
== expected_fail
)
54 printf ("expected fail: errno %d\n", errno
);
58 FAIL_EXIT1 ("execveat failed: %m (%d)", errno
);
60 xwaitpid (pid
, &status
, 0);
62 if (!WIFEXITED (status
))
63 FAIL_RET ("child hasn't exited normally");
65 if (WIFEXITED (status
))
67 if (WEXITSTATUS (status
) == EXIT_UNSUPPORTED
)
68 FAIL_UNSUPPORTED ("execveat is unimplemented");
69 else if (expected_fail
!= 0)
70 TEST_COMPARE (WEXITSTATUS (status
), 0);
72 TEST_COMPARE (WEXITSTATUS (status
), 3);
84 char *tmp_dir
, *symlink_name
, *tmp_sh
;
88 dirp
= opendir ("/bin");
90 FAIL_EXIT1 ("failed to open /bin");
93 /* Call execveat for various fd/pathname combinations. */
95 /* Check the pathname relative to a valid dirfd. */
96 call_execveat (fd
, "sh", 0, 0, __LINE__
);
98 /* Use the special value AT_FDCWD as dirfd. Quoting open(2):
99 If pathname is relative and dirfd is the special value AT_FDCWD, then
100 pathname is interpreted relative to the current working directory of
101 the calling process. */
102 call_execveat (AT_FDCWD
, "sh", 0, 0, __LINE__
);
105 /* Check the pathname relative to a valid dirfd with O_PATH. */
106 fd
= xopen ("/bin", O_PATH
| O_DIRECTORY
, O_RDONLY
);
107 call_execveat (fd
, "sh", 0, 0, __LINE__
);
110 /* Check absolute pathname, dirfd should be ignored. */
111 call_execveat (AT_FDCWD
, "/bin/sh", 0, 0, __LINE__
);
112 fd
= xopen ("/usr", O_PATH
| O_DIRECTORY
, 0);
113 /* Same check for absolute pathname, but with input file descriptor
114 opened with different flags. The dirfd should be ignored. */
115 call_execveat (fd
, "/bin/sh", 0, 0, __LINE__
);
119 fd
= xopen ("/usr", O_RDONLY
, 0);
120 /* Same check for absolute pathname, but with input file descriptor
121 opened with different flags. The dirfd should be ignored. */
122 call_execveat (fd
, "/bin/sh", 0, 0, __LINE__
);
125 fd
= xopen ("/bin/sh", O_RDONLY
, 0);
126 /* Check relative pathname, where dirfd does not point to a directory. */
127 call_execveat (fd
, "sh", 0, ENOTDIR
, __LINE__
);
128 /* Check absolute pathname, but dirfd is a regular file. The dirfd
129 should be ignored. */
130 call_execveat (fd
, "/bin/sh", 0, 0, __LINE__
);
134 /* Quoting open(2): O_PATH
135 Obtain a file descriptor that can be used for two purposes: to
136 indicate a location in the filesystem tree and to perform
137 operations that act purely at the file descriptor level. */
138 fd
= xopen ("/bin/sh", O_PATH
, 0);
139 /* Check the empty pathname. Dirfd is a regular file with O_PATH. */
140 call_execveat (fd
, "", 0, ENOENT
, __LINE__
);
141 /* Same check for an empty pathname, but with AT_EMPTY_PATH flag.
143 If oldpath is an empty string, create a link to the file referenced
144 by olddirfd (which may have been obtained using the open(2) O_PATH flag. */
145 call_execveat (fd
, "", AT_EMPTY_PATH
, 0, __LINE__
);
146 call_execveat (fd
, "", AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
, 0, __LINE__
);
149 /* Create a temporary directory "tmp_dir" and create a symbolik link tmp_sh
150 pointing to /bin/sh inside the tmp_dir. Open dirfd as a symbolic link. */
151 tmp_dir
= support_create_temp_directory ("tst-execveat_dir");
152 symlink_name
= xasprintf ("%s/symlink", tmp_dir
);
153 xsymlink ("tmp_sh", symlink_name
);
154 add_temp_file (symlink_name
);
155 tmp_sh
= xasprintf ("%s/tmp_sh", tmp_dir
);
156 add_temp_file (tmp_sh
);
157 fd_out
= xopen (symlink_name
, O_CREAT
| O_WRONLY
, 0);
158 xstat ("/bin/sh", &st
);
159 fd
= xopen ("/bin/sh", O_RDONLY
, 0);
160 xcopy_file_range (fd
, 0, fd_out
, 0, st
.st_size
, 0);
161 xfchmod (fd_out
, 0700);
164 fd_out
= xopen (symlink_name
, O_PATH
, 0);
166 /* Check the empty pathname. Dirfd is a symbolic link. */
167 call_execveat (fd_out
, "", 0, ENOENT
, __LINE__
);
168 call_execveat (fd_out
, "", AT_EMPTY_PATH
, 0, __LINE__
);
169 call_execveat (fd_out
, "", AT_EMPTY_PATH
| AT_SYMLINK_NOFOLLOW
, 0,
177 /* Call execveat with closed fd, we expect this to fail with EBADF. */
178 call_execveat (fd
, "sh", 0, EBADF
, __LINE__
);
179 /* Call execveat with closed fd, we expect this to pass because the pathname is
181 call_execveat (fd
, "/bin/sh", 0, 0, __LINE__
);
186 #include <support/test-driver.c>