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