mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
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.
This commit is contained in:
parent
a5dcc87e77
commit
43ffc53a35
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
||||
2017-09-19 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
[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 <wdijkstr@arm.com>
|
||||
|
||||
* benchtests/Makefile: Add logf benchmark.
|
||||
|
@ -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
|
||||
|
88
posix/tst-fexecve.c
Normal file
88
posix/tst-fexecve.c
Normal file
@ -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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <support/check.h>
|
||||
|
||||
/* 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 <support/test-driver.c>
|
@ -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 */
|
||||
|
@ -19,8 +19,13 @@
|
||||
#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>
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user