diff options
Diffstat (limited to 'posix')
-rw-r--r-- | posix/Makefile | 5 | ||||
-rw-r--r-- | posix/Versions | 3 | ||||
-rw-r--r-- | posix/execveat.c | 40 | ||||
-rw-r--r-- | posix/tst-execveat.c | 142 | ||||
-rw-r--r-- | posix/unistd.h | 5 |
5 files changed, 193 insertions, 2 deletions
diff --git a/posix/Makefile b/posix/Makefile index 605ddbade8..2e96d7e4a1 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -65,7 +65,8 @@ routines := \ spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \ posix_madvise \ get_child_max sched_cpucount sched_cpualloc sched_cpufree \ - streams-compat + streams-compat \ + execveat aux := init-posix environ tests := test-errno tstgetopt testfnm runtests runptests \ @@ -102,7 +103,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 tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ tst-glob_lstat_compat tst-spawn4-compat diff --git a/posix/Versions b/posix/Versions index 7d06a6d0c0..8a50a2b617 100644 --- a/posix/Versions +++ b/posix/Versions @@ -147,6 +147,9 @@ libc { } GLIBC_2.30 { } + GLIBC_2.32 { + execveat; + } GLIBC_PRIVATE { __libc_fork; __libc_pread; __libc_pwrite; __nanosleep_nocancel; __pause_nocancel; diff --git a/posix/execveat.c b/posix/execveat.c new file mode 100644 index 0000000000..cab61952b3 --- /dev/null +++ b/posix/execveat.c @@ -0,0 +1,40 @@ +/* Copyright (C) 1991-2020 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 (difrd < 0 || path == NULL || argv == NULL || envp == NULL) + { + __set_errno (EINVAL); + return -1; + } + + __set_errno (ENOSYS); + return -1; +} +stub_warning (execveat) + +weak_alias (__execveat, execveat) diff --git a/posix/tst-execveat.c b/posix/tst-execveat.c new file mode 100644 index 0000000000..0e0a33deb5 --- /dev/null +++ b/posix/tst-execveat.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2017-2020 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 <sys/types.h> +#include <dirent.h> +#include <support/check.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 *argv[] = { (char *) "sh", (char *) "-c", (char *) "exit 3", NULL }; + char *envp[] = { (char *) "FOO=BAR", NULL }; + pid_t pid; + int status; + + printf("call number: %d\n", num); + + pid = xfork (); + if (pid == 0) + { + + TEST_COMPARE (execveat (fd, "sh", 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, errno %d", errno); + } + xwaitpid (pid, &status, 0); + + if (WIFEXITED (status)) + if (expected_fail) + TEST_COMPARE (WEXITSTATUS (status), 0); + else + TEST_COMPARE (WEXITSTATUS (status), 3); + else if (!expected_fail) + FAIL_EXIT1 ("execveat failed"); + return 0; +} + +static int +do_test (void) +{ + DIR *dirp; + int fd; + + dirp = opendir ("/bin"); + if (dirp == NULL) + FAIL_EXIT1 ("failed to open /bin"); + fd = dirfd (dirp); + + /* Call execveat for various fd/pathname combinations */ + + /* fd: valid dir, pathname: relative, flags:: 0 */ + call_execveat (fd, "sh", 0, 0, 1); + /* fd: valid dir, pathname: relative, flags: O_PATH */ + call_execveat (fd, "sh", O_PATH, 0, 2); + /* fd: AT_FDCWD, pathname: relative, flags: 0 + 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 */ + chdir("/bin"); + call_execveat (AT_FDCWD, "sh", 0, 0, 3); + xclose (fd); + closedir (dirp); + + dirp = opendir ("/usr"); + fd = dirfd (dirp); + chdir ("/etc"); + /* fd: AT_FDCWD, pathname: absolute in different dir, flags: 0 */ + call_execveat (AT_FDCWD, "/bin/sh", 0, 0, 4); + + /* fd: valid dir, pathname: absolute in differen dir, flags: 0 */ + call_execveat (fd, "/bin/sh", 0, 0, 5); + /* fd: valid dir, pathname: absolute, flags: O_PATH */ + call_execveat (fd, "/bin/sh", O_PATH, 0, 6); + xclose (fd); + closedir (dirp); + + fd = xopen ("/bin/sh", 0, 0); + /* fd: regular file, pathname: relative, flags: 0 */ + call_execveat(fd, "sh", 0, ENOTDIR, 7); + /* fd: regular file, pathname: absolute, flags: 0 */ + call_execveat (fd, "/bin/sh", 0, 0, 8); + xclose (fd); + + fd = xopen ("/bin/sh", O_PATH, 0); + /* fd: O_PATH of regular file, pathname: empty, flags: 0 */ + call_execveat (fd, "", 0, ENOTDIR, 10); + /* fd: O_PATH of regular file, pathname: empty, flags: AT_EMPTY_PATH */ + call_execveat (fd, "", AT_EMPTY_PATH, 0, 11); // fails with ENOTDIR (20) + /* fd: O_PATH of regular file, pathname: empty, + flags: AT_EMPTY_PATH AT_SYMLINK_NOFOLLOW */ + // call_execveat (fd, "", AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, NULL, 0, 12); //fails with ENOTDIR + xclose (fd); + + fd = xopen ("/bin/sh", O_NOFOLLOW | O_PATH, 0); + /* fd: O_PATH of symbolic link, pathname: empty, flags: */ +// call_execveat(fd, "", 0, 1, 13); //fails with errno ENOTDIR + /* fd: O_PATH of symbolic link, pathname: empty, flags: */ +// call_execveat (fd, "", AT_EMPTY_PATH, 0, 14); //fails with errno ENOTDIR + /* fd: O_PATH of symbolic link, pathname: empty, + flags: AT_EMPTY_PATH AT_SYMLINK_NOFOLLOW */ + call_execveat (fd, "", AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, ENOTDIR, 15); + xclose (fd); + + /* Call execveat with closed fd, we expect this to fail with EBADF */ + call_execveat (fd, "sh", 0, EBADF, 16); + /* Call execveat with closed fd, we expect this to pass because the pathname is + absolute */ + call_execveat (fd, "/bin/sh", 0, 0, 17); + + return 0; +} + +#include <support/test-driver.c> diff --git a/posix/unistd.h b/posix/unistd.h index 32b8161619..b1117f2eda 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -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 |