mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 02:18:37 +00:00
Add support for execveat syscall
Refactor the code to be reusable between execve and execveat syscalls. https://bugs.kde.org/show_bug.cgi?id=345077
This commit is contained in:
parent
bfd43aef3e
commit
6f6ff49ffa
2
.gitignore
vendored
2
.gitignore
vendored
@ -1052,6 +1052,8 @@
|
||||
/memcheck/tests/linux/timerfd-syscall
|
||||
/memcheck/tests/linux/proc-auxv
|
||||
/memcheck/tests/linux/sys-openat
|
||||
/memcheck/tests/linux/sys-execveat
|
||||
/memcheck/tests/linux/check_execveat
|
||||
|
||||
# /memcheck/tests/mips32/
|
||||
/memcheck/tests/mips32/*.stderr.diff
|
||||
|
||||
1
NEWS
1
NEWS
@ -39,6 +39,7 @@ To see details of a given bug, visit
|
||||
https://bugs.kde.org/show_bug.cgi?id=XXXXXX
|
||||
where XXXXXX is the bug number as listed below.
|
||||
|
||||
345077 linux syscall execveat support (linux 3.19)
|
||||
n-i-bz helgrind: If hg_cli__realloc fails, return NULL.
|
||||
|
||||
Release 3.16.0 (27 May 2020)
|
||||
|
||||
@ -123,6 +123,11 @@ void handle_sys_pwritev(ThreadId tid, SyscallStatus* status,
|
||||
Int fd, Addr vector, Int count,
|
||||
const char *str);
|
||||
|
||||
extern
|
||||
void handle_pre_sys_execve(ThreadId tid, SyscallStatus *status, Addr pathname,
|
||||
Addr arg_2, Addr arg_3, Bool is_execveat,
|
||||
Bool check_pathptr);
|
||||
|
||||
DECL_TEMPLATE(generic, sys_ni_syscall); // * P -- unimplemented
|
||||
DECL_TEMPLATE(generic, sys_exit);
|
||||
DECL_TEMPLATE(generic, sys_fork);
|
||||
|
||||
@ -299,6 +299,9 @@ DECL_TEMPLATE(linux, sys_membarrier);
|
||||
// Linux-specific (new in Linux 3.18)
|
||||
DECL_TEMPLATE(linux, sys_bpf);
|
||||
|
||||
// Linux-specific (new in Linux 3.19)
|
||||
DECL_TEMPLATE(linux, sys_execveat);
|
||||
|
||||
// Linux-specific (new in Linux 4.11)
|
||||
DECL_TEMPLATE(linux, sys_statx);
|
||||
|
||||
|
||||
@ -856,6 +856,7 @@ static SyscallTableEntry syscall_table[] = {
|
||||
|
||||
// LIN__(__NR_kexec_file_load, sys_ni_syscall), // 320
|
||||
LINXY(__NR_bpf, sys_bpf), // 321
|
||||
LINX_(__NR_execveat, sys_execveat), // 322
|
||||
|
||||
LINXY(__NR_preadv2, sys_preadv2), // 327
|
||||
LINX_(__NR_pwritev2, sys_pwritev2), // 328
|
||||
|
||||
@ -65,7 +65,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
void ML_(guess_and_register_stack) (Addr sp, ThreadState* tst)
|
||||
{
|
||||
Bool debug = False;
|
||||
@ -2847,9 +2846,10 @@ void VG_(reap_threads)(ThreadId self)
|
||||
vg_assert(i_am_the_only_thread());
|
||||
}
|
||||
|
||||
// XXX: prototype here seemingly doesn't match the prototype for i386-linux,
|
||||
// but it seems to work nonetheless...
|
||||
PRE(sys_execve)
|
||||
/* This handles the common part of the PRE macro for execve and execveat. */
|
||||
void handle_pre_sys_execve(ThreadId tid, SyscallStatus *status, Addr pathname,
|
||||
Addr arg_2, Addr arg_3, Bool is_execveat,
|
||||
Bool check_pathptr)
|
||||
{
|
||||
HChar* path = NULL; /* path to executable */
|
||||
HChar** envp = NULL;
|
||||
@ -2860,27 +2860,39 @@ PRE(sys_execve)
|
||||
Int i, j, tot_args;
|
||||
SysRes res;
|
||||
Bool setuid_allowed, trace_this_child;
|
||||
const char *str;
|
||||
char str2[30], str3[30];
|
||||
|
||||
PRINT("sys_execve ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %#"
|
||||
FMT_REGWORD "x )", ARG1, (HChar*)(Addr)ARG1, ARG2, ARG3);
|
||||
PRE_REG_READ3(vki_off_t, "execve",
|
||||
char *, filename, char **, argv, char **, envp);
|
||||
PRE_MEM_RASCIIZ( "execve(filename)", ARG1 );
|
||||
if (ARG2 != 0) {
|
||||
/* At least the terminating NULL must be addressable. */
|
||||
if (!ML_(safe_to_deref)((HChar **) (Addr)ARG2, sizeof(HChar *))) {
|
||||
if (is_execveat)
|
||||
str = "execveat";
|
||||
else
|
||||
str = "execve";
|
||||
|
||||
VG_(strcpy)(str2, str);
|
||||
VG_(strcpy)(str3, str);
|
||||
|
||||
if (arg_2 != 0) {
|
||||
/* At least the terminating NULL must be addressable. */
|
||||
if (!ML_(safe_to_deref)((HChar **) (Addr)arg_2, sizeof(HChar *))) {
|
||||
SET_STATUS_Failure(VKI_EFAULT);
|
||||
return;
|
||||
}
|
||||
ML_(pre_argv_envp)( ARG2, tid, "execve(argv)", "execve(argv[i])" );
|
||||
VG_(strcat)(str2, "(argv)");
|
||||
VG_(strcat)(str3, "(argv[i])");
|
||||
ML_(pre_argv_envp)( arg_2, tid, str2, str3 );
|
||||
}
|
||||
if (ARG3 != 0) {
|
||||
// Reset helper strings to syscall name.
|
||||
str2[VG_(strlen)(str)] = '\0';
|
||||
str3[VG_(strlen)(str)] = '\0';
|
||||
if (arg_3 != 0) {
|
||||
/* At least the terminating NULL must be addressable. */
|
||||
if (!ML_(safe_to_deref)((HChar **) (Addr)ARG3, sizeof(HChar *))) {
|
||||
if (!ML_(safe_to_deref)((HChar **) (Addr)arg_3, sizeof(HChar *))) {
|
||||
SET_STATUS_Failure(VKI_EFAULT);
|
||||
return;
|
||||
}
|
||||
ML_(pre_argv_envp)( ARG3, tid, "execve(envp)", "execve(envp[i])" );
|
||||
VG_(strcat)(str2, "(envp)");
|
||||
VG_(strcat)(str3, "(envp[i])");
|
||||
ML_(pre_argv_envp)( arg_3, tid, str2, str3 );
|
||||
}
|
||||
|
||||
vg_assert(VG_(is_valid_tid)(tid));
|
||||
@ -2893,35 +2905,36 @@ PRE(sys_execve)
|
||||
an effort to check that the execve will work before actually
|
||||
doing it. */
|
||||
|
||||
/* Check that the name at least begins in client-accessible storage. */
|
||||
if (ARG1 == 0 /* obviously bogus */
|
||||
|| !VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
|
||||
SET_STATUS_Failure( VKI_EFAULT );
|
||||
return;
|
||||
/* Check that the name at least begins in client-accessible storage.
|
||||
If we didn't create it ourselves in execveat. */
|
||||
if (check_pathptr
|
||||
&& !VG_(am_is_valid_for_client)( pathname, 1, VKI_PROT_READ )) {
|
||||
SET_STATUS_Failure( VKI_EFAULT );
|
||||
return;
|
||||
}
|
||||
|
||||
// debug-only printing
|
||||
if (0) {
|
||||
VG_(printf)("ARG1 = %p(%s)\n", (void*)(Addr)ARG1, (HChar*)(Addr)ARG1);
|
||||
if (ARG2) {
|
||||
VG_(printf)("ARG2 = ");
|
||||
VG_(printf)("pathname = %p(%s)\n", (void*)(Addr)pathname, (HChar*)(Addr)pathname);
|
||||
if (arg_2) {
|
||||
VG_(printf)("arg_2 = ");
|
||||
Int q;
|
||||
HChar** vec = (HChar**)(Addr)ARG2;
|
||||
HChar** vec = (HChar**)(Addr)arg_2;
|
||||
for (q = 0; vec[q]; q++)
|
||||
VG_(printf)("%p(%s) ", vec[q], vec[q]);
|
||||
VG_(printf)("\n");
|
||||
} else {
|
||||
VG_(printf)("ARG2 = null\n");
|
||||
VG_(printf)("arg_2 = null\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Decide whether or not we want to follow along
|
||||
{ // Make 'child_argv' be a pointer to the child's arg vector
|
||||
// (skipping the exe name)
|
||||
const HChar** child_argv = (const HChar**)(Addr)ARG2;
|
||||
const HChar** child_argv = (const HChar**)(Addr)arg_2;
|
||||
if (child_argv && child_argv[0] == NULL)
|
||||
child_argv = NULL;
|
||||
trace_this_child = VG_(should_we_trace_this_child)( (HChar*)(Addr)ARG1,
|
||||
trace_this_child = VG_(should_we_trace_this_child)( (HChar*)(Addr)pathname,
|
||||
child_argv );
|
||||
}
|
||||
|
||||
@ -2929,7 +2942,7 @@ PRE(sys_execve)
|
||||
// ok, etc. We allow setuid executables to run only in the case when
|
||||
// we are not simulating them, that is, they to be run natively.
|
||||
setuid_allowed = trace_this_child ? False : True;
|
||||
res = VG_(pre_exec_check)((const HChar *)(Addr)ARG1, NULL, setuid_allowed);
|
||||
res = VG_(pre_exec_check)((const HChar *)(Addr)pathname, NULL, setuid_allowed);
|
||||
if (sr_isError(res)) {
|
||||
SET_STATUS_Failure( sr_Err(res) );
|
||||
return;
|
||||
@ -2946,7 +2959,7 @@ PRE(sys_execve)
|
||||
}
|
||||
|
||||
/* After this point, we can't recover if the execve fails. */
|
||||
VG_(debugLog)(1, "syswrap", "Exec of %s\n", (HChar*)(Addr)ARG1);
|
||||
VG_(debugLog)(1, "syswrap", "Exec of %s\n", (HChar*)(Addr)pathname);
|
||||
|
||||
|
||||
// Terminate gdbserver if it is active.
|
||||
@ -2982,7 +2995,7 @@ PRE(sys_execve)
|
||||
}
|
||||
|
||||
} else {
|
||||
path = (HChar*)(Addr)ARG1;
|
||||
path = (HChar*)(Addr)pathname;
|
||||
}
|
||||
|
||||
// Set up the child's environment.
|
||||
@ -2996,29 +3009,29 @@ PRE(sys_execve)
|
||||
//
|
||||
// Then, if tracing the child, set VALGRIND_LIB for it.
|
||||
//
|
||||
if (ARG3 == 0) {
|
||||
if (arg_3 == 0) {
|
||||
envp = NULL;
|
||||
} else {
|
||||
envp = VG_(env_clone)( (HChar**)(Addr)ARG3 );
|
||||
envp = VG_(env_clone)( (HChar**)(Addr)arg_3 );
|
||||
if (envp == NULL) goto hosed;
|
||||
VG_(env_remove_valgrind_env_stuff)( envp, True /*ro_strings*/, NULL );
|
||||
}
|
||||
|
||||
if (trace_this_child) {
|
||||
// Set VALGRIND_LIB in ARG3 (the environment)
|
||||
// Set VALGRIND_LIB in arg_3 (the environment)
|
||||
VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
|
||||
}
|
||||
|
||||
// Set up the child's args. If not tracing it, they are
|
||||
// simply ARG2. Otherwise, they are
|
||||
// simply arg_2. Otherwise, they are
|
||||
//
|
||||
// [launcher_basename] ++ VG_(args_for_valgrind) ++ [ARG1] ++ ARG2[1..]
|
||||
// [launcher_basename] ++ VG_(args_for_valgrind) ++ [pathname] ++ arg_2[1..]
|
||||
//
|
||||
// except that the first VG_(args_for_valgrind_noexecpass) args
|
||||
// are omitted.
|
||||
//
|
||||
if (!trace_this_child) {
|
||||
argv = (HChar**)(Addr)ARG2;
|
||||
argv = (HChar**)(Addr)arg_2;
|
||||
} else {
|
||||
vg_assert( VG_(args_for_valgrind) );
|
||||
vg_assert( VG_(args_for_valgrind_noexecpass) >= 0 );
|
||||
@ -3033,7 +3046,7 @@ PRE(sys_execve)
|
||||
// name of client exe
|
||||
tot_args++;
|
||||
// args for client exe, skipping [0]
|
||||
arg2copy = (HChar**)(Addr)ARG2;
|
||||
arg2copy = (HChar**)(Addr)arg_2;
|
||||
if (arg2copy && arg2copy[0]) {
|
||||
for (i = 1; arg2copy[i]; i++)
|
||||
tot_args++;
|
||||
@ -3049,7 +3062,7 @@ PRE(sys_execve)
|
||||
continue;
|
||||
argv[j++] = * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i );
|
||||
}
|
||||
argv[j++] = (HChar*)(Addr)ARG1;
|
||||
argv[j++] = (HChar*)(Addr)pathname;
|
||||
if (arg2copy && arg2copy[0])
|
||||
for (i = 1; arg2copy[i]; i++)
|
||||
argv[j++] = arg2copy[i];
|
||||
@ -3113,9 +3126,9 @@ PRE(sys_execve)
|
||||
VG_(printf)("env: %s\n", *cpp);
|
||||
}
|
||||
|
||||
// always execute this because it's executing valgrind, not the "target" exe
|
||||
SET_STATUS_from_SysRes(
|
||||
VG_(do_syscall3)(__NR_execve, (UWord)path, (UWord)argv, (UWord)envp)
|
||||
);
|
||||
VG_(do_syscall3)(__NR_execve, (UWord)path, (UWord)argv, (UWord)envp));
|
||||
|
||||
/* If we got here, then the execve failed. We've already made way
|
||||
too much of a mess to continue, so we have to abort. */
|
||||
@ -3123,12 +3136,30 @@ PRE(sys_execve)
|
||||
vg_assert(FAILURE);
|
||||
VG_(message)(Vg_UserMsg, "execve(%#" FMT_REGWORD "x(%s), %#" FMT_REGWORD
|
||||
"x, %#" FMT_REGWORD "x) failed, errno %lu\n",
|
||||
ARG1, (HChar*)(Addr)ARG1, ARG2, ARG3, ERR);
|
||||
pathname, (HChar*)(Addr)pathname, arg_2, arg_3, ERR);
|
||||
VG_(message)(Vg_UserMsg, "EXEC FAILED: I can't recover from "
|
||||
"execve() failing, so I'm dying.\n");
|
||||
VG_(message)(Vg_UserMsg, "Add more stringent tests in PRE(sys_execve), "
|
||||
"or work out how to recover.\n");
|
||||
VG_(exit)(101);
|
||||
|
||||
}
|
||||
|
||||
// XXX: prototype here seemingly doesn't match the prototype for i386-linux,
|
||||
// but it seems to work nonetheless...
|
||||
PRE(sys_execve)
|
||||
{
|
||||
PRINT("sys_execve ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %#"
|
||||
FMT_REGWORD "x )", ARG1, (HChar*)(Addr)ARG1, ARG2, ARG3);
|
||||
PRE_REG_READ3(vki_off_t, "execve",
|
||||
char *, filename, char **, argv, char **, envp);
|
||||
PRE_MEM_RASCIIZ( "execve(filename)", ARG1 );
|
||||
|
||||
char *pathname = (char *)ARG1;
|
||||
Addr arg_2 = (Addr)ARG2;
|
||||
Addr arg_3 = (Addr)ARG3;
|
||||
|
||||
handle_pre_sys_execve(tid, status, (Addr)pathname, arg_2, arg_3, 0, True);
|
||||
}
|
||||
|
||||
PRE(sys_access)
|
||||
|
||||
@ -13138,6 +13138,87 @@ POST(sys_io_uring_register)
|
||||
{
|
||||
}
|
||||
|
||||
PRE(sys_execveat)
|
||||
{
|
||||
PRINT("sys_execveat ( %lu, %#lx(%s), %#lx, %#lx, %lu", ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5);
|
||||
PRE_REG_READ5(vki_off_t, "execveat",
|
||||
int, fd, char *, filename, char **, argv, char **, envp, int, flags);
|
||||
PRE_MEM_RASCIIZ( "execveat(filename)", ARG2);
|
||||
|
||||
#if !defined(__NR_execveat)
|
||||
SET_STATUS_Failure(VKI_ENOSYS);
|
||||
return;
|
||||
#endif
|
||||
|
||||
char *path = (char*) ARG2;
|
||||
Addr arg_2 = ARG3;
|
||||
Addr arg_3 = ARG4;
|
||||
const HChar *buf;
|
||||
HChar *abs_path = NULL;
|
||||
Bool check_at_symlink = False;
|
||||
Bool check_pathptr = True;
|
||||
|
||||
if (ML_(safe_to_deref) (path, 1)) {
|
||||
/* If pathname is absolute, we'll ignore dirfd
|
||||
* and just pass the pathname, try to determine
|
||||
* the absolute path otherwise. */
|
||||
if (path[0] != '/') {
|
||||
/* Check dirfd is a valid fd. */
|
||||
if (!ML_(fd_allowed)(ARG1, "execveat", tid, False)) {
|
||||
SET_STATUS_Failure( VKI_EBADF );
|
||||
return;
|
||||
}
|
||||
/* If pathname is empty and AT_EMPTY_PATH is
|
||||
set then dirfd describes the whole path. */
|
||||
if (path[0] == '\0') {
|
||||
if (ARG5 & VKI_AT_EMPTY_PATH) {
|
||||
if (VG_(resolve_filename)(ARG1, &buf)) {
|
||||
VG_(strcpy)(path, buf);
|
||||
check_pathptr = False;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ARG1 == VKI_AT_FDCWD) {
|
||||
check_at_symlink = True;
|
||||
} else
|
||||
if (ARG5 & VKI_AT_SYMLINK_NOFOLLOW)
|
||||
check_at_symlink = True;
|
||||
else if (VG_(resolve_filename)(ARG1, &buf)) {
|
||||
abs_path = VG_(malloc)("execveat",
|
||||
(VG_(strlen)(buf) + 1
|
||||
+ VG_(strlen)(path) + 1));
|
||||
VG_(sprintf)(abs_path, "%s/%s", buf, path);
|
||||
path = abs_path;
|
||||
check_pathptr = False;
|
||||
}
|
||||
else
|
||||
path = NULL;
|
||||
if (check_at_symlink) {
|
||||
struct vg_stat statbuf;
|
||||
SysRes statres;
|
||||
|
||||
statres = VG_(stat)(path, &statbuf);
|
||||
if (sr_isError(statres) || VKI_S_ISLNK(statbuf.mode)) {
|
||||
SET_STATUS_Failure( VKI_ELOOP );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SET_STATUS_Failure(VKI_EFAULT);
|
||||
return;
|
||||
}
|
||||
|
||||
handle_pre_sys_execve(tid, status, (Addr) path, arg_2, arg_3, 1,
|
||||
check_pathptr);
|
||||
|
||||
/* The exec failed, we keep running... cleanup. */
|
||||
VG_(free)(abs_path);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#undef PRE
|
||||
#undef POST
|
||||
|
||||
|
||||
@ -1296,6 +1296,8 @@ struct vki_seminfo {
|
||||
|
||||
#define VKI_EWOULDBLOCK VKI_EAGAIN
|
||||
|
||||
#define VKI_ELOOP 40
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// From linux-2.6.8.1/include/linux/wait.h
|
||||
//----------------------------------------------------------------------
|
||||
@ -1502,6 +1504,7 @@ struct vki_flock64 {
|
||||
};
|
||||
|
||||
#define VKI_AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
|
||||
#define VKI_AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// From linux-2.6.8.1/include/linux/sysctl.h
|
||||
|
||||
@ -28,7 +28,8 @@ EXTRA_DIST = \
|
||||
proc-auxv.vgtest proc-auxv.stderr.exp getregset.vgtest \
|
||||
getregset.stderr.exp getregset.stdout.exp \
|
||||
sys-preadv_pwritev.vgtest sys-preadv_pwritev.stderr.exp \
|
||||
sys-preadv2_pwritev2.vgtest sys-preadv2_pwritev2.stderr.exp
|
||||
sys-preadv2_pwritev2.vgtest sys-preadv2_pwritev2.stderr.exp \
|
||||
sys-execveat.vgtest sys-execveat.stderr.exp sys-execveat.stdout.exp
|
||||
|
||||
check_PROGRAMS = \
|
||||
brk \
|
||||
@ -47,7 +48,9 @@ check_PROGRAMS = \
|
||||
syslog-syscall \
|
||||
sys-statx \
|
||||
timerfd-syscall \
|
||||
proc-auxv
|
||||
proc-auxv \
|
||||
sys-execveat \
|
||||
check_execveat
|
||||
|
||||
if HAVE_AT_FDCWD
|
||||
check_PROGRAMS += sys-openat
|
||||
|
||||
18
memcheck/tests/linux/check_execveat.c
Normal file
18
memcheck/tests/linux/check_execveat.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int has_execveat = 0;
|
||||
#if defined(__NR_execveat)
|
||||
errno = 0;
|
||||
syscall(__NR_execveat, 0, NULL, 0, 0, 0);
|
||||
has_execveat = (errno != ENOSYS);
|
||||
#else
|
||||
has_execveat = 0;
|
||||
#endif
|
||||
|
||||
return has_execveat ? 0 : 1;
|
||||
}
|
||||
64
memcheck/tests/linux/sys-execveat.c
Normal file
64
memcheck/tests/linux/sys-execveat.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static int sys_execveat (int dirfd, const char *pathname,
|
||||
char *const argv[], char *const envp[],
|
||||
int flags)
|
||||
{
|
||||
#if defined(__NR_execveat)
|
||||
return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
char *argv[] = { "foobar", "execveat exists", NULL };
|
||||
char *envp[] = { NULL };
|
||||
DIR *dirp;
|
||||
int fd;
|
||||
|
||||
dirp = opendir("/bin");
|
||||
if (dirp == NULL) {
|
||||
perror("execveat");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fd = dirfd(dirp);
|
||||
|
||||
/* Check valgrind will produce expected warnings for the
|
||||
various wrong arguments. */
|
||||
do {
|
||||
char *mem = malloc(16);
|
||||
void *t = (void *) &mem[0];
|
||||
void *z = (void *) -1;
|
||||
int flag = *((int *) &mem[8]);
|
||||
|
||||
sys_execveat(-1, "bin/xecho", argv, envp, 0);
|
||||
sys_execveat(-1, "xecho", argv, envp, 0);
|
||||
sys_execveat(fd, "xecho", argv, envp, flag);
|
||||
sys_execveat(fd, "", argv, envp, 0);
|
||||
sys_execveat(fd, NULL, argv, envp, 0);
|
||||
sys_execveat(fd, "xecho", t, envp, 0);
|
||||
sys_execveat(fd, "xecho", z, envp, 0);
|
||||
} while (0);
|
||||
|
||||
/* Check execveat called with the correct arguments works. */
|
||||
if (sys_execveat(fd, "echo", argv, envp, 0) == -1) {
|
||||
perror("execveat");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
19
memcheck/tests/linux/sys-execveat.stderr.exp
Normal file
19
memcheck/tests/linux/sys-execveat.stderr.exp
Normal file
@ -0,0 +1,19 @@
|
||||
Syscall param execveat(flags) contains uninitialised byte(s)
|
||||
...
|
||||
by 0x........: sys_execveat (sys-execveat.c:16)
|
||||
by 0x........: main (sys-execveat.c:48)
|
||||
|
||||
Syscall param execveat(filename) points to unaddressable byte(s)
|
||||
...
|
||||
by 0x........: sys_execveat (sys-execveat.c:16)
|
||||
by 0x........: main (sys-execveat.c:50)
|
||||
Address 0x........ is not stack'd, malloc'd or (recently) free'd
|
||||
|
||||
Syscall param execveat(argv) points to uninitialised byte(s)
|
||||
...
|
||||
by 0x........: sys_execveat (sys-execveat.c:16)
|
||||
by 0x........: main (sys-execveat.c:51)
|
||||
Address 0x........ is 0 bytes inside a block of size 16 alloc'd
|
||||
at 0x........: malloc (vg_replace_malloc.c:...)
|
||||
by 0x........: main (sys-execveat.c:41)
|
||||
|
||||
1
memcheck/tests/linux/sys-execveat.stdout.exp
Normal file
1
memcheck/tests/linux/sys-execveat.stdout.exp
Normal file
@ -0,0 +1 @@
|
||||
execveat exists
|
||||
3
memcheck/tests/linux/sys-execveat.vgtest
Normal file
3
memcheck/tests/linux/sys-execveat.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prereq: ./check_execveat
|
||||
prog: sys-execveat
|
||||
vgopts: -q
|
||||
Loading…
x
Reference in New Issue
Block a user