From 43ffc53a352a67672210c9dd4959f6c6b7407e60 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Wed, 6 Sep 2017 17:29:29 +0200 Subject: [PATCH] Use execveat syscall in fexecve (bug 22134) By using execveat we no longer depend on /proc. The execveat syscall was introduced in 3.19, except for a few late comers. --- ChangeLog | 18 +++++ posix/Makefile | 2 +- posix/tst-fexecve.c | 88 ++++++++++++++++++++++ sysdeps/unix/sysv/linux/alpha/kernel-features.h | 5 ++ sysdeps/unix/sysv/linux/fexecve.c | 15 ++++ sysdeps/unix/sysv/linux/hppa/kernel-features.h | 5 ++ sysdeps/unix/sysv/linux/kernel-features.h | 5 ++ .../unix/sysv/linux/microblaze/kernel-features.h | 5 ++ 8 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 posix/tst-fexecve.c diff --git a/ChangeLog b/ChangeLog index 048fd5e..0efae2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2017-09-19 Andreas Schwab + + [BZ #22134] + * sysdeps/unix/sysv/linux/fexecve.c (fexecve) [__NR_execveat]: Try + execveat first. + [!__ASSUME_EXECVEAT]: Fall back to /proc if execveat is + unimplemented. + * sysdeps/unix/sysv/linux/kernel-features.h (__ASSUME_EXECVEAT) + [__LINUX_KERNEL_VERSION >= 0x031300]: Define. + * sysdeps/unix/sysv/linux/alpha/kernel-features.h + (__ASSUME_EXECVEAT) [__LINUX_KERNEL_VERSION < 0x040200]: Undef. + * sysdeps/unix/sysv/linux/hppa/kernel-features.h + (__ASSUME_EXECVEAT) [__LINUX_KERNEL_VERSION < 0x040000]: Undef. + * sysdeps/unix/sysv/linux/microblaze/kernel-features.h + (__ASSUME_EXECVEAT) [__LINUX_KERNEL_VERSION < 0x040000]: Undef. + * posix/Makefile (tests): Add tst-fexecve. + * posix/tst-fexecve.c: New file. + 2017-09-19 Wilco Dijkstra * benchtests/Makefile: Add logf benchmark. diff --git a/posix/Makefile b/posix/Makefile index 7188cba..7f77b07 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -93,7 +93,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ tst-posix_spawn-fd tst-posix_spawn-setsid \ tst-posix_fadvise tst-posix_fadvise64 \ - tst-sysconf-empty-chroot tst-glob_symlinks + tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 xtests := bug-ga2 diff --git a/posix/tst-fexecve.c b/posix/tst-fexecve.c new file mode 100644 index 0000000..2409102 --- /dev/null +++ b/posix/tst-fexecve.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2017 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 + . */ + +#include +#include +#include +#include + +#include + +/* Try executing "/bin/sh -c true", using FD opened on /bin/sh. */ +static int +try_fexecve (int fd) +{ + pid_t pid = fork (); + + if (pid == 0) + { + static const char *const argv[] = { + "/bin/sh", "-c", "true", NULL + }; + fexecve (fd, (char *const *) argv, environ); + _exit (errno); + } + if (pid < 0) + FAIL_RET ("fork failed: %m"); + + pid_t termpid; + int status; + termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (termpid == -1) + FAIL_RET ("waitpid failed: %m"); + if (termpid != pid) + FAIL_RET ("waitpid returned %ld != %ld", + (long int) termpid, (long int) pid); + if (!WIFEXITED (status)) + FAIL_RET ("child hasn't exited normally"); + + /* If fexecve is unimplemented mark this test as UNSUPPORTED. */ + if (WEXITSTATUS (status) == ENOSYS) + FAIL_UNSUPPORTED ("fexecve is unimplemented"); + + if (WEXITSTATUS (status) != 0) + { + errno = WEXITSTATUS (status); + FAIL_RET ("fexecve failed: %m"); + } + return 0; +} + +static int +do_test (void) +{ + int fd; + int ret; + + fd = open ("/bin/sh", O_RDONLY); + if (fd < 0) + FAIL_UNSUPPORTED ("/bin/sh cannot be opened: %m"); + ret = try_fexecve (fd); + close (fd); + +#ifdef O_PATH + fd = open ("/bin/sh", O_RDONLY | O_PATH); + if (fd < 0) + FAIL_UNSUPPORTED ("/bin/sh cannot be opened (O_PATH): %m"); + ret |= try_fexecve (fd); + close (fd); +#endif + + return ret; +} + +#include diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h index 53f7611..5bc2ddb 100644 --- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h +++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h @@ -35,4 +35,9 @@ #define __ASSUME_RECV_SYSCALL 1 #define __ASSUME_SEND_SYSCALL 1 +/* Support for the execveat syscall was added in 4.2. */ +#if __LINUX_KERNEL_VERSION < 0x040200 +# undef __ASSUME_EXECVEAT +#endif + #endif /* _KERNEL_FEATURES_H */ diff --git a/sysdeps/unix/sysv/linux/fexecve.c b/sysdeps/unix/sysv/linux/fexecve.c index 30fa719..3bf5de5 100644 --- a/sysdeps/unix/sysv/linux/fexecve.c +++ b/sysdeps/unix/sysv/linux/fexecve.c @@ -19,8 +19,13 @@ #include #include #include +#include #include +#include +#include +#include + /* Execute the file FD refers to, overlaying the running program image. ARGV and ENVP are passed to the new program, as for `execve'. */ @@ -33,6 +38,15 @@ fexecve (int fd, char *const argv[], char *const envp[]) return -1; } +#ifdef __NR_execveat + INLINE_SYSCALL (execveat, 5, fd, "", argv, envp, AT_EMPTY_PATH); +# ifndef __ASSUME_EXECVEAT + if (errno != ENOSYS) + return -1; +# endif +#endif + +#ifndef __ASSUME_EXECVEAT /* We use the /proc filesystem to get the information. If it is not mounted we fail. */ char buf[sizeof "/proc/self/fd/" + sizeof (int) * 3]; @@ -50,6 +64,7 @@ fexecve (int fd, char *const argv[], char *const envp[]) save = ENOSYS; __set_errno (save); +#endif return -1; } diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h index 0e73a5c..f25a840 100644 --- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h +++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h @@ -27,3 +27,8 @@ #define __ASSUME_RECV_SYSCALL 1 #define __ASSUME_SEND_SYSCALL 1 + +/* Support for the execveat syscall was added in 4.0. */ +#if __LINUX_KERNEL_VERSION < 0x040000 +# undef __ASSUME_EXECVEAT +#endif diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 9495db4..2e1fe65 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -102,3 +102,8 @@ implementation does not assume the __ASSUME_* and instead use a fallback implementation based on p{read,write}v and returning an error for non supported flags. */ + +/* Support for the execveat syscall was added in 3.19. */ +#if __LINUX_KERNEL_VERSION >= 0x031300 +# define __ASSUME_EXECVEAT 1 +#endif diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h index 0257524..6575df2 100644 --- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h @@ -47,3 +47,8 @@ #if __LINUX_KERNEL_VERSION < 0x030300 # undef __ASSUME_SENDMMSG_SYSCALL #endif + +/* Support for the execveat syscall was added in 4.0. */ +#if __LINUX_KERNEL_VERSION < 0x040000 +# undef __ASSUME_EXECVEAT +#endif -- 2.7.4