On 12/04/2021 16:26, Alexandra Hájková via Libc-alpha wrote:
> From: Alexandra Hájková <ahajkova@redhat.com>
>
> Also add the test for the new wrapper.
> ---
> This version:
> * fixes some indentation
> * nothing is missing in NEWS
> * returns the errno after calling openat_nocancel
> * fixes copy paste comment error
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index 303fa297bc..36bc188b55 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -117,6 +117,7 @@ tests += tst-ofdlocks-compat
> endif
>
> tests-internal += tst-sigcontext-get_pc
> +tests-static-internal += tst-execveat-compat
>
> CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
>
This not build the tst-execveat-compat since 'tests-static-internal' is
not a generic rule. The elf/Makefile does define it, but it ended adding
is on test-internal and test-static to actually enable the test.
You need to mimic it:
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 36bc188b55..49df102257 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -117,7 +117,9 @@ tests += tst-ofdlocks-compat endif tests-internal += tst-sigcontext-get_pc -tests-static-internal += tst-execveat-compat + +tests-static += tst-execveat-compat +tests-internal += tst-execveat-compat CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
> diff --git a/sysdeps/unix/sysv/linux/execveat_fallback.c b/sysdeps/unix/sysv/linux/execveat_fallback.c
> new file mode 100644
> index 0000000000..db67dd0321
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/execveat_fallback.c
> @@ -0,0 +1,69 @@
> +/* Execute program relative to a directory file descriptor.
> + Copyright (C) 2021 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <sys/stat.h>
> +
> +#include <sysdep.h>
> +#include <sys/syscall.h>
> +#include <kernel-features.h>
> +#include <fd_to_filename.h>
> +#include <not-cancel.h>
> +
> +int
> +__execveat_fallback (int dirfd, const char *path, char *const argv[],
> + char *const envp[], int flags)
> +{
> + int fd;
> +
> + if (path[0] == '\0' && (flags & AT_EMPTY_PATH) && dirfd >= 0)
> + fd = dirfd;
> + else
> + {
> + int oflags = O_CLOEXEC;
The default O_CLOEXEC leads the same issue described by fexecve man
page [1]: if path[0] refers to an executable script with a shebang
execveat will fail with ENOENT:
$ cat script
#!/bin/sh
exit $*
$ cat test.c
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
extern int __attribute__((weak)) execveat (int __fd, const char *__path,
char *const __argv[],
char *const __envp[], int __flags);
int main (int argc, char *argv[])
{
char *pathname = "script";
pid_t pid = fork ();
assert (pid >= 0);
if (pid == 0)
{
char *args[] = { pathname, "99", NULL };
char *envp[] = { NULL };
execveat (AT_FDCWD, pathname, args, envp, 0);
_exit (EXIT_FAILURE);
}
int status;
int rc = waitpid (pid, &status, 0);
assert (rc == pid);
assert (WIFEXITED(status));
assert (WEXITSTATUS(status) == 99);
return 0;
}
$ gcc test.c -o test
$ ./testrun.sh ./test
/bin/sh: 0: Can't open /proc/self/fd/3
test: test.c:34: main: Assertion `WEXITSTATUS(status) == 99' failed.
Aborted (core dumped)
The fexecve call could be mitigated since it moves the responsability
of adding the O_CLOEXEC to caller. I still think it is not ideal,
but since fexecve is POSIX interface it should be better to always
fail with ENOSYS on older kernels.
There is another corner cases that the fallback do not mimic exactly
the syscall:
execveat (99 /* invalid fd */, "", AT_EMPTY_PATH)
which returns ENOENT instead of EBADF, but I do not considere this
a deal break.
So we have some options here:
1. Leave as is and document properly that using with an executable
script with shebang might fail.
2. Remove the O_CLOEXEC from fallback, which leads to file leakage.
3. Remove the fallback and return ENOSYS on kernel without execveat
support.
I personally prefer to go for 3. instead of providing a broken fallback.
[1] https://man7.org/linux/man-pages/man3/fexecve.3.html
> + if (flags & AT_SYMLINK_NOFOLLOW)
> + oflags |= O_NOFOLLOW;
> + fd = __openat_nocancel (dirfd, path, oflags);
> + }
> + if (fd < 0)
> + return errno;
This returns the wrong value, it should return 'fd' or just '-1'
> +
> + struct fd_to_filename fdfilename;
> + const char *gfilename = __fd_to_filename (fd, &fdfilename);
> +
> + /* We do not need the return value. */
> + __execve (gfilename, argv, envp);
> +
> + int save = errno;
> +
> + /* We come here only if the 'execve' call fails. Determine whether
> + /proc is mounted. If not we return ENOSYS. */
> + struct stat64 st;
> + if (__stat64 (FD_TO_FILENAME_PREFIX, &st) != 0 && errno == ENOENT)
> + save = ENOSYS;
> +
> + if (fd != dirfd)
> + __close_nocancel_nostatus (fd);
> + __set_errno (save);
> +
> + return -1;
> +}
> diff --git a/sysdeps/unix/sysv/linux/tst-execveat-compat.c b/sysdeps/unix/sysv/linux/tst-execveat-compat.c
> new file mode 100644
> index 0000000000..a37e2329a5
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-execveat-compat.c
> @@ -0,0 +1,28 @@
> +/* Test the fallback implementation of execveat.
> + Copyright (C) 2021 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +/* Get the declaration of the official execveat function. */
> +#include <unistd.h>
> +
> +/* Compile a local version of execveat. */
> +#include <sysdeps/unix/sysv/linux/execveat_fallback.c>
> +
> +/* Re-use the test, but run it against execveat_fallback defined
> + above. */
> +#define execveat execveat_fallback
Because you weren't building the tests the failure was not showing itself:
execveat_fallback.c defined __execveat_fallback not execveat_fallback.
You need to fix it with:
diff --git a/sysdeps/unix/sysv/linux/tst-execveat-compat.c b/sysdeps/unix/sysv/linux/tst-execveat-compat.c
index a37e2329a5..9374018627 100644
--- a/sysdeps/unix/sysv/linux/tst-execveat-compat.c
+++ b/sysdeps/unix/sysv/linux/tst-execveat-compat.c
@@ -24,5 +24,5 @@
/* Re-use the test, but run it against execveat_fallback defined
above. */
-#define execveat execveat_fallback
+#define execveat __execveat_fallback
#include <posix/tst-execveat.c>
@@ -18,6 +18,11 @@ Major new features:
a dump of information related to IFUNC resolver operation and
glibc-hwcaps subdirectory selection.
+* The function execveat has been added and it operates similar to execve.
+ The syscall is already used to implement fexecve without requiring /proc to
+ be mounted. Similar to fexecve, if the syscall is not supported a fallback
+ which access /proc is used.
+
Deprecated and removed features, and other changes affecting compatibility:
[Add deprecations, removals and changes affecting compatibility here]
@@ -191,6 +191,10 @@ extern int __libc_pause (void);
extern int __getlogin_r_loginuid (char *name, size_t namesize)
attribute_hidden;
+extern int
+__execveat_fallback (int dirfd, const char *path, char *const argv[],
+ char *const envp[], int flags) attribute_hidden;
+
# if IS_IN (rtld)
# include <dl-unistd.h>
# endif
@@ -66,7 +66,8 @@ routines := \
posix_madvise \
get_child_max sched_cpucount sched_cpualloc sched_cpufree \
streams-compat \
- shm-directory
+ shm-directory \
+ execveat
aux := init-posix environ
tests := test-errno tstgetopt testfnm runtests runptests \
@@ -103,7 +104,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
- tst-wordexp-nocmd
+ tst-wordexp-nocmd tst-execveat
# Test for the glob symbol version that was replaced in glibc 2.27.
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
@@ -147,6 +147,9 @@ libc {
}
GLIBC_2.30 {
}
+ GLIBC_2.34 {
+ execveat;
+ }
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
new file mode 100644
@@ -0,0 +1,41 @@
+/* Execute program relative to a directory file descriptor.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+/* Replace the current process, executing PATH relative to difrd with
+ arguments argv and environment envp.
+ argv and envp are terminated by NULL pointers. */
+int
+__execveat (int dirfd, const char *path, char *const argv[], char *const envp[],
+ int flags)
+{
+ if (path == NULL || argv == NULL || envp == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (execveat)
+
+weak_alias (__execveat, execveat)
new file mode 100644
@@ -0,0 +1,183 @@
+/* Test execveat at the various corner cases.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xdlfcn.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+#include <wait.h>
+#include <support/test-driver.h>
+
+int
+call_execveat (int fd, const char *pathname, int flags, int expected_fail,
+ int num)
+{
+ char *envp[] = { (char *) "FOO=3", NULL };
+ char *argv[] = { (char *) "sh", (char *) "-c", (char *) "exit $FOO", NULL };
+ pid_t pid;
+ int status;
+
+ if (test_verbose > 0)
+ printf ("call line number: %d\n", num);
+
+ pid = xfork ();
+ if (pid == 0)
+ {
+ TEST_COMPARE (execveat (fd, pathname, argv, envp, flags), -1);
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("execveat is unimplemented");
+ else if (errno == expected_fail)
+ {
+ if (test_verbose > 0)
+ printf ("expected fail: errno %d\n", errno);
+ _exit (0);
+ }
+ else
+ FAIL_EXIT1 ("execveat failed: %m (%d)", errno);
+ }
+ xwaitpid (pid, &status, 0);
+
+ if (!WIFEXITED (status))
+ FAIL_RET ("child hasn't exited normally");
+
+ if (WIFEXITED (status))
+ {
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ FAIL_UNSUPPORTED ("execveat is unimplemented");
+ else if (expected_fail != 0)
+ TEST_COMPARE (WEXITSTATUS (status), 0);
+ else
+ TEST_COMPARE (WEXITSTATUS (status), 3);
+ }
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ DIR *dirp;
+ int fd, fd_out;
+ char *tmp_dir, *symlink_name, *tmp_sh;
+ struct stat64 st;
+
+ dirp = opendir ("/bin");
+ if (dirp == NULL)
+ FAIL_EXIT1 ("failed to open /bin");
+ fd = dirfd (dirp);
+
+ /* Call execveat for various fd/pathname combinations. */
+
+ /* Check the pathname relative to a valid dirfd. */
+ call_execveat (fd, "sh", 0, 0, __LINE__);
+ xchdir ("/bin");
+ /* Use the special value AT_FDCWD as dirfd. Quoting open(2):
+ If pathname is relative and dirfd is the special value AT_FDCWD, then
+ pathname is interpreted relative to the current working directory of
+ the calling process. */
+ call_execveat (AT_FDCWD, "sh", 0, 0, __LINE__);
+ xclose (fd);
+#ifdef O_PATH
+ /* Check the pathname relative to a valid dirfd with O_PATH. */
+ fd = xopen ("/bin", O_PATH | O_DIRECTORY, O_RDONLY);
+ call_execveat (fd, "sh", 0, 0, __LINE__);
+ xclose (fd);
+
+ /* Check absolute pathname, dirfd should be ignored. */
+ call_execveat (AT_FDCWD, "/bin/sh", 0, 0, __LINE__);
+ fd = xopen ("/usr", O_PATH | O_DIRECTORY, 0);
+ /* Same check for absolute pathname, but with input file descriptor
+ openend with different flags. The dirfd should be ignored. */
+ call_execveat (fd, "/bin/sh", 0, 0, __LINE__);
+ xclose (fd);
+#endif
+
+ fd = xopen ("/usr", O_RDONLY, 0);
+ /* Same check for absolute pathname, but with input file descriptor
+ openend with different flags. The dirfd should be ignored. */
+ call_execveat (fd, "/bin/sh", 0, 0, __LINE__);
+ xclose (fd);
+
+ fd = xopen ("/bin/sh", O_RDONLY, 0);
+ /* Check relative pathname, where dirfd does not point to a directory. */
+ call_execveat (fd, "sh", 0, ENOTDIR, __LINE__);
+ /* Check absolute pathname, but dirfd is a regular file. The dirfd
+ should be ignored. */
+ call_execveat (fd, "/bin/sh", 0, 0, __LINE__);
+ xclose (fd);
+
+#ifdef O_PATH
+ /* Quoting open(2): O_PATH
+ Obtain a file descriptor that can be used for two purposes: to
+ indicate a location in the filesystem tree and to perform
+ operations that act purely at the file descriptor level. */
+ fd = xopen ("/bin/sh", O_PATH, 0);
+ /* Check the empty pathname. Dirfd is a regular file with O_PATH. */
+ call_execveat (fd, "", 0, ENOENT, __LINE__);
+ /* Same check for an empty pathname, but with AT_EMPTY_PATH flag.
+ Quoting open(2):
+ If oldpath is an empty string, create a link to the file referenced
+ by olddirfd (which may have been obtained using the open(2) O_PATH flag. */
+ call_execveat (fd, "", AT_EMPTY_PATH, 0, __LINE__);
+ call_execveat (fd, "", AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, 0, __LINE__);
+ xclose (fd);
+
+ /* Create a temporary directory "tmp_dir" and create a symbolik link tmp_sh
+ pointing to /bin/sh inside the tmp_dir. Open dirfd as a symbolic link. */
+ tmp_dir = support_create_temp_directory ("tst-execveat_dir");
+ symlink_name = xasprintf ("%s/symlink", tmp_dir);
+ xsymlink ("tmp_sh", symlink_name);
+ add_temp_file (symlink_name);
+ tmp_sh = xasprintf ("%s/tmp_sh", tmp_dir);
+ add_temp_file (tmp_sh);
+ fd_out = xopen (symlink_name, O_CREAT | O_WRONLY, 0);
+ xstat ("/bin/sh", &st);
+ fd = xopen ("/bin/sh", O_RDONLY, 0);
+ xcopy_file_range (fd, 0, fd_out, 0, st.st_size, 0);
+ xfchmod (fd_out, 0700);
+ xclose (fd);
+ xclose (fd_out);
+ fd_out = xopen (symlink_name, O_PATH, 0);
+
+ /* Check the empty pathname. Dirfd is a symbolic link. */
+ call_execveat (fd_out, "", 0, ENOENT, __LINE__);
+ call_execveat (fd_out, "", AT_EMPTY_PATH, 0, __LINE__);
+ call_execveat (fd_out, "", AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, 0,
+ __LINE__);
+ xclose (fd_out);
+ free (symlink_name);
+ free (tmp_sh);
+ free (tmp_dir);
+#endif
+
+ /* Call execveat with closed fd, we expect this to fail with EBADF. */
+ call_execveat (fd, "sh", 0, EBADF, __LINE__);
+ /* Call execveat with closed fd, we expect this to pass because the pathname is
+ absolute. */
+ call_execveat (fd, "/bin/sh", 0, 0, __LINE__);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
@@ -295,6 +295,11 @@ extern int euidaccess (const char *__name, int __type)
/* An alias for `euidaccess', used by some other systems. */
extern int eaccess (const char *__name, int __type)
__THROW __nonnull ((1));
+
+/* Execute program relative to a directory file descriptor. */
+extern int execveat (int __fd, const char *__path, char *const __argv[],
+ char *const __envp[], int __flags)
+ __THROW __nonnull ((2, 3));
#endif
#ifdef __USE_ATFILE
@@ -2207,6 +2207,7 @@ GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 _hurd_libc_proc_init F
+GLIBC_2.34 execveat F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
@@ -117,6 +117,7 @@ tests += tst-ofdlocks-compat
endif
tests-internal += tst-sigcontext-get_pc
+tests-static-internal += tst-execveat-compat
CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
@@ -2174,4 +2174,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2263,6 +2263,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -1933,4 +1933,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -156,6 +156,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
@@ -153,6 +153,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
@@ -2117,4 +2117,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
new file mode 100644
@@ -0,0 +1,55 @@
+/* Execute program relative to a directory file descriptor.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+#include <kernel-features.h>
+#include <fd_to_filename.h>
+#include <not-cancel.h>
+
+#ifndef __ASSUME_EXECVEAT
+#include "execveat_fallback.c"
+#endif
+
+/* Execute the file FD refers to, overlaying the running program image.
+ ARGV and ENVP are passed to the new program, as for `execve'. */
+int
+execveat (int dirfd, const char *path, char *const argv[], char *const envp[],
+ int flags)
+{
+ /* Avoid implicit array coercion in syscall macros. */
+ INLINE_SYSCALL_CALL (execveat, dirfd, path, &argv[0], &envp[0], flags);
+#ifndef __ASSUME_EXECVEAT
+ if (errno != ENOSYS)
+ return -1;
+
+ if ((flags & ~(AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)) != 0)
+ return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+
+ return __execveat_fallback (dirfd, path, argv, envp, flags);
+#endif
+
+ return -1;
+}
new file mode 100644
@@ -0,0 +1,69 @@
+/* Execute program relative to a directory file descriptor.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+#include <kernel-features.h>
+#include <fd_to_filename.h>
+#include <not-cancel.h>
+
+int
+__execveat_fallback (int dirfd, const char *path, char *const argv[],
+ char *const envp[], int flags)
+{
+ int fd;
+
+ if (path[0] == '\0' && (flags & AT_EMPTY_PATH) && dirfd >= 0)
+ fd = dirfd;
+ else
+ {
+ int oflags = O_CLOEXEC;
+ if (flags & AT_SYMLINK_NOFOLLOW)
+ oflags |= O_NOFOLLOW;
+ fd = __openat_nocancel (dirfd, path, oflags);
+ }
+ if (fd < 0)
+ return errno;
+
+ struct fd_to_filename fdfilename;
+ const char *gfilename = __fd_to_filename (fd, &fdfilename);
+
+ /* We do not need the return value. */
+ __execve (gfilename, argv, envp);
+
+ int save = errno;
+
+ /* We come here only if the 'execve' call fails. Determine whether
+ /proc is mounted. If not we return ENOSYS. */
+ struct stat64 st;
+ if (__stat64 (FD_TO_FILENAME_PREFIX, &st) != 0 && errno == ENOENT)
+ save = ENOSYS;
+
+ if (fd != dirfd)
+ __close_nocancel_nostatus (fd);
+ __set_errno (save);
+
+ return -1;
+}
@@ -2076,6 +2076,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2253,6 +2253,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2110,6 +2110,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -157,6 +157,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
@@ -2196,6 +2196,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2168,4 +2168,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2165,4 +2165,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2159,6 +2159,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2157,6 +2157,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2165,6 +2165,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2159,6 +2159,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2207,4 +2207,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2223,6 +2223,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2256,6 +2256,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2078,6 +2078,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2370,4 +2370,5 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -1935,4 +1935,5 @@ GLIBC_2.33 write F
GLIBC_2.33 writev F
GLIBC_2.33 wscanf F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2135,4 +2135,5 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
@@ -2221,6 +2221,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2114,6 +2114,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2083,6 +2083,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2080,6 +2080,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2212,6 +2212,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
@@ -2131,6 +2131,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
new file mode 100644
@@ -0,0 +1,28 @@
+/* Test the fallback implementation of execveat.
+ Copyright (C) 2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Get the declaration of the official execveat function. */
+#include <unistd.h>
+
+/* Compile a local version of execveat. */
+#include <sysdeps/unix/sysv/linux/execveat_fallback.c>
+
+/* Re-use the test, but run it against execveat_fallback defined
+ above. */
+#define execveat execveat_fallback
+#include <posix/tst-execveat.c>
@@ -2092,6 +2092,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
@@ -2189,4 +2189,5 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 __isnanf128 F
GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 execveat F
GLIBC_2.34 pthread_kill F