私は、大学の LAN で ACM-ICPC のような競技を実施するためのオンライン審査員に取り組んでいます。そのためには、サーバー上で悪意のあるプログラムが実行されないように、裁判官が十分に安全である必要があります。(そのようなプログラムの例は次のようになります)
int main(){
while(1) fork();
}
このプログラムtestcodeの実行可能ファイルを呼び出しましょう。
このプログラムは、ジャッジを実行しているサーバーをフリーズさせます。明らかに、私はそれが起こることを望んでいません。それを防ぐために、ptraceを使用してみました。次のコードを思いつきました:(このコードモニターの実行可能ファイルを呼び出しましょう)
#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 呼び出しが含まれている場合、マシンはスラッシングのためにフリーズします。元のプロセスが強制終了されている間、私が理解できる理由は次のとおりです。モニターコードによって、その子は生き残り、フォーク爆弾を運び続けます。正常にデプロイできるようにモニター・コードを修正するにはどうすればよいですか?
PS: 移植性は問題ではありません。Linux 固有の回答を探しています。
編集: exec を呼び出す前に子プロセスの最大数を 0 に設定するために setrlimit を使用しました。