Я работаю над онлайн-судьей для проведения ACM-ICPC, например, соревнований в локальной сети моего колледжа.Для этого я требую, чтобы судья был в достаточной безопасности, чтобы предотвратить выполнение вредоносных программ на моем сервере.(Примером такой программы может быть)
int main(){
while(1) fork();
}
Позволяет вызвать исполняемый файл этой программы testcode .
Эта программа заставит мой сервер, на котором работает судья,замораживать.Очевидно, я не хочу, чтобы это произошло. Чтобы предотвратить это, я попытался использовать ptrace. Я придумал следующий код: (Позволяет вызвать исполняемый файл этого кода monitor )
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/reg.h>
#include<stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/reg.h>
#include<stdio.h>
#include<signal.h>
#include<sys/prctl.h>
#include<stdlib.h>
#define NOBANNEDSYS 40
int bannedsys[50]={2,14,12,15,26,37,38,39,39,40,41,42,46,47,48,49,50,60,61,63,72,83,88,120,102,182,183,190};
int main(int argc,char **argv) {
int insyscall=0;
if(argc!=2) {
fprintf(stderr,"Usage: %s <prog name> ",argv[0]);
exit(-1);
}
int status = 0;
int syscall_n = 0;
int entering = 1;
int amp;
struct user_regs_struct regs;
int pid = fork();
if ( !pid ) {
prctl(PR_SET_PDEATHSIG, SIGKILL);
ptrace( PTRACE_TRACEME, 0, 0, 0 );
execlp( argv[1],argv[1], 0 );
}
else {
//ptrace( PTRACE_SINGLESTEP ,pid, 0, 0 );
// ptrace( PTRACE_SYSCALL, pid, 0, 0 );
while (1) {
wait( &);
if ( WIFEXITED( amp ) ) break;
//ptrace( PTRACE_SINGLESTEP ,pid, 0, 0 );
if(insyscall==0){
ptrace( PTRACE_GETREGS, pid, 0,®s );
int i=0;
for(i=0;i<NOBANNEDSYS;i++) if(regs.orig_eax==bannedsys[i]) { kill(pid,SIGKILL);
printf("%d killed due to illegal system call\n",pid);
abort();
}
insyscall=1;
}
else insyscall=0;
// ptrace(PTRACE_CONT,pid,0,0);
// wait(&);
ptrace( PTRACE_SYSCALL, pid, 0, 0 );
// puts("Here");
//ptrace(PTRACE_CONT, pid, 0, 0);
}
}
return 0;
}
Этот код хорошо работает при блокировке системных вызовов, которые могут вызвать проблемы. Но когда отслеживаемый код содержит вызовы fork в цикле, такие как testcode , машина зависает из-за перебора.в то время как исходный процесс уничтожен кодом монитора, его ребенок выживает и продолжает нести вилочную бомбу.Как исправить код монитора, чтобы его можно было успешно развернуть?
PS: переносимость не имеет значения. Я ищу ответ для Linux.
РЕДАКТИРОВАТЬ: я использовал setrlimit для настройкимаксимальное число дочерних процессов до 0 до вызова exec.Это до сих пор кажется хорошим решением. Хотя было бы неплохо услышать от сообщества, если в коде монитора все еще есть лазейки.