]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for execveat syscall
authorAlexandra Hájková <ahajkova@redhat.com>
Thu, 9 Apr 2020 15:28:18 +0000 (17:28 +0200)
committerMark Wielaard <mark@klomp.org>
Mon, 8 Jun 2020 18:58:09 +0000 (20:58 +0200)
Refactor the code to be reusable between execve and
execveat syscalls.

https://bugs.kde.org/show_bug.cgi?id=345077

14 files changed:
.gitignore
NEWS
coregrind/m_syswrap/priv_syswrap-generic.h
coregrind/m_syswrap/priv_syswrap-linux.h
coregrind/m_syswrap/syswrap-amd64-linux.c
coregrind/m_syswrap/syswrap-generic.c
coregrind/m_syswrap/syswrap-linux.c
include/vki/vki-linux.h
memcheck/tests/linux/Makefile.am
memcheck/tests/linux/check_execveat.c [new file with mode: 0644]
memcheck/tests/linux/sys-execveat.c [new file with mode: 0644]
memcheck/tests/linux/sys-execveat.stderr.exp [new file with mode: 0644]
memcheck/tests/linux/sys-execveat.stdout.exp [new file with mode: 0644]
memcheck/tests/linux/sys-execveat.vgtest [new file with mode: 0644]

index 085a30b4ad74785aa9226f0e63ff239b54bca653..b2cd3a48e131de69b1fa8af93d16779f6d832b33 100644 (file)
 /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
diff --git a/NEWS b/NEWS
index 2eebd8874fd953b044dfe965e7ec85c187202a2b..9d89f5ec5293b38db24fb0d38c5ff7d8483383d4 100644 (file)
--- a/NEWS
+++ b/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)
index 73f9224f7681a56d3e11590c44350ae44f778bf5..4717abac6536abb0b4af05f3caec5c45586c9aa3 100644 (file)
@@ -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);
index 349a97e4d15f334a85838e2cb91345d8a041f3a8..cdc73c1e6d68f69fe6b0e2b5cf1fe7a742d7c69a 100644 (file)
@@ -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);
 
index 0aef84af99b2baa57c44ae8079b6e48e440d5717..28d90135a456a10a6c2607e302801dbd2597f589 100644 (file)
@@ -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
index 280c48f1b4a7e91bba028b36d2aee6e123d4491a..864bda76c576b3513dc663df263495c93dc3da31 100644 (file)
@@ -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)
index b32bd214adaed628d0592af2e7e8a285f4a05bfb..5b5b7eee63d495c203a88e0d683894ea71bc1fc7 100644 (file)
@@ -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
 
index ffda18f1833fb3767a6cb2b567f47310dc5948ea..75b5831650be0105af85c95f09f352065c42c735 100644 (file)
@@ -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
index 14d4a0716240a8afeae110d63c8317e2c3969044..3111f631b44f014bb281584a11686b2f15532aa9 100644 (file)
@@ -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
diff --git a/memcheck/tests/linux/check_execveat.c b/memcheck/tests/linux/check_execveat.c
new file mode 100644 (file)
index 0000000..ad6107f
--- /dev/null
@@ -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;
+}
diff --git a/memcheck/tests/linux/sys-execveat.c b/memcheck/tests/linux/sys-execveat.c
new file mode 100644 (file)
index 0000000..921b888
--- /dev/null
@@ -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);
+}
+
diff --git a/memcheck/tests/linux/sys-execveat.stderr.exp b/memcheck/tests/linux/sys-execveat.stderr.exp
new file mode 100644 (file)
index 0000000..a58b0fb
--- /dev/null
@@ -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)
+
diff --git a/memcheck/tests/linux/sys-execveat.stdout.exp b/memcheck/tests/linux/sys-execveat.stdout.exp
new file mode 100644 (file)
index 0000000..c7e51ee
--- /dev/null
@@ -0,0 +1 @@
+execveat exists
diff --git a/memcheck/tests/linux/sys-execveat.vgtest b/memcheck/tests/linux/sys-execveat.vgtest
new file mode 100644 (file)
index 0000000..87ac016
--- /dev/null
@@ -0,0 +1,3 @@
+prereq: ./check_execveat
+prog: sys-execveat
+vgopts: -q