mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-03 09:48:29 +00:00
Spoof PID across execve() on Windows
It's now possible with cosmo and redbean, to deliver a signal to a child process after it has called execve(). However the executed program needs to be compiled using cosmocc. The cosmo runtime WinMain() implementation now intercepts a _COSMO_PID environment variable that's set by execve(). It ensures the child process will use the same C:\ProgramData\cosmo\sigs file, which is where kill() will place the delivered signal. We are able to do this on Windows even better than NetBSD, which has a bug with this Fixes #1334
This commit is contained in:
parent
9cc1bd04b2
commit
26c051c297
8 changed files with 187 additions and 21 deletions
|
@ -17,13 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/struct/sigset.internal.h"
|
||||
#include "libc/calls/syscall-nt.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/fds.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nt/enum/processaccess.h"
|
||||
#include "libc/nt/enum/startf.h"
|
||||
|
@ -33,8 +34,10 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/processinformation.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/proc/describefds.internal.h"
|
||||
#include "libc/proc/ntspawn.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -43,23 +46,37 @@
|
|||
#include "libc/thread/thread.h"
|
||||
#ifdef __x86_64__
|
||||
|
||||
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
|
||||
|
||||
extern pthread_mutex_t __sig_worker_lock;
|
||||
|
||||
static void sys_execve_nt_abort(sigset_t sigmask) {
|
||||
_pthread_unlock();
|
||||
pthread_mutex_unlock(&__sig_worker_lock);
|
||||
__sig_unblock(sigmask);
|
||||
}
|
||||
|
||||
textwindows int sys_execve_nt(const char *program, char *const argv[],
|
||||
char *const envp[]) {
|
||||
|
||||
// execve() needs to be @asyncsignalsafe
|
||||
sigset_t sigmask = __sig_block();
|
||||
_pthread_lock();
|
||||
pthread_mutex_lock(&__sig_worker_lock); // order matters
|
||||
_pthread_lock(); // order matters
|
||||
|
||||
// new process should be a child of our parent
|
||||
int64_t hParentProcess;
|
||||
int ppid = sys_getppid_nt();
|
||||
if (!(hParentProcess = OpenProcess(
|
||||
kNtProcessDupHandle | kNtProcessCreateProcess, false, ppid))) {
|
||||
_pthread_unlock();
|
||||
__sig_unblock(sigmask);
|
||||
sys_execve_nt_abort(sigmask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// inherit pid
|
||||
char pidvar[11 + 21];
|
||||
FormatUint64(stpcpy(pidvar, "_COSMO_PID="), __pid);
|
||||
|
||||
// inherit signal mask
|
||||
char maskvar[6 + 21];
|
||||
FormatUint64(stpcpy(maskvar, "_MASK="), sigmask);
|
||||
|
@ -84,22 +101,26 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
if (!(fdspec = __describe_fds(g_fds.p, g_fds.n, &si, hParentProcess,
|
||||
&lpExplicitHandles, &dwExplicitHandleCount))) {
|
||||
CloseHandle(hParentProcess);
|
||||
_pthread_unlock();
|
||||
__sig_unblock(sigmask);
|
||||
sys_execve_nt_abort(sigmask);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// inherit pending signals
|
||||
atomic_fetch_or_explicit(
|
||||
__sig.process,
|
||||
atomic_load_explicit(&__get_tls()->tib_sigpending, memory_order_acquire),
|
||||
memory_order_release);
|
||||
|
||||
// launch the process
|
||||
struct NtProcessInformation pi;
|
||||
int rc = ntspawn(&(struct NtSpawnArgs){
|
||||
AT_FDCWD, program, argv, envp, (char *[]){fdspec, maskvar, 0}, 0, 0,
|
||||
hParentProcess, lpExplicitHandles, dwExplicitHandleCount, &si, &pi});
|
||||
AT_FDCWD, program, argv, envp, (char *[]){fdspec, maskvar, pidvar, 0}, 0,
|
||||
0, hParentProcess, lpExplicitHandles, dwExplicitHandleCount, &si, &pi});
|
||||
__undescribe_fds(hParentProcess, lpExplicitHandles, dwExplicitHandleCount);
|
||||
if (rc == -1) {
|
||||
free(fdspec);
|
||||
CloseHandle(hParentProcess);
|
||||
_pthread_unlock();
|
||||
__sig_unblock(sigmask);
|
||||
sys_execve_nt_abort(sigmask);
|
||||
if (GetLastError() == kNtErrorSharingViolation) {
|
||||
return etxtbsy();
|
||||
} else {
|
||||
|
@ -112,12 +133,13 @@ textwindows int sys_execve_nt(const char *program, char *const argv[],
|
|||
if (DuplicateHandle(GetCurrentProcess(), pi.hProcess, hParentProcess, &handle,
|
||||
0, false, kNtDuplicateSameAccess)) {
|
||||
unassert(!(handle & 0xFFFFFFFFFF000000));
|
||||
TerminateThisProcess(0x23000000u | handle);
|
||||
__imp_TerminateProcess(-1, 0x23000000u | handle);
|
||||
} else {
|
||||
// TODO(jart): Why does `make loc` print this?
|
||||
// kprintf("DuplicateHandle failed w/ %d\n", GetLastError());
|
||||
TerminateThisProcess(ECHILD);
|
||||
__imp_TerminateProcess(-1, ECHILD);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue