mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
Ensure we hook all exec* variants not just 'terminal' ones. Closes #2301
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include <map>
|
||||
#include "common/threading.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "hooks/hooks.h"
|
||||
#include "os/os_specific.h"
|
||||
#include "plthook/plthook.h"
|
||||
@@ -37,6 +38,8 @@
|
||||
|
||||
Threading::CriticalSection libLock;
|
||||
|
||||
RDOC_EXTERN_CONFIG(bool, Linux_Debug_PtraceLogging);
|
||||
|
||||
static std::map<rdcstr, rdcarray<FunctionLoadCallback>> libraryCallbacks;
|
||||
static rdcarray<rdcstr> libraryHooks;
|
||||
static rdcarray<FunctionHook> functionHooks;
|
||||
@@ -97,47 +100,95 @@ void StopAtMainInChild();
|
||||
bool StopChildAtMain(pid_t childPid);
|
||||
void ResumeProcess(pid_t childPid, uint32_t delay = 0);
|
||||
|
||||
__attribute__((visibility("default"))) int execle(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, arg);
|
||||
|
||||
rdcarray<char *> argList;
|
||||
argList.push_back((char *)arg);
|
||||
|
||||
while(true)
|
||||
{
|
||||
char *nextArg = va_arg(args, char *);
|
||||
argList.push_back(nextArg);
|
||||
|
||||
// list is terminated with a NULL
|
||||
if(!nextArg)
|
||||
break;
|
||||
}
|
||||
|
||||
char **envp = va_arg(args, char **);
|
||||
///////////////////////////////////////////////////////////////
|
||||
// exec hooks - we have to hook each variant since if the application calls the 'real' one of a
|
||||
// variant, even if it ultimately goes to execve it will be resolved to the real libc one as libc
|
||||
// doesn't get LD_PRELOAD hooked.
|
||||
//
|
||||
// There are two 'real' implementations we have, execve and execvpe that forward to the real
|
||||
// function after patching the environment. That's to allow the real function to handle the path
|
||||
// handling in the vpe case, otherwise they're identical.
|
||||
//
|
||||
// The other variants all forward to one of those - the 'l' cases unroll the va_args first before
|
||||
// calling onwards
|
||||
|
||||
#define GET_EXECL_PARAMS(has_e) \
|
||||
va_list args; \
|
||||
va_start(args, arg); \
|
||||
\
|
||||
rdcarray<char *> arglist; \
|
||||
arglist.push_back((char *)arg); \
|
||||
\
|
||||
while(true) \
|
||||
{ \
|
||||
char *nextArg = va_arg(args, char *); \
|
||||
arglist.push_back(nextArg); \
|
||||
\
|
||||
/* list is terminated with a NULL */ \
|
||||
if(!nextArg) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
char **envp = NULL; \
|
||||
if(has_e) \
|
||||
envp = va_arg(args, char **); \
|
||||
\
|
||||
va_end(args);
|
||||
|
||||
if(!realexecve)
|
||||
{
|
||||
EXECVEPROC passthru = (EXECVEPROC)dlsym(RTLD_NEXT, "execve");
|
||||
return passthru(pathname, argList.data(), envp);
|
||||
}
|
||||
__attribute__((visibility("default"))) int execl(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
GET_EXECL_PARAMS(false);
|
||||
|
||||
rdcarray<char *> modifiedEnv;
|
||||
rdcstr envpStr;
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execl(%s)", pathname);
|
||||
|
||||
// if we're not hooking children just call to the real one, but ensure we remove any hooking env
|
||||
// vars that were kept around after initialisation
|
||||
if(!RenderDoc::Inst().GetCaptureOptions().hookIntoChildren)
|
||||
{
|
||||
GetUnhookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecve(pathname, argList.data(), modifiedEnv.data());
|
||||
}
|
||||
return execve(pathname, arglist.data(), environ);
|
||||
}
|
||||
|
||||
GetHookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecve(pathname, argList.data(), modifiedEnv.data());
|
||||
__attribute__((visibility("default"))) int execlp(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
GET_EXECL_PARAMS(false);
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execlp(%s)", pathname);
|
||||
|
||||
return execvpe(pathname, arglist.data(), environ);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int execle(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
GET_EXECL_PARAMS(true);
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execle(%s)", pathname);
|
||||
|
||||
return execve(pathname, arglist.data(), envp);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int execlpe(const char *pathname, const char *arg, ...)
|
||||
{
|
||||
GET_EXECL_PARAMS(true);
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execlpe(%s)", pathname);
|
||||
|
||||
return execvpe(pathname, arglist.data(), envp);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int execv(const char *pathname, char *const argv[])
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execv(%s)", pathname);
|
||||
|
||||
return execve(pathname, argv, environ);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int execvp(const char *pathname, char *const argv[])
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("execvp(%s)", pathname);
|
||||
|
||||
return execvpe(pathname, argv, environ);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int execve(const char *pathname, char *const argv[],
|
||||
@@ -145,6 +196,9 @@ __attribute__((visibility("default"))) int execve(const char *pathname, char *co
|
||||
{
|
||||
if(!realexecve)
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("unhooked early execve(%s)", pathname);
|
||||
|
||||
EXECVEPROC passthru = (EXECVEPROC)dlsym(RTLD_NEXT, "execve");
|
||||
return passthru(pathname, argv, envp);
|
||||
}
|
||||
@@ -156,10 +210,16 @@ __attribute__((visibility("default"))) int execve(const char *pathname, char *co
|
||||
// vars that were kept around after initialisation
|
||||
if(!RenderDoc::Inst().GetCaptureOptions().hookIntoChildren)
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("unhooked execve(%s)", pathname);
|
||||
|
||||
GetUnhookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecve(pathname, argv, envp);
|
||||
return realexecve(pathname, argv, modifiedEnv.data());
|
||||
}
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("hooked execve(%s)", pathname);
|
||||
|
||||
GetHookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecve(pathname, argv, modifiedEnv.data());
|
||||
}
|
||||
@@ -169,6 +229,9 @@ __attribute__((visibility("default"))) int execvpe(const char *pathname, char *c
|
||||
{
|
||||
if(!realexecvpe)
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("unhooked early execvpe(%s)", pathname);
|
||||
|
||||
EXECVPEPROC passthru = (EXECVPEPROC)dlsym(RTLD_NEXT, "execvpe");
|
||||
return passthru(pathname, argv, envp);
|
||||
}
|
||||
@@ -180,10 +243,16 @@ __attribute__((visibility("default"))) int execvpe(const char *pathname, char *c
|
||||
// vars that were kept around after initialisation
|
||||
if(!RenderDoc::Inst().GetCaptureOptions().hookIntoChildren)
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("unhooked execvpe(%s)", pathname);
|
||||
|
||||
GetUnhookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecvpe(pathname, argv, envp);
|
||||
return realexecvpe(pathname, argv, modifiedEnv.data());
|
||||
}
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("hooked execvpe(%s)", pathname);
|
||||
|
||||
GetHookedEnvp(envp, envpStr, modifiedEnv);
|
||||
return realexecvpe(pathname, argv, modifiedEnv.data());
|
||||
}
|
||||
@@ -207,6 +276,9 @@ __attribute__((visibility("default"))) pid_t fork()
|
||||
// envp because it was probably fetched before the fork - see the exec hooks for where we patch
|
||||
// that part.
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("non-hooked fork()");
|
||||
|
||||
pid_t ret = realfork();
|
||||
if(ret == 0)
|
||||
unsetenv(RENDERDOC_VULKAN_LAYER_VAR);
|
||||
@@ -214,6 +286,9 @@ __attribute__((visibility("default"))) pid_t fork()
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("hooked fork()");
|
||||
|
||||
// fork in a captured application. Need to get the child ident and register it
|
||||
|
||||
// set up environment variables for hooking now
|
||||
@@ -223,6 +298,9 @@ __attribute__((visibility("default"))) pid_t fork()
|
||||
|
||||
if(ret == 0)
|
||||
{
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("hooked fork() in child %d", getpid());
|
||||
|
||||
StopAtMainInChild();
|
||||
}
|
||||
else if(ret > 0)
|
||||
@@ -230,6 +308,9 @@ __attribute__((visibility("default"))) pid_t fork()
|
||||
// restore environment variables
|
||||
ResetHookingEnvVars();
|
||||
|
||||
if(Linux_Debug_PtraceLogging())
|
||||
RDCLOG("hooked fork() in parent, child is %d", ret);
|
||||
|
||||
bool stopped = StopChildAtMain(ret);
|
||||
|
||||
if(stopped)
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
dlopen;
|
||||
dlsym;
|
||||
fork;
|
||||
execl;
|
||||
execlp;
|
||||
execle;
|
||||
execlpe;
|
||||
execv;
|
||||
execvp;
|
||||
execve;
|
||||
execvpe;
|
||||
_exit;
|
||||
|
||||
Reference in New Issue
Block a user