Pracuję nad sędzią online do prowadzenia ACM-ICPC jak konkursy w mojej uczelni LAN. W tym celu wymagam, aby sędzia mógł być wystarczająco bezpieczny, aby zapobiec uruchamianiu się złośliwego oprogramowania na moim serwerze. (Przykładem takiego programu byłoby)Jak zapobiec procesowi powstawania większej liczby dzieci?
int main(){
while(1) fork();
}
Nazwijmy wykonywalny tego programu testcode.
Ten program spowodowałby zawieszenie mojego serwera z uruchomionym sędzią. Oczywiście ja nie chcę, żeby happen.So aby zapobiec Próbowałem za pomocą ptrace.I wpadł na następujący kod: (Nazwijmy wykonywalnego tego kodu monitora)
#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;
}
Ten kod działa całkiem dobrze w blokowaniu wywołań systemowych, które mogą powodować problemy. Ale gdy kod, który ma być monitorowany, zawiera wywołania fork w pętli, jak kod testowy, urządzenie zawiesza się z powodu rzucania. Powodem, dla którego mogłem to stwierdzić, jest to, że oryginalny proces został zabity przez monitor koduje swoje dziecko, które przeżywa i nadal niesie bombę widłową. Jak naprawić kod monitora, aby mógł zostać pomyślnie wdrożony?
PS: Przenośność nie jest problemem. Szukam konkretnej odpowiedzi na Linuksa.
EDYTOWANIE: Użyłem setrlimit do ustawienia maksymalnej liczby procesów podrzędnych na 0 przed wywołaniem exec.To do tej pory wydaje się być dobrym rozwiązaniem.Ale byłoby miło usłyszeć od społeczności, jeśli nadal istnieją luki w kod monitora.
Czy rozważałeś ograniczenie zasobów za pomocą 'setrlimit (2)' i ograniczenie 'możliwości (7)'. RTFM po więcej. –
wydaje się działać ... Ustawiłem liczbę limitów procesowych na 0. – bashrc