Mark Wielaard 4d61a8
diff --git a/coregrind/m_syswrap/priv_syswrap-generic.h b/coregrind/m_syswrap/priv_syswrap-generic.h
Mark Wielaard 4d61a8
index 4717abac6..c50b31399 100644
Mark Wielaard 4d61a8
--- a/coregrind/m_syswrap/priv_syswrap-generic.h
Mark Wielaard 4d61a8
+++ b/coregrind/m_syswrap/priv_syswrap-generic.h
Mark Wielaard 4d61a8
@@ -106,6 +106,10 @@ extern Bool
Mark Wielaard 4d61a8
 ML_(handle_auxv_open)(SyscallStatus *status, const HChar *filename,
Mark Wielaard 4d61a8
                       int flags);
Mark Wielaard 4d61a8
 
Mark Wielaard 4d61a8
+extern Bool
Mark Wielaard 4d61a8
+ML_(handle_self_exe_open)(SyscallStatus *status, const HChar *filename,
Mark Wielaard 4d61a8
+                          int flags);
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
 /* Helper function for generic mprotect and linux pkey_mprotect. */
Mark Wielaard 4d61a8
 extern void handle_sys_mprotect (ThreadId tid, SyscallStatus *status,
Mark Wielaard 4d61a8
                                  Addr *addr, SizeT *len, Int *prot);
Mark Wielaard 4d61a8
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
Mark Wielaard 4d61a8
index 7d4b385a3..3810f7474 100644
Mark Wielaard 4d61a8
--- a/coregrind/m_syswrap/syswrap-generic.c
Mark Wielaard 4d61a8
+++ b/coregrind/m_syswrap/syswrap-generic.c
Mark Wielaard 4d61a8
@@ -4078,6 +4078,38 @@ Bool ML_(handle_auxv_open)(SyscallStatus *status, const HChar *filename,
Mark Wielaard 4d61a8
 }
Mark Wielaard 4d61a8
 #endif // defined(VGO_linux) || defined(VGO_solaris)
Mark Wielaard 4d61a8
 
Mark Wielaard 4d61a8
+#if defined(VGO_linux)
Mark Wielaard 4d61a8
+Bool ML_(handle_self_exe_open)(SyscallStatus *status, const HChar *filename,
Mark Wielaard 4d61a8
+                               int flags)
Mark Wielaard 4d61a8
+{
Mark Wielaard 4d61a8
+   HChar  name[30];   // large enough for /proc/<int>/exe
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
+   if (!ML_(safe_to_deref)((const void *) filename, 1))
Mark Wielaard 4d61a8
+      return False;
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
+   /* Opening /proc/<pid>/exe or /proc/self/exe? */
Mark Wielaard 4d61a8
+   VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
Mark Wielaard 4d61a8
+   if (!VG_STREQ(filename, name) && !VG_STREQ(filename, "/proc/self/exe"))
Mark Wielaard 4d61a8
+      return False;
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
+   /* Allow to open the file only for reading. */
Mark Wielaard 4d61a8
+   if (flags & (VKI_O_WRONLY | VKI_O_RDWR)) {
Mark Wielaard 4d61a8
+      SET_STATUS_Failure(VKI_EACCES);
Mark Wielaard 4d61a8
+      return True;
Mark Wielaard 4d61a8
+   }
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
+   SysRes sres = VG_(dup)(VG_(cl_exec_fd));
Mark Wielaard 4d61a8
+   SET_STATUS_from_SysRes(sres);
Mark Wielaard 4d61a8
+   if (!sr_isError(sres)) {
Mark Wielaard 4d61a8
+      OffT off = VG_(lseek)(sr_Res(sres), 0, VKI_SEEK_SET);
Mark Wielaard 4d61a8
+      if (off < 0)
Mark Wielaard 4d61a8
+         SET_STATUS_Failure(VKI_EMFILE);
Mark Wielaard 4d61a8
+   }
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
+   return True;
Mark Wielaard 4d61a8
+}
Mark Wielaard 4d61a8
+#endif // defined(VGO_linux)
Mark Wielaard 4d61a8
+
Mark Wielaard 4d61a8
 PRE(sys_open)
Mark Wielaard 4d61a8
 {
Mark Wielaard 4d61a8
    if (ARG2 & VKI_O_CREAT) {
Mark Wielaard 4d61a8
@@ -4119,8 +4151,10 @@ PRE(sys_open)
Mark Wielaard 4d61a8
       }
Mark Wielaard 4d61a8
    }
Mark Wielaard 4d61a8
 
Mark Wielaard 4d61a8
-   /* Handle also the case of /proc/self/auxv or /proc/<pid>/auxv. */
Mark Wielaard 4d61a8
-   if (ML_(handle_auxv_open)(status, (const HChar *)(Addr)ARG1, ARG2))
Mark Wielaard 4d61a8
+   /* Handle also the case of /proc/self/auxv or /proc/<pid>/auxv
Mark Wielaard 4d61a8
+      or /proc/self/exe or /proc/<pid>/exe. */
Mark Wielaard 4d61a8
+   if (ML_(handle_auxv_open)(status, (const HChar *)(Addr)ARG1, ARG2)
Mark Wielaard 4d61a8
+       || ML_(handle_self_exe_open)(status, (const HChar *)(Addr)ARG1, ARG2))
Mark Wielaard 4d61a8
       return;
Mark Wielaard 4d61a8
 #endif // defined(VGO_linux)
Mark Wielaard 4d61a8