mirror of
https://gitlab.com/niansa/execontrol.git
synced 2025-03-06 20:48:26 +01:00
Initial commit
This commit is contained in:
commit
037d77caff
3 changed files with 156 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
CMakeLists.txt.user*
|
5
CMakeLists.txt
Normal file
5
CMakeLists.txt
Normal 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
150
main.c
Normal 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, ®s);
|
||||
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, ®s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue