1
0

run.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * Loco program runner core
  3. * Copyright (C) 2011 Lodevil(Du Jiong)
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "run.h"
  19. #include <sys/ptrace.h>
  20. #include <sys/resource.h>
  21. #include <sys/types.h>
  22. #include <sys/wait.h>
  23. #include <sys/user.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include "access.h"
  27. #include "limit.h"
  28. const char *last_run_err;
  29. #define RAISE_RUN(err) {last_run_err = err;return -1;}
  30. int traceLoop(struct Runobj *runobj, struct Result *rst, pid_t pid) {
  31. int status, incall = 0;
  32. struct rusage ru;
  33. struct user_regs_struct regs;
  34. while (1) {
  35. if (wait4(pid, &status, WSTOPPED, &ru) == -1)
  36. RAISE_RUN("wait4 [WSTOPPED] failure");
  37. if (WIFEXITED(status))
  38. break;
  39. else if (WSTOPSIG(status) != SIGTRAP) {
  40. ptrace(PTRACE_KILL, pid, NULL, NULL);
  41. waitpid(pid, NULL, 0);
  42. rst->time_used = ru.ru_utime.tv_sec * 1000
  43. + ru.ru_utime.tv_usec / 1000
  44. + ru.ru_stime.tv_sec * 1000
  45. + ru.ru_stime.tv_usec / 1000;
  46. rst->memory_used = ru.ru_maxrss;
  47. switch (WSTOPSIG(status)) {
  48. case SIGSEGV:
  49. if (rst->memory_used > runobj->memory_limit)
  50. rst->judge_result = MLE;
  51. else
  52. rst->judge_result = RE;
  53. break;
  54. case SIGALRM:
  55. case SIGXCPU:
  56. rst->judge_result = TLE;
  57. break;
  58. default:
  59. rst->judge_result = RE;
  60. break;
  61. }
  62. rst->re_signum = WSTOPSIG(status);
  63. rst->time_used = ru.ru_utime.tv_sec * 1000
  64. + ru.ru_utime.tv_usec / 1000
  65. + ru.ru_stime.tv_sec * 1000
  66. + ru.ru_stime.tv_usec / 1000;
  67. rst->memory_used = ru.ru_maxrss;
  68. return 0;
  69. }
  70. if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1)
  71. RAISE_RUN("PTRACE_GETREGS failure");
  72. if (incall) {
  73. int ret = checkAccess(runobj, pid, &regs);
  74. if (ret != ACCESS_OK) {
  75. ptrace(PTRACE_KILL, pid, NULL, NULL);
  76. waitpid(pid, NULL, 0);
  77. rst->time_used = ru.ru_utime.tv_sec * 1000
  78. + ru.ru_utime.tv_usec / 1000
  79. + ru.ru_stime.tv_sec * 1000
  80. + ru.ru_stime.tv_usec / 1000;
  81. rst->memory_used = ru.ru_maxrss
  82. * (sysconf(_SC_PAGESIZE) / 1024);
  83. rst->judge_result = RE;
  84. if (ret == ACCESS_CALL_ERR) {
  85. rst->re_call = REG_SYS_CALL(&regs);
  86. } else {
  87. rst->re_file = lastFileAccess();
  88. rst->re_file_flag = REG_ARG_2(&regs);
  89. }
  90. return 0;
  91. }
  92. incall = 0;
  93. } else
  94. incall = 1;
  95. ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
  96. }
  97. rst->time_used = ru.ru_utime.tv_sec * 1000
  98. + ru.ru_utime.tv_usec / 1000
  99. + ru.ru_stime.tv_sec * 1000
  100. + ru.ru_stime.tv_usec / 1000;
  101. rst->memory_used = ru.ru_maxrss;
  102. if (rst->time_used > runobj->time_limit)
  103. rst->judge_result = TLE;
  104. else if (rst->memory_used > runobj->memory_limit)
  105. rst->judge_result = MLE;
  106. else
  107. rst->judge_result = AC;
  108. return 0;
  109. }
  110. int waitExit(struct Runobj *runobj, struct Result *rst, pid_t pid) {
  111. int status;
  112. struct rusage ru;
  113. if (wait4(pid, &status, 0, &ru) == -1)
  114. RAISE_RUN("wait4 failure");
  115. rst->time_used = ru.ru_utime.tv_sec * 1000
  116. + ru.ru_utime.tv_usec / 1000
  117. + ru.ru_stime.tv_sec * 1000
  118. + ru.ru_stime.tv_usec / 1000;
  119. rst->memory_used = ru.ru_maxrss;
  120. if (WIFSIGNALED(status)) {
  121. switch (WTERMSIG(status)) {
  122. case SIGSEGV:
  123. if (rst->memory_used > runobj->memory_limit)
  124. rst->judge_result = MLE;
  125. else
  126. rst->judge_result = RE;
  127. break;
  128. case SIGALRM:
  129. case SIGXCPU:
  130. rst->judge_result = TLE;
  131. break;
  132. default:
  133. rst->judge_result = RE;
  134. break;
  135. }
  136. rst->re_signum = WTERMSIG(status);
  137. } else {
  138. if (rst->time_used > runobj->time_limit)
  139. rst->judge_result = TLE;
  140. else if (rst->memory_used > runobj->memory_limit)
  141. rst->judge_result = MLE;
  142. else
  143. rst->judge_result = AC;
  144. }
  145. return 0;
  146. }
  147. int runit(struct Runobj *runobj, struct Result *rst) {
  148. pid_t pid;
  149. int fd_err[2];
  150. if (pipe2(fd_err, O_NONBLOCK))
  151. RAISE1("run :pipe2(fd_err) failure");
  152. pid = vfork();
  153. if (pid < 0) {
  154. close(fd_err[0]);
  155. close(fd_err[1]);
  156. RAISE1("run : vfork failure");
  157. }
  158. if (pid == 0) {
  159. close(fd_err[0]);
  160. #define RAISE_EXIT(err) {\
  161. int r = write(fd_err[1],err,strlen(err));\
  162. _exit(r);\
  163. }
  164. if (runobj->fd_in != -1)
  165. if (dup2(runobj->fd_in, 0) == -1)
  166. RAISE_EXIT("dup2 stdin failure!")
  167. if (runobj->fd_out != -1)
  168. if (dup2(runobj->fd_out, 1) == -1)
  169. RAISE_EXIT("dup2 stdout failure")
  170. if (runobj->fd_err != -1)
  171. if (dup2(runobj->fd_err, 2) == -1)
  172. RAISE_EXIT("dup2 stderr failure")
  173. if (setResLimit(runobj) == -1)
  174. RAISE_EXIT(last_limit_err)
  175. if (runobj->runner != -1)
  176. if (setuid(runobj->runner))
  177. RAISE_EXIT("setuid failure")
  178. if (runobj->trace)
  179. if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) == -1)
  180. RAISE_EXIT("TRACEME failure")
  181. execvp(runobj->args[0], (char * const *) runobj->args);
  182. RAISE_EXIT("execvp failure")
  183. } else {
  184. int r;
  185. char errbuffer[100] = { 0 };
  186. close(fd_err[1]);
  187. r = read(fd_err[0], errbuffer, 90);
  188. close(fd_err[0]);
  189. if (r > 0) {
  190. waitpid(pid, NULL, WNOHANG);
  191. RAISE(errbuffer);
  192. return -1;
  193. }
  194. if (runobj->trace)
  195. r = traceLoop(runobj, rst, pid);
  196. else
  197. r = waitExit(runobj, rst, pid);
  198. if (r)
  199. RAISE1(last_run_err);
  200. return 0;
  201. }
  202. }