1
0
Fork 0
mirror of https://gitlab.com/niansa/execontrol.git synced 2025-03-06 20:48:26 +01:00

Initial commit

This commit is contained in:
niansa/tuxifan 2022-05-16 23:57:38 +02:00
commit 037d77caff
3 changed files with 156 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
CMakeLists.txt.user*

5
CMakeLists.txt Normal file
View file

@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(execontrol LANGUAGES C)
add_executable(execontrol main.c)

150
main.c Normal file
View file

@ -0,0 +1,150 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <sys/syscall.h>
#define run_checked(name, ...) check_ret(#name "(" #__VA_ARGS__ ")", name(__VA_ARGS__))
long check_ret(const char *fnc, long value) {
if (value < 0) {
perror(fnc);
exit(-errno);
}
return value;
}
size_t read_string(char *buffer, size_t buffer_len, int pid, unsigned long long addr) {
// Read string
size_t string_len;
for (string_len = 0; string_len != buffer_len-1; string_len++) {
buffer[string_len] = ptrace(PTRACE_PEEKDATA, pid, addr+string_len);
if (buffer[string_len] == '\0') {
break;
}
if (buffer[string_len] < 0) {
buffer[string_len] = '\0';
break;
}
}
buffer[buffer_len-1] = '\0';
return string_len;
}
void run(int pid, int *sync) {
// Start ptrace
run_checked(ptrace, PTRACE_SEIZE, pid, 0, 0);
run_checked(ptrace, PTRACE_INTERRUPT, pid, 0, 0);
run_checked(waitpid, pid, 0, 0);
run_checked(ptrace, PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL);
// Run
int lastsig = 0;
char syscall_result = 0;
for (;;) {
int status;
// Wait for next event
run_checked(ptrace, PTRACE_SYSCALL, pid, 0, lastsig);
run_checked(waitpid, pid, &status, 0);
// Handle exit
if (WIFEXITED(status)) {
exit(WEXITSTATUS(status));
}
// Handle signals
if (WIFSTOPPED(status)) {
lastsig = WSTOPSIG(status);
// Handle trap
if (lastsig == SIGTRAP) {
lastsig = 0;
// Must be a syscall; handle it
struct user_regs_struct regs;
run_checked(ptrace, PTRACE_GETREGS, pid, 0, &regs);
switch (regs.orig_rax) {
case SYS_execve: {
if (!syscall_result) {
// Read filename
char filename[1024];
read_string(filename, sizeof(filename), pid, regs.rdi);
// Check filename
if (strstr(filename, "python")) {
regs.orig_rax = -1;
regs.rax = -ECANCELED;
}
}
} break;
case SYS_clone: {
if (syscall_result) {
// Attach to it
int npid = regs.rax;
run_checked(write, sync[1], &npid, sizeof(npid));
}
} break;
case SYS_execveat: {
regs.orig_rax = -1;
regs.rax = -ENOTSUP;
} break;
}
// Toggle syscall_result flag
syscall_result = !syscall_result;
run_checked(ptrace, PTRACE_SETREGS, pid, 0, &regs);
}
}
}
}
void kill_parent() {
kill(getppid(), SIGINT);
}
int main(int argc, char **argv) {
// Check arguments
if (argc < 2) {
fprintf(stderr, "Usage: %s <pipe> <executable> [args...]\n", argv[0]);
return -EINVAL;
}
// Get arguments
char *control_pipe_path= argv[1],
*executable = argv[2],
**executable_argv = argv+2;
// Create control pipe
mkfifo(control_pipe_path, 0600);
int control_pipe = run_checked(open, control_pipe_path, O_RDWR);
// Create synchronization buffer
int sync[2];
run_checked(pipe, sync);
char syncbuf[1];
// Start process
pid_t pid = fork();
if (pid == 0) {
run_checked(write, sync[1], syncbuf, sizeof(syncbuf));
// Run given program if not init, else run init
execvp(executable, executable_argv);
perror(executable);
return -errno;
}
run_checked(read, sync[0], syncbuf, sizeof(syncbuf));
// Run
if (fork() == 0) {
atexit(kill_parent);
run(pid, sync);
exit(0);
}
// Attach to all further processes
for(;;) {
int npid;
run_checked(read, sync[0], &npid, sizeof(npid));
if (fork() == 0) {
run(npid, sync);
return 0;
}
}
}