about summary refs log tree commit diff
path: root/posix
diff options
context:
space:
mode:
Diffstat (limited to 'posix')
-rw-r--r--posix/Makefile5
-rw-r--r--posix/Versions3
-rw-r--r--posix/execveat.c40
-rw-r--r--posix/tst-execveat.c142
-rw-r--r--posix/unistd.h5
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