| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /**
- * Loco program runner core
- * Copyright (C) 2011 Lodevil(Du Jiong)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "run.h"
- #include <sys/ptrace.h>
- #include <sys/resource.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <sys/user.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "access.h"
- #include "limit.h"
- const char *last_run_err;
- #define RAISE_RUN(err) {last_run_err = err;return -1;}
- int traceLoop(struct Runobj *runobj, struct Result *rst, pid_t pid) {
- int status, incall = 0;
- struct rusage ru;
- struct user_regs_struct regs;
- while (1) {
- if (wait4(pid, &status, WSTOPPED, &ru) == -1)
- RAISE_RUN("wait4 [WSTOPPED] failure");
- if (WIFEXITED(status))
- break;
- else if (WSTOPSIG(status) != SIGTRAP) {
- ptrace(PTRACE_KILL, pid, NULL, NULL);
- waitpid(pid, NULL, 0);
- rst->time_used = ru.ru_utime.tv_sec * 1000
- + ru.ru_utime.tv_usec / 1000
- + ru.ru_stime.tv_sec * 1000
- + ru.ru_stime.tv_usec / 1000;
- rst->memory_used = ru.ru_maxrss;
- switch (WSTOPSIG(status)) {
- case SIGSEGV:
- if (rst->memory_used > runobj->memory_limit)
- rst->judge_result = MLE;
- else
- rst->judge_result = RE;
- break;
- case SIGALRM:
- case SIGXCPU:
- rst->judge_result = TLE;
- break;
- default:
- rst->judge_result = RE;
- break;
- }
- rst->re_signum = WSTOPSIG(status);
- rst->time_used = ru.ru_utime.tv_sec * 1000
- + ru.ru_utime.tv_usec / 1000
- + ru.ru_stime.tv_sec * 1000
- + ru.ru_stime.tv_usec / 1000;
- rst->memory_used = ru.ru_maxrss;
- return 0;
- }
- if (ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1)
- RAISE_RUN("PTRACE_GETREGS failure");
- if (incall) {
- int ret = checkAccess(runobj, pid, ®s);
- if (ret != ACCESS_OK) {
- ptrace(PTRACE_KILL, pid, NULL, NULL);
- waitpid(pid, NULL, 0);
- rst->time_used = ru.ru_utime.tv_sec * 1000
- + ru.ru_utime.tv_usec / 1000
- + ru.ru_stime.tv_sec * 1000
- + ru.ru_stime.tv_usec / 1000;
- rst->memory_used = ru.ru_maxrss
- * (sysconf(_SC_PAGESIZE) / 1024);
- rst->judge_result = RE;
- if (ret == ACCESS_CALL_ERR) {
- rst->re_call = REG_SYS_CALL(®s);
- } else {
- rst->re_file = lastFileAccess();
- rst->re_file_flag = REG_ARG_2(®s);
- }
- return 0;
- }
- incall = 0;
- } else
- incall = 1;
- ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
- }
-
-
- rst->time_used = ru.ru_utime.tv_sec * 1000
- + ru.ru_utime.tv_usec / 1000
- + ru.ru_stime.tv_sec * 1000
- + ru.ru_stime.tv_usec / 1000;
- rst->memory_used = ru.ru_maxrss;
- if (rst->time_used > runobj->time_limit)
- rst->judge_result = TLE;
- else if (rst->memory_used > runobj->memory_limit)
- rst->judge_result = MLE;
- else
- rst->judge_result = AC;
- return 0;
- }
- int waitExit(struct Runobj *runobj, struct Result *rst, pid_t pid) {
- int status;
- struct rusage ru;
- if (wait4(pid, &status, 0, &ru) == -1)
- RAISE_RUN("wait4 failure");
- rst->time_used = ru.ru_utime.tv_sec * 1000
- + ru.ru_utime.tv_usec / 1000
- + ru.ru_stime.tv_sec * 1000
- + ru.ru_stime.tv_usec / 1000;
- rst->memory_used = ru.ru_maxrss;
- if (WIFSIGNALED(status)) {
- switch (WTERMSIG(status)) {
- case SIGSEGV:
- if (rst->memory_used > runobj->memory_limit)
- rst->judge_result = MLE;
- else
- rst->judge_result = RE;
- break;
- case SIGALRM:
- case SIGXCPU:
- rst->judge_result = TLE;
- break;
- default:
- rst->judge_result = RE;
- break;
- }
- rst->re_signum = WTERMSIG(status);
- } else {
- if (rst->time_used > runobj->time_limit)
- rst->judge_result = TLE;
- else if (rst->memory_used > runobj->memory_limit)
- rst->judge_result = MLE;
- else
- rst->judge_result = AC;
- }
- return 0;
- }
- int runit(struct Runobj *runobj, struct Result *rst) {
- pid_t pid;
- int fd_err[2];
- if (pipe2(fd_err, O_NONBLOCK))
- RAISE1("run :pipe2(fd_err) failure");
- pid = vfork();
- if (pid < 0) {
- close(fd_err[0]);
- close(fd_err[1]);
- RAISE1("run : vfork failure");
- }
- if (pid == 0) {
- close(fd_err[0]);
- #define RAISE_EXIT(err) {\
- int r = write(fd_err[1],err,strlen(err));\
- _exit(r);\
- }
- if (runobj->fd_in != -1)
- if (dup2(runobj->fd_in, 0) == -1)
- RAISE_EXIT("dup2 stdin failure!")
- if (runobj->fd_out != -1)
- if (dup2(runobj->fd_out, 1) == -1)
- RAISE_EXIT("dup2 stdout failure")
- if (runobj->fd_err != -1)
- if (dup2(runobj->fd_err, 2) == -1)
- RAISE_EXIT("dup2 stderr failure")
- if (setResLimit(runobj) == -1)
- RAISE_EXIT(last_limit_err)
- if (runobj->runner != -1)
- if (setuid(runobj->runner))
- RAISE_EXIT("setuid failure")
- if (runobj->trace)
- if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1)
- RAISE_EXIT("TRACEME failure")
- execvp(runobj->args[0], (char * const *) runobj->args);
- RAISE_EXIT("execvp failure")
- } else {
- int r;
- char errbuffer[100] = { 0 };
- close(fd_err[1]);
- r = read(fd_err[0], errbuffer, 90);
- close(fd_err[0]);
- if (r > 0) {
- waitpid(pid, NULL, WNOHANG);
- RAISE(errbuffer);
- return -1;
- }
- if (runobj->trace)
- r = traceLoop(runobj, rst, pid);
- else
- r = waitExit(runobj, rst, pid);
- if (r)
- RAISE1(last_run_err);
- return 0;
- }
- }
|