void piping(struct command *L){ int status, i, length; int pipefd[10][2]; length = list_size(L); for (i=0; i<length-1; i++){ pipe(pipefd[i]); } //first arguement //fork, stdin pid_t pid = fork(); if (pid == 0) { if (L->infile && !L->outfile) io_redirect(L); dup2(pipefd[0][1], 1); //connect the standard output of cat to the write end of the first pipe execvp(L->cmd, L->argv); exit(0); } else { L->pid = pid; close(pipefd[0][1]); } L=L->next; //everything in between i = 0; while (L->next != NULL){ pid = fork(); if (pid == 0) { dup2(pipefd[i][0], 0); //connect the standard input of uniq to the read end of the first pipe dup2(pipefd[i+1][1], 1); //connect the standard output of uniq to the write end of the second pipe execvp(L->cmd, L->argv); } else { L->pid = pid; close(pipefd[i+1][1]); } i++; L=L->next; } //last arguement //fork stdout pid = fork(); if (pid == 0) { if (!L->infile && L->outfile) io_redirect(L); dup2(pipefd[length-2][0], 0); //connect the standard input of sort to the read end of the second pipe execvp(L->cmd, L->argv); } else { L->pid = pid; if (L->background == 0) pid = wait(&status); } }
void exec_cmdline(struct command *L){ int i, in, out, status; pid_t pid; if (L->pipe == 1) piping(L); else { pid = fork(); if (pid == 0){ if (L->infile || L->outfile) io_redirect(L); i = execvp(L->cmd, L->argv); printf("errno is %d\n", errno); if (i < 0){ printf("%s: command not found\n", L->cmd); exit(1); } } else if (pid < 0){ printf("fork failed\n"); exit(1); } else { //pid of child if (L->pid == 0) L->pid = pid; //printf("pid: %d\n", L->pid); if (L->pcpu > 0){ LALARM = L; alarm(5); //efficiency_enforcement(L, pid); } if (L->background == 0) wait(NULL); } } }
bool judge(const char *input_file, const char *output_file_std, const char *stdout_file_executive, const char *stderr_file_executive) { rusage rused{}; pid_t executor = fork(); // create a child process for executor if (executor < 0) { FM_LOG_FATAL("fork executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } else if (executor == 0) { // child process log_add_info("executor"); off_t fsize = file_size(output_file_std); // io redirect, must before set_security_option() io_redirect(input_file, stdout_file_executive, stderr_file_executive); // chroot & setuid set_security_option(); // set memory, time and file size limit etc. set_limit(fsize); // must after set_security_option() FM_LOG_DEBUG("time limit: %d, time limit addtion: %d", oj_solution.time_limit, time_limit_addtion); uint64_t real_time_limit = oj_solution.time_limit + time_limit_addtion; // time fix // set real time alarm if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { FM_LOG_FATAL("malarm for executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("begin execute"); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { FM_LOG_FATAL("Trace executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_PTRACE); } // load program if (oj_solution.lang == LANG_JAVA) { print_executor(EXEC_J); execvp(EXEC_J[0], (char *const *) EXEC_J); } else if (oj_solution.lang == LANG_KOTLIN) { print_executor(EXEC_KT); execvp(EXEC_KT[0], (char *const *) EXEC_KT); } else if (oj_solution.lang == LANG_PYTHON27) { print_executor(EXEC_PY27); #ifdef FAST_JUDGE execvp(EXEC_PY27[0], (char * const *) EXEC_PY27); #else execv(EXEC_PY27[0], (char *const *) EXEC_PY27); #endif } else if (oj_solution.lang == LANG_PYTHON3) { print_executor(EXEC_PY3); #ifdef FAST_JUDGE execvp(EXEC_PY3[0], (char * const *) EXEC_PY3); #else execv(EXEC_PY3[0], (char *const *) EXEC_PY3); #endif } else { execl("./Main", "./Main", NULL); } // exec error FM_LOG_FATAL("exec error"); exit(EXIT_PRE_JUDGE_EXECLP); } else { // Judger int status = 0; user_regs_struct regs{}; stderr = freopen("error.txt", "a+", stderr); init_syscalls(oj_solution.lang); while (true) { if (wait4(executor, &status, 0, &rused) < 0) { FM_LOG_FATAL("wait4 executor failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } if (WIFEXITED(status)) { if ((oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN) || WEXITSTATUS(status) == EXIT_SUCCESS) { // AC PE WA FM_LOG_TRACE("normal quit"); int result; if (oj_solution.spj) { // use SPJ result = oj_compare_output_spj(input_file, output_file_std, stdout_file_executive, oj_solution.spj_exe_file); } else { // compare file result = oj_compare_output(output_file_std, stdout_file_executive); } // WA if (result == OJ_WA) { oj_solution.result = OJ_WA; } else if (oj_solution.result != OJ_PE) { // previous case is AC oj_solution.result = result; // AC or PE } else /* (oj_solution.result == OJ_PE) */ { // previous case is PE oj_solution.result = OJ_PE; } FM_LOG_NOTICE("case result: %d, problem result: %d", result, oj_solution.result); } else { // not return 0 oj_solution.result = OJ_RE; FM_LOG_NOTICE("abnormal quit, exit_code: %d", WEXITSTATUS(status)); } break; } // RE/TLE/OLE if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_NOTICE("child process killed by signal %d, %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_NOTICE("child process stopped by signal %d, %s", signo, strsignal(signo)); } switch (signo) { // Ignore case SIGCHLD: oj_solution.result = OJ_AC; break; // TLE case SIGALRM: // alarm() and setitimer(ITIMER_REAL) case SIGVTALRM: // setitimer(ITIMER_VIRTUAL) case SIGXCPU: // exceeds soft processor limit oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded: %s", strsignal(signo)); break; // OLE case SIGXFSZ: // exceeds file size limit oj_solution.result = OJ_OLE; FM_LOG_TRACE("Output Limit Exceeded"); break; // RE case SIGSEGV: // segmentation violation case SIGFPE: // any arithmetic exception case SIGBUS: // the process incurs a hardware fault case SIGABRT: // abort() function case SIGKILL: // exceeds hard processor limit default: oj_solution.result = OJ_RE; FILE *fp = fopen(stderr_file_executive, "a+"); if (fp == nullptr) { fprintf(stderr, "%s\n", strsignal(signo)); FM_LOG_WARNING("Runtime Error: %s", strsignal(signo)); } else { fprintf(fp, "%s\n", strsignal(signo)); fclose(fp); } break; } // end of swtich kill(executor, SIGKILL); break; } // end of "if (WIFSIGNALED(status) ...)" oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); // TODO(power): check why memory exceed too much if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; kill(executor, SIGKILL); break; } // check syscall if (ptrace(PTRACE_GETREGS, executor, NULL, ®s) < 0) { FM_LOG_FATAL("ptrace(PTRACE_GETREGS) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } int syscall_id = 0; #ifdef __i386__ syscall_id = (int)regs.orig_eax; #else syscall_id = (int) regs.orig_rax; #endif if (syscall_id > 0 && !is_valid_syscall(syscall_id)) { oj_solution.result = OJ_RF; FM_LOG_FATAL("restricted function, syscall_id: %d", syscall_id); kill(executor, SIGKILL); break; } if (ptrace(PTRACE_SYSCALL, executor, NULL, NULL) < 0) { FM_LOG_FATAL("ptrace(PTRACE_SYSCALL) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } } // end of while } // end of fork for judge process oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; FM_LOG_NOTICE("memory limit exceeded: %d (fault: %d * %d)", oj_solution.memory_usage, rused.ru_minflt, page_size); } oj_solution.time_usage = std::max(oj_solution.time_usage, (unsigned long) rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); if (oj_solution.time_usage > oj_solution.time_limit) { oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded"); } if (oj_solution.result != OJ_AC) { if (oj_solution.judge_type == ACM) { FM_LOG_NOTICE("not AC/PE, no need to continue"); } if (oj_solution.result == OJ_TLE) { oj_solution.time_usage = oj_solution.time_limit; } else if (oj_solution.result == OJ_WA) { if (oj_solution.lang == LANG_JAVA) { // TODO: kotlin fix_java_result(stdout_file_executive, stderr_file_executive); } else if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_file_executive)) { oj_solution.result = OJ_RE; FM_LOG_TRACE("Runtime Error"); } } return false; } return true; }
/* * 执行用户提交的程序 */ static void judge() { struct rusage rused; pid_t executive = fork(); if (executive < 0) { exit(JUDGE_CONF::EXIT_PRE_JUDGE); } else if (executive == 0) { //子进程,用户程序 FM_LOG_TRACE("Start Judging."); io_redirect(); security_control(); int real_time_limit = PROBLEM::time_limit; if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { exit(JUDGE_CONF::EXIT_PRE_JUDGE); } set_limit(); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { exit(JUDGE_CONF::EXIT_PRE_JUDGE_PTRACE); } if (PROBLEM::lang != JUDGE_CONF::LANG_JAVA){ execl("./a.out", "a.out", NULL); } else { execlp("java", "java", "Main", NULL); } //走到这了说明出错了 exit(JUDGE_CONF::EXIT_PRE_JUDGE_EXECLP); } else { //父进程 int status = 0; //子进程状态 int syscall_id = 0; //系统调用号 struct user_regs_struct regs; //寄存器 init_RF_table(PROBLEM::lang); //初始化系统调用表 while (true) {//循环监控子进程 if (wait4(executive, &status, 0, &rused) < 0) { FM_LOG_WARNING("wait4 failed."); exit(JUDGE_CONF::EXIT_JUDGE); } //自行退出 if (WIFEXITED(status)) { if (PROBLEM::lang != JUDGE_CONF::LANG_JAVA || WEXITSTATUS(status) == EXIT_SUCCESS) { FM_LOG_TRACE("OK, normal quit. All is good."); //PROBLEM::result = JUDGE_CONF::PROCEED; } else { FM_LOG_WARNING("oh, some error occured.Abnormal quit."); PROBLEM::result = JUDGE_CONF::RE; } break; } //被信号终止掉了 if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { //要过滤掉SIGTRAP信号 int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_WARNING("child signaled by %d : %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_WARNING("child stop by %d : %s\n", signo, strsignal(signo)); } switch (signo) { //TLE case SIGALRM: case SIGXCPU: case SIGVTALRM: case SIGKILL: FM_LOG_TRACE("Well, Time Limit Exeeded"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::TLE; break; case SIGXFSZ: FM_LOG_TRACE("File Limit Exceeded"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::OLE; break; case SIGSEGV: case SIGFPE: case SIGBUS: case SIGABRT: //FM_LOG_TRACE("RE了"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::RE; break; default: //FM_LOG_TRACE("不知道哪儿跪了"); PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::RE; break; } ptrace(PTRACE_KILL, executive, NULL, NULL); break; } //MLE PROBLEM::memory_usage = std::max((long int)PROBLEM::memory_usage, rused.ru_minflt * (getpagesize() / JUDGE_CONF::KILO)); if (PROBLEM::memory_usage > PROBLEM::memory_limit) { PROBLEM::time_usage = 0; PROBLEM::memory_usage = 0; PROBLEM::result = JUDGE_CONF::MLE; FM_LOG_TRACE("Well, Memory Limit Exceeded."); ptrace(PTRACE_KILL, executive, NULL, NULL); break; } //获得子进程的寄存器,目的是为了获知其系统调用 if (ptrace(PTRACE_GETREGS, executive, NULL, ®s) < 0) { FM_LOG_WARNING("ptrace PTRACE_GETREGS failed"); exit(JUDGE_CONF::EXIT_JUDGE); } #ifdef __i386__ syscall_id = regs.orig_eax; #else syscall_id = regs.orig_rax; #endif //检查系统调用是否合法 if (syscall_id > 0 && !is_valid_syscall(PROBLEM::lang, syscall_id, executive, regs)) { FM_LOG_WARNING("restricted fuction %d\n", syscall_id); if (syscall_id == SYS_rt_sigprocmask){ FM_LOG_WARNING("The glibc failed."); } else { //FM_LOG_WARNING("%d\n", SYS_write); FM_LOG_WARNING("restricted fuction table"); } PROBLEM::result = JUDGE_CONF::RE; ptrace(PTRACE_KILL, executive, NULL, NULL); break; } if (ptrace(PTRACE_SYSCALL, executive, NULL, NULL) < 0) { FM_LOG_WARNING("ptrace PTRACE_SYSCALL failed."); exit(JUDGE_CONF::EXIT_JUDGE); } } } //这儿关于time_usage和memory_usage计算的有点混乱 //主要是为了减轻web的任务 //只要不是AC,就把time_usage和memory_usage归0 if (PROBLEM::result == JUDGE_CONF::SE){ PROBLEM::time_usage += (rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); PROBLEM::time_usage += (rused.ru_stime.tv_sec * 1000 + rused.ru_stime.tv_usec / 1000); } }
enum result execute(struct request * req, struct run_result * rused) { pid_t pid; char outfile[EOJ_PATH_MAX]; char complete_fname[EOJ_PATH_MAX]; char fstdout[EOJ_PATH_MAX]; unsigned int ltime = req->time_limit, lmem = req->mem_limit; //reset syscall times check_syscall(-1, req); snprintf(outfile, EOJ_PATH_MAX, "%s%s", req->fname_nosx, req->cpl->execsuffix); snprintf(complete_fname, EOJ_PATH_MAX, "%s%s", req->out_dir, outfile); snprintf(fstdout, EOJ_PATH_MAX, "%s%s%s", req->out_dir, req->fname_nosx, ".result"); //add record only at first time if (access(fstdout, F_OK)) add_file_records(&fcreat_record, fstdout); pid = fork(); if (pid == 0) { if (set_limit(ltime, 1024)) { eoj_log("set rlimit error: %s", strerror(errno)); exit(1); } if (io_redirect(req->input_file, fstdout)) { eoj_log("ioredirect error: %s", strerror(errno)); exit(1); } ptrace(PTRACE_TRACEME, 0, NULL, NULL ); if (execl(complete_fname, outfile, NULL ) == -1) { eoj_log("exec fail: %s", strerror(errno)); exit(1); } } enum result result; int status; struct rusage rusage; long orig_ax; while (1) { if (wait4(pid, &status, 0, &rusage) < 0) { eoj_log("wait error: %s", strerror(errno)); return SYS_ERROR; } result = check_mem_rusage(&rusage, rused, lmem); if (result == MEM_LIMIT_EXCEED) { kill(pid, SIGKILL); //eoj_log("memory limit exceed"); break; } if (WIFEXITED(status)) { result = RNORMAL; break; } else if (WSTOPSIG(status) != 5) { int sig = WSTOPSIG(status); switch (sig) { case SIGXCPU: case SIGKILL: //eoj_log("time limt exceed"); result = TIME_LIMIT_EXCEED; break; case SIGXFSZ: //eoj_log("output limit exceed"); result = OUTPUT_LIMIT_EXCEED; break; default: eoj_log("unknown error,sig %s", strsignal(sig)); result = RUN_TIME_ERR; break; } kill(pid, SIGKILL); break; } /* it doesn't work.very strange */ // else if (WIFSIGNALED(status)) { // int sig = WTERMSIG(status); // switch (sig) { // case SIGKILL: // case SIGXCPU: // eoj_log("%s time limt exceed", req->fname_nosx); // result = TIME_LIMIT_EXCEED; // break; // case SIGXFSZ: // result = OUTPUT_LIMIT_EXCEED; // eoj_log("%s output limit exceed", req->fname_nosx); // break; // default: // result = RUN_TIME_ERR; // break; // } // break; // } orig_ax = ptrace(PTRACE_PEEKUSER, pid, WORDLEN * ORIG_AX, NULL ); if (orig_ax >= 0 && check_syscall(orig_ax, req)) { eoj_log("run illegal system call %ld", orig_ax); kill(pid, SIGKILL); result = RUN_TIME_ERR; break; } if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL ) < 0) { eoj_log("ptrace error: %s", strerror(errno)); kill(pid, SIGKILL); result = SYS_ERROR; break; } } return result; }