new version

This commit is contained in:
virusdefender 2016-07-25 11:19:22 +08:00
parent 93dddbc89e
commit 1a7aadef82
113 changed files with 646 additions and 1272 deletions

37
LICENSE
View File

@ -1,37 +0,0 @@
The Star And Thank Author License (SATA)
Copyright (c) <Qingdao University Online Judge Dev Team> <info@qduoj.com>
Project Url: https://github.com/QingdaoU/Judger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
And wait, the most important, you shall star/+1/like the project(s) in project url
section above first, and then thank the author(s) in Copyright section.
Here are some suggested ways:
- Email the authors a thank-you letter, and make friends with him/her/them.
- Report bugs or issues.
- Tell friends what a wonderful project this is.
- And, sure, you can just express thanks in your mind without telling the world.
Contributors of this project by forking have the option to add his/her name and
forked project url at copyright and project url sections, but shall not delete
or modify anything else in these two sections.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,34 +0,0 @@
#Judger [![Build Status](https://travis-ci.org/QingdaoU/Judger.svg?branch=master)](https://travis-ci.org/QingdaoU/Judger)
OnlineJudge 判题沙箱
##Python api 使用方法
见 demo
```
sudo python setup.py install
cd demo && sudo python demo.py
```
##C语言 api 使用方法
`#include "runner.c"`即可,然后传入 `config``result` 的结构体指针。
## 为什么不是ptrace
ptrace在很多OJ上都有应用但是不可否认的是ptrace存在一个重大缺点严重影响进程运行的性能因为每次系统调用就要进行两次上下文切换从子进程到父进程然后父进程到子进程。OJ上题目很多都需要大量的输入和输出会产生大量的系统调用导致代码运行时间加长。
##注意
- 本Judger定位于C/C++语言如果使用Java由于JVM的特殊性请设置`use_sandbox=False max_memory=MEMORY_UNLIMITED`安全方面使用Java自带的安全策略内存限制方面使用`Xms`、`Xmx`等参数。参考[这里](https://github.com/QingdaoU/OnlineJudge/blob/master/judge)关于Java的部分注释。
- `runner.c`里面硬编码了系统调用白名单在Ubuntu 14.04 64位系统上测试通过。如果在您的系统上正常程序出现了`Runtime Error`可能是部分系统调用不一致导致的。如果怀疑是这个原因提出issue请务必提供系统版本和`strace ./FILE_NAME`的结果。目前已知32位系统肯定会出现非白名单系统调用但是因为32位系统无法使用docker一般出现在本地测试环境中。
- 如果使用了 `use_nobody = True` 则需要 `root` 权限启动。
- Python api 请只使用str。
##感谢
- https://github.com/lodevil/Lo-runner
- https://github.com/quark-zju/lrun
- https://github.com/daveho/EasySandbox

View File

@ -1,34 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int *p = NULL;
int j;
char input[100];
// 150M
int v = 150000000;
printf("start\n");
for (j = 0; j < argc; j++)
printf("argv[%d]: %s\n", j, argv[j]);
scanf("%s", input);
printf("%s\n", input);
p = (int *) malloc(v);
if (p == NULL) {
printf("malloc failed\n");
}
else {
memset(p, 0, v);
printf("malloc succeeded\n");
}
printf("begin to execute command\n");
system("/bin/ls /tmp");
printf("uid: %d", getuid());
return 0;
}

View File

@ -1,49 +0,0 @@
# coding=utf-8
import os
import judger
base_path = os.path.dirname(os.path.abspath(__file__))
def _compile():
return judger.run(path="/usr/bin/gcc",
in_file=os.path.join(base_path, "in"),
out_file=os.path.join(base_path, "gcc_out"),
max_cpu_time=judger.CPU_TIME_UNLIMITED,
max_memory=judger.MEMORY_UNLIMITED,
args=[os.path.join(base_path, "demo.c"), "-o", os.path.join(base_path, "demo")],
env=["PATH=" + os.environ["PATH"]],
log_path="compile.log",
use_sandbox=False,
use_nobody=False)
def run(use_sandbox, use_nobody):
print "compile result: ", _compile()
path = os.path.join(base_path, "demo")
return judger.run(path=path,
in_file=os.path.join(base_path, "in"),
out_file=os.path.join(base_path, "out"),
# ms
max_cpu_time=2000,
# Byte
max_memory=200000000,
# args env and log_path are optional
args=["1", "2", "####"],
env=["aaa=123"],
log_path="run.log",
# default is True
use_sandbox=use_sandbox,
use_nobody=use_nobody)
print "sandbox and nobody"
print run(use_sandbox=True, use_nobody=True)
print '\n\nno sandbox and root'
print run(use_sandbox=False, use_nobody=False)
print "\n\nout: ", open("out").read()
print "\n\nno sandbox and nobody"
print run(use_sandbox=False, use_nobody=True)
print "\n\nout: ", open("out").read()

View File

@ -1 +0,0 @@
Hello world

150
judger.c
View File

@ -1,150 +0,0 @@
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <python2.7/Python.h>
#include "runner.h"
#define RaiseValueError(msg) {PyErr_SetString(PyExc_ValueError, msg); return NULL;}
static PyObject *judger_run(PyObject *self, PyObject *args, PyObject *kwargs) {
struct config config;
struct result result = {0, 0, 0, 0, 0, 0};
PyObject *args_list = NULL, *env_list = NULL, *use_sandbox = NULL, *use_nobody = NULL,
*next = NULL, *args_iter = NULL, *env_iter = NULL, *log_path = NULL;
int count = 0;
struct passwd *passwd;
static char *kwargs_list[] = {"path", "in_file", "out_file", "max_cpu_time",
"max_memory", "args", "env", "use_sandbox", "use_nobody", "log_path", NULL};
config.path = config.in_file = config.out_file = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssil|OOOOO", kwargs_list, &(config.path), &(config.in_file),
&(config.out_file), &(config.max_cpu_time), &(config.max_memory),
&args_list, &env_list, &use_sandbox, &use_nobody, &log_path)) {
RaiseValueError("Invalid args and kwargs");
}
if (config.max_cpu_time < 1 && config.max_cpu_time != CPU_TIME_UNLIMITED) {
RaiseValueError("max_cpu_time must > 1 ms or unlimited");
}
// by default, max_real_time = max_cpu_time * 3
config.max_real_time = config.max_cpu_time * 3;
if (config.max_memory < 16 * 1024 * 1024 && config.max_memory != MEMORY_UNLIMITED) {
RaiseValueError("max_memory must > 16M or unlimited");
}
if (access(config.path, F_OK) == -1) {
RaiseValueError("Exec file does not exist");
}
if (access(config.in_file, F_OK) == -1) {
RaiseValueError("in_file does not exist");
}
config.err_file = config.out_file;
config.args[count++] = config.path;
if (args_list != NULL) {
if (!PyList_Check(args_list)) {
RaiseValueError("args must be a list");
}
args_iter = PyObject_GetIter(args_list);
while (1) {
next = PyIter_Next((args_iter));
if (!next) {
break;
}
if (!PyString_Check(next) && !PyUnicode_Check(next)) {
RaiseValueError("arg in args must be a string");
}
config.args[count] = PyString_AsString(next);
count++;
if(count > 95) {
RaiseValueError("Number of args must < 95");
}
}
}
config.args[count] = NULL;
count = 0;
if (env_list != NULL) {
if (!PyList_Check(env_list)) {
RaiseValueError("env must be a list");
}
env_iter = PyObject_GetIter(env_list);
while (1) {
next = PyIter_Next(env_iter);
if (!next) {
break;
}
if (!PyString_Check(next) && !PyUnicode_Check(next)) {
RaiseValueError("env item must be a string");
}
config.env[count] = PyString_AsString(next);
count++;
if(count > 95) {
RaiseValueError("Number of env must < 95");
}
}
}
config.env[count] = NULL;
if (use_sandbox != NULL) {
if (!PyBool_Check(use_sandbox)) {
RaiseValueError("use_sandbox must ba a bool");
}
config.use_sandbox = PyObject_IsTrue(use_sandbox);
}
else {
config.use_sandbox = 1;
}
if (use_nobody != NULL) {
if (!PyBool_Check(use_nobody)) {
RaiseValueError("use_nobody must be a bool");
}
if (PyObject_IsTrue(use_nobody)) {
passwd = getpwnam("nobody");
if(passwd == NULL) {
RaiseValueError("get nobody user info failed");
}
config.gid = passwd->pw_gid;
config.uid = passwd->pw_uid;
}
else {
config.uid = config.gid = -1;
}
}
else {
config.uid = config.gid = -1;
}
if (log_path != NULL) {
if (!PyString_Check(log_path)) {
RaiseValueError("log path must be a string");
}
config.log_path = PyString_AsString(log_path);
}
else {
config.log_path = "judger.log";
}
if((config.uid != -1 || config.gid != -1) && getuid() != 0) {
RaiseValueError("Root user is required when use_nobody=True");
}
run(&config, &result);
return Py_BuildValue("{s:l, s:i, s:i, s:i, s:i, s:i}",
"cpu_time", result.cpu_time, "memory", result.memory, "real_time", result.real_time, "signal",
result.signal, "flag", result.flag, "exit_status", result.exit_status);
}
static PyMethodDef judger_methods[] = {
{"run", (PyCFunction) judger_run, METH_KEYWORDS, NULL},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initjudger(void) {
PyObject *module = Py_InitModule3("judger", judger_methods, NULL);
PyModule_AddIntConstant(module, "CPU_TIME_UNLIMITED", CPU_TIME_UNLIMITED);
PyModule_AddIntConstant(module, "MEMORY_UNLIMITED", MEMORY_UNLIMITED);
}

View File

@ -1,89 +0,0 @@
#ifndef __LOGGER__
#define __LOGGER__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/file.h>
FILE* log_open(const char *);
void log_close(FILE*);
static void log_write(int level, const char* source_filename, const int line_number, const FILE* log_fp, const char*, ...);
const int LOG_FATAL = 0;
const int LOG_WARNING = 1;
const int LOG_INFO = 2;
const int LOG_DEBUG = 3;
static char LOG_LEVEL_NOTE[][10] =
{ "FATAL", "WARNING", "INFO", "DEBUG" };
#define LOG_DEBUG(log_fp, x...) log_write(LOG_DEBUG, __FILE__, __LINE__, log_fp, ##x)
#define LOG_INFO(log_fp, x...) log_write(LOG_INFO, __FILE__ __LINE__, log_fp, ##x)
#define LOG_WARNING(log_fp, x...) log_write(LOG_WARNING, __FILE__, __LINE__, log_fp, ##x)
#define LOG_FATAL(log_fp, x...) log_write(LOG_FATAL, __FILE__, __LINE__, log_fp, ##x)
#define log_buffer_size 8192
FILE* log_open(const char* filename)
{
FILE* log_fp = fopen(filename, "a");
if (log_fp == NULL)
{
fprintf(stderr, "can not open log file %s", filename);
}
return log_fp;
}
void log_close(FILE* log_fp)
{
if (log_fp != NULL)
{
fclose(log_fp);
}
}
static void log_write(int level, const char* source_filename, const int line, const FILE* log_fp, const char *fmt, ...)
{
if (log_fp == NULL)
{
fprintf(stderr, "can not open log file");
return;
}
static char buffer[log_buffer_size];
static char log_buffer[log_buffer_size];
static char datetime[100];
static char line_str[20];
static time_t now;
now = time(NULL);
strftime(datetime, 99, "%Y-%m-%d %H:%M:%S", localtime(&now));
snprintf(line_str, 19, "%d", line);
va_list ap;
va_start(ap, fmt);
vsnprintf(log_buffer, log_buffer_size, fmt, ap);
va_end(ap);
size_t count = snprintf(buffer, log_buffer_size,
"%s [%s] [%s:%d]%s\n",
LOG_LEVEL_NOTE[level], datetime, source_filename, line, log_buffer);
fprintf(stdout, "%s", buffer);
int log_fd = fileno((FILE *)log_fp);
if (flock(log_fd, LOCK_EX) == 0)
{
if (write(log_fd, buffer, count) < 0)
{
fprintf(stderr, "write error");
return;
}
flock(log_fd, LOCK_UN);
}
else
{
fprintf(stderr, "flock error");
return;
}
}
#endif

290
runner.c
View File

@ -1,290 +0,0 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#ifndef __APPLE__
#include <seccomp.h>
#else
#warning "###### This judger can not work under OSX, installation is only for dev dependencies! #####"
#endif
#include <signal.h>
#include <errno.h>
#include <pwd.h>
#include <sched.h>
#include <grp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "runner.h"
#include "logger.h"
#define STACK_SIZE (2 * 1024 * 1024)
int set_timer(int sec, int ms, int is_cpu_time) {
struct itimerval time_val;
time_val.it_interval.tv_sec = time_val.it_interval.tv_usec = 0;
time_val.it_value.tv_sec = sec;
time_val.it_value.tv_usec = ms * 1000;
if (setitimer(is_cpu_time ? ITIMER_VIRTUAL : ITIMER_REAL, &time_val, NULL)) {
return SETITIMER_FAILED;
}
return SUCCESS;
}
int child_process(void *clone_args){
FILE *log_fp = ((struct clone_args *)clone_args)->log_fp;
struct config *config = ((struct clone_args *)clone_args)->config;
FILE *in_file = NULL, *out_file = NULL, *err_file = NULL;
struct rlimit memory_limit, cpu_time_rlimit;
gid_t group_list[] = {config->gid};
#ifndef __APPLE__
int i;
int syscalls_whitelist[] = {SCMP_SYS(read), SCMP_SYS(fstat),
SCMP_SYS(mmap), SCMP_SYS(mprotect),
SCMP_SYS(munmap), SCMP_SYS(open),
SCMP_SYS(arch_prctl), SCMP_SYS(brk),
SCMP_SYS(access), SCMP_SYS(exit_group),
SCMP_SYS(close)};
int syscalls_whitelist_length = sizeof(syscalls_whitelist) / sizeof(int);
scmp_filter_ctx ctx = NULL;
#endif
// child process
// On success, these system calls return 0.
// On error, -1 is returned, and errno is set appropriately.
if (config->max_memory != MEMORY_UNLIMITED) {
memory_limit.rlim_cur = memory_limit.rlim_max = (rlim_t) (config->max_memory) * 2;
if (setrlimit(RLIMIT_AS, &memory_limit) == -1) {
LOG_FATAL(log_fp, "setrlimit memory failed, errno: %d", errno);
ERROR(log_fp, SETRLIMIT_FAILED);
}
}
if (config->max_cpu_time != CPU_TIME_UNLIMITED) {
// cpu time
if (set_timer(config->max_cpu_time / 1000, config->max_cpu_time % 1000, 1) != SUCCESS) {
LOG_FATAL(log_fp, "set cpu time timer failed");
ERROR(log_fp, SETITIMER_FAILED);
}
// real time
if (set_timer(config->max_real_time / 1000, config->max_real_time % 1000, 0) != SUCCESS) {
LOG_FATAL(log_fp, "set real time timer failed");
ERROR(log_fp, SETITIMER_FAILED);
}
// child process can not inherit timeout rules from parent process defined by setitimer, so we use setrlimit to
// control child process max running time
cpu_time_rlimit.rlim_cur = cpu_time_rlimit.rlim_max = (config->max_cpu_time + 1000) / 1000;
if (setrlimit(RLIMIT_CPU, &cpu_time_rlimit) == -1) {
LOG_FATAL(log_fp, "setrlimit cpu time failed, errno: %d", errno);
ERROR(log_fp, SETRLIMIT_FAILED);
}
}
// read stdin from in file
// On success, these system calls return the new descriptor.
// On error, -1 is returned, and errno is set appropriately.
if (config->in_file != NULL) {
if ((in_file = fopen(config->in_file, "r")) == NULL) {
LOG_FATAL(log_fp, "failed to open stdin redirect file");
ERROR(log_fp, DUP2_FAILED);
}
if (dup2(fileno(in_file), fileno(stdin)) == -1) {
LOG_FATAL(log_fp, "dup2 stdin failed, errno: %d", errno);
ERROR(log_fp, DUP2_FAILED);
}
}
// write stdout to out file
if (config->out_file != NULL) {
if ((out_file = fopen(config->out_file, "w")) == NULL) {
LOG_FATAL(log_fp, "failed to open stdout redirect file");
ERROR(log_fp, DUP2_FAILED);
}
if (dup2(fileno(out_file), fileno(stdout)) == -1) {
LOG_FATAL(log_fp, "dup2 stdout failed, errno: %d", errno);
ERROR(log_fp, DUP2_FAILED);
}
}
// write stderr to err file
if (config->err_file != NULL) {
// if err_file and out_file are the same path, we use out_file pointer as err_file pointer, to avoid conflict
if (strcmp(config->out_file, config->err_file) == 0) {
err_file = out_file;
}
else {
if ((err_file = fopen(config->err_file, "w")) == NULL) {
LOG_FATAL(log_fp, "failed to open stderr redirect file");
ERROR(log_fp, DUP2_FAILED);
}
}
if (dup2(fileno(err_file), fileno(stderr)) == -1) {
LOG_FATAL(log_fp, "dup2 stdout failed, errno: %d", errno);
ERROR(log_fp, DUP2_FAILED);
}
}
if (config->gid != -1 && (setgid(config->gid) == -1 || setgroups(sizeof(group_list) / sizeof(gid_t), group_list) == -1)) {
LOG_FATAL(log_fp, "setgid failed, errno: %d", errno);
ERROR(log_fp, SET_GID_FAILED);
}
if (config->uid != -1 && setuid(config->uid) == -1) {
LOG_FATAL(log_fp, "setuid failed, errno: %d", errno);
ERROR(log_fp, SET_UID_FAILED);
}
#ifndef __APPLE__
if (config->use_sandbox != 0) {
// load seccomp rules
ctx = seccomp_init(SCMP_ACT_KILL);
if (!ctx) {
LOG_FATAL(log_fp, "init seccomp failed");
ERROR(log_fp, LOAD_SECCOMP_FAILED);
}
for (i = 0; i < syscalls_whitelist_length; i++) {
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls_whitelist[i], 0) != 0) {
LOG_FATAL(log_fp, "load syscall white list failed");
ERROR(log_fp, LOAD_SECCOMP_FAILED);
}
}
// add extra rule for execve
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve), 1, SCMP_A0(SCMP_CMP_EQ, config->path)) != 0) {
LOG_FATAL(log_fp, "load execve rule failed");
ERROR(log_fp, LOAD_SECCOMP_FAILED);
}
// only fd 0 1 2 are allowed
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_LE, 2)) != 0) {
LOG_FATAL(log_fp, "load dup2 rule failed");
ERROR(log_fp, LOAD_SECCOMP_FAILED);
}
if (seccomp_load(ctx) != 0) {
LOG_FATAL(log_fp, "seccomp load failed");
ERROR(log_fp, LOAD_SECCOMP_FAILED);
}
seccomp_release(ctx);
}
#endif
execve(config->path, config->args, config->env);
LOG_FATAL(log_fp, "execve failed, errno: %d", errno);
ERROR(log_fp, EXCEVE_FAILED);
return 1;
}
void run(struct config *config, struct result *result) {
int status;
struct rusage resource_usage;
struct timeval start, end;
int signal, pid;
FILE *log_fp = NULL;
char *stack = NULL;
struct clone_args clone_args;
log_fp = log_open(config->log_path);
if(log_fp == NULL){
result->flag = SYSTEM_ERROR;
return;
}
gettimeofday(&start, NULL);
if(config->max_memory < 1 && config->max_memory != MEMORY_UNLIMITED) {
LOG_FATAL(log_fp, "max_memory must > 1 or unlimited");
result->flag = SYSTEM_ERROR;
log_close(log_fp);
return;
}
if(config->max_cpu_time < 1 && config->max_cpu_time != CPU_TIME_UNLIMITED) {
LOG_FATAL(log_fp, "max_cpu_time must > 1 or unlimited");
result->flag = SYSTEM_ERROR;
log_close(log_fp);
return;
}
if((stack = malloc(STACK_SIZE)) == NULL) {
LOG_FATAL(log_fp, "malloc stack failed");
result->flag = SYSTEM_ERROR;
log_close(log_fp);
return;
}
clone_args.config = config;
clone_args.log_fp = log_fp;
pid = clone(child_process, stack + STACK_SIZE, SIGCHLD, (void *)(&clone_args));
if (pid < 0) {
LOG_FATAL(log_fp, "fork failed");
result->flag = SYSTEM_ERROR;
log_close(log_fp);
return;
}
else {
// parent process
// on success, returns the process ID of the child whose state has changed;
// On error, -1 is returned.
if (wait4(pid, &status, 0, &resource_usage) == -1) {
LOG_FATAL(log_fp, "wait4 failed");
result->flag = SYSTEM_ERROR;
log_close(log_fp);
return;
}
LOG_DEBUG(log_fp, "exit status: %d", WEXITSTATUS(status));
result->exit_status = WEXITSTATUS(status);
result->cpu_time = (int) (resource_usage.ru_utime.tv_sec * 1000 +
resource_usage.ru_utime.tv_usec / 1000 +
resource_usage.ru_stime.tv_sec * 1000 +
resource_usage.ru_stime.tv_usec / 1000);
// avoid 0 ms
if(result->cpu_time == 0) {
result->cpu_time = 1;
}
// osx: ru_maxrss the maximum resident set size utilized (in bytes).
// linux: ru_maxrss (since Linux 2.6.32)This is the maximum resident set size used (in kilobytes).
// For RUSAGE_CHILDREN, this is the resident set size of the largest child,
// not the maximum resident set size of the processtree.
result->memory = resource_usage.ru_maxrss * 1024;
result->signal = 0;
result->flag = SUCCESS;
if (WIFSIGNALED(status) != 0) {
signal = WTERMSIG(status);
LOG_DEBUG(log_fp, "signal: %d", signal);
result->signal = signal;
if (signal == SIGALRM) {
result->flag = REAL_TIME_LIMIT_EXCEEDED;
}
else if (signal == SIGVTALRM) {
result->flag = CPU_TIME_LIMIT_EXCEEDED;
}
else if (signal == SIGSEGV) {
if (config->max_memory != MEMORY_UNLIMITED && result->memory > config->max_memory) {
result->flag = MEMORY_LIMIT_EXCEEDED;
}
else {
result->flag = RUNTIME_ERROR;
}
}
// Child process error
else if (signal == SIGUSR1){
result->flag = SYSTEM_ERROR;
}
else {
result->flag = RUNTIME_ERROR;
}
}
else {
if (config->max_memory != MEMORY_UNLIMITED && result->memory > config->max_memory) {
result->flag = MEMORY_LIMIT_EXCEEDED;
}
if (WEXITSTATUS(status) != 0) {
result->flag = RUNTIME_ERROR;
}
}
gettimeofday(&end, NULL);
result->real_time = (int) (end.tv_sec * 1000 + end.tv_usec / 1000 - start.tv_sec * 1000 - start.tv_usec / 1000);
log_close(log_fp);
}
}

View File

@ -1,67 +0,0 @@
#ifndef JUDGER_RUNNER_H
#define JUDGER_RUNNER_H
#define CPU_TIME_UNLIMITED -1
#define MEMORY_UNLIMITED -1
#define SUCCESS 0
#define FORK_FAILED 1
#define WAIT4_FAILED 2
#define RUN_FAILED 3
#define SETITIMER_FAILED 4
#define SETRLIMIT_FAILED 5
#define DUP2_FAILED 6
#define EXCEVE_FAILED 7
#define LOAD_SECCOMP_FAILED 8
#define SET_UID_FAILED 9
#define SET_GID_FAILED 10
#define CPU_TIME_LIMIT_EXCEEDED 1
#define REAL_TIME_LIMIT_EXCEEDED 2
#define MEMORY_LIMIT_EXCEEDED 3
#define RUNTIME_ERROR 4
#define SYSTEM_ERROR 5
#define ERROR(log_fp, code) LOG_FATAL(log_fp, "judger return error code: %d", code);raise(SIGUSR1)
struct result {
int cpu_time;
long memory;
int real_time;
int signal;
int flag;
int exit_status;
};
struct config {
int max_cpu_time;
int max_real_time;
long max_memory;
char *path;
char *in_file;
char *out_file;
char *err_file;
char *args[100];
char *env[100];
int use_sandbox;
char *log_path;
uid_t uid;
gid_t gid;
};
void run(struct config *, struct result *);
struct clone_args {
struct config *config;
FILE *log_fp;
};
#endif

View File

@ -1,14 +0,0 @@
# coding=utf-8
import platform
from distutils.core import setup, Extension
if platform.system() != 'Darwin':
libraries = ['seccomp']
else:
libraries = []
setup(name='judger',
version='1.0',
ext_modules=[Extension('judger', sources=['judger.c', 'runner.c'],
libraries=libraries)])

157
src/child.c Normal file
View File

@ -0,0 +1,157 @@
#define _BSD_SOURCE
#define _POSIX_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <grp.h>
#include <dlfcn.h>
#include <errno.h>
#include <sched.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mount.h>
#include "runner.h"
#include "child.h"
#include "logger.h"
#include "killer.h"
void close_file(FILE *fp, ...) {
va_list args;
va_start(args, fp);
if (fp != NULL) {
fclose(fp);
}
va_end(args);
}
int child_process(void *args) {
FILE *log_fp = ((child_args *) args)->log_fp;
runner_config *config = ((child_args *) args)->config;
// set memory limit
if (config->max_memory != UNLIMITED) {
struct rlimit max_memory;
max_memory.rlim_cur = max_memory.rlim_max = (rlim_t) (config->max_memory) * 2;
if (setrlimit(RLIMIT_AS, &max_memory) != 0) {
CHILD_ERROR_EXIT(SETRLIMIT_FAILED);
}
}
// set cpu time limit (in seconds)
if (config->max_cpu_time != UNLIMITED) {
struct rlimit max_cpu_time;
max_cpu_time.rlim_cur = max_cpu_time.rlim_max = (rlim_t) ((config->max_cpu_time + 1000) / 1000);
if (setrlimit(RLIMIT_CPU, &max_cpu_time) != 0) {
CHILD_ERROR_EXIT(SETRLIMIT_FAILED);
}
}
// set max process number limit
if (config->max_process_number != UNLIMITED) {
struct rlimit max_process_number;
max_process_number.rlim_cur = max_process_number.rlim_max = (rlim_t) config->max_process_number;
if (setrlimit(RLIMIT_NPROC, &max_process_number) != 0) {
CHILD_ERROR_EXIT(SETRLIMIT_FAILED);
}
}
// set max output size limit
if (config->max_output_size != UNLIMITED) {
struct rlimit max_output_size;
max_output_size.rlim_cur = max_output_size.rlim_max = (rlim_t ) config->max_output_size;
if (setrlimit(RLIMIT_FSIZE, &max_output_size) != 0) {
CHILD_ERROR_EXIT(SETRLIMIT_FAILED);
}
}
FILE *input_file = NULL, *output_file = NULL, *error_file = NULL;
if (config->input_path != NULL) {
input_file = fopen(config->input_path, "r");
if (input_file == NULL) {
CHILD_ERROR_EXIT(DUP2_FAILED);
}
// redirect file -> stdin
// On success, these system calls return the new descriptor.
// On error, -1 is returned, and errno is set appropriately.
if (dup2(fileno(input_file), fileno(stdin)) == -1) {
// todo log
close_file(input_file);
CHILD_ERROR_EXIT(DUP2_FAILED);
}
}
if (config->output_path != NULL) {
output_file = fopen(config->output_path, "w");
if (output_file == NULL) {
close_file(input_file);
CHILD_ERROR_EXIT(DUP2_FAILED);
}
// redirect stdout -> file
if (dup2(fileno(output_file), fileno(stdout)) == -1) {
close_file(input_file, output_file);
CHILD_ERROR_EXIT(DUP2_FAILED);
}
}
if (config->error_path != NULL) {
// if outfile and error_file is the same path, we use the same file pointer
if (strcmp(config->output_path, config->error_path) == 0) {
error_file = output_file;
}
else {
error_file = fopen(config->error_path, "w");
if (error_file == NULL) {
// todo log
close_file(input_file, output_file);
CHILD_ERROR_EXIT(DUP2_FAILED);
}
}
// redirect stderr -> file
if (dup2(fileno(error_file), fileno(stderr)) == -1) {
// todo log
close_file(input_file, output_file, error_file);
CHILD_ERROR_EXIT(DUP2_FAILED);
}
}
// set gid
gid_t group_list[] = {config->gid};
if (config->gid != -1 && (setgid(config->gid) == -1 || setgroups(sizeof(group_list) / sizeof(gid_t), group_list) == -1)) {
CHILD_ERROR_EXIT(SETUID_FAILED);
}
// set uid
if (config->uid != -1 && setuid(config->uid) == -1) {
CHILD_ERROR_EXIT(SETUID_FAILED);
}
// load seccomp so
if (config->seccomp_rule_so_path != NULL) {
void *handler = dlopen(config->seccomp_rule_so_path, RTLD_LAZY);
int (*load_seccomp)(void *, runner_config *);
if (!handler) {
LOG_FATAL(log_fp, "seccomp failed");
CHILD_ERROR_EXIT(LOAD_SECCOMP_FAILED);
}
load_seccomp = dlsym(handler, "load_seccomp");
if (load_seccomp(handler, config) != 0) {
CHILD_ERROR_EXIT(LOAD_SECCOMP_FAILED);
}
}
execve(config->exe_path, config->args, config->env);
CHILD_ERROR_EXIT(EXECVE_FAILED);
return 0;
}

16
src/child.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef JUDGER_CHILD_H
#define JUDGER_CHILD_H
#include "runner.h"
#define CHILD_ERROR_EXIT(error_code)\
{\
LOG_ERROR(error_code); \
raise(SIGUSR1); \
return -1; \
}
int child_process(void *config);
#endif //JUDGER_CHILD_H

33
src/killer.c Normal file
View File

@ -0,0 +1,33 @@
#define _POSIX_SOURCE
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "killer.h"
int kill_pid(pid_t pid) {
return kill(pid, SIGKILL);
}
void *timeout_killer(void *timeout_killer_args) {
// this is a new thread, kill the process if timeout
pid_t pid = ((struct timeout_killer_args *)timeout_killer_args)->pid;
int timeout = ((struct timeout_killer_args *)timeout_killer_args)->timeout;
// On success, pthread_detach() returns 0; on error, it returns an error number.
if (pthread_detach(pthread_self()) != 0) {
kill_pid(pid);
return NULL;
}
// usleep can't be used, for time args must < 1000ms
// this may sleep longer that expected, but we will have a check at the end
if (sleep((unsigned int)((timeout + 1000) / 1000)) != 0) {
kill_pid(pid);
return NULL;
}
if (kill_pid(pid) != 0) {
return NULL;
}
return NULL;
}

13
src/killer.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef JUDGER_KILLER_H
#define JUDGER_KILLER_H
struct timeout_killer_args {
int pid;
int timeout;
};
int kill_pid(pid_t pid);
void *timeout_killer(void *timeout_killer_args);
#endif //JUDGER_KILLER_H

66
src/logger.c Normal file
View File

@ -0,0 +1,66 @@
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/file.h>
#include "logger.h"
#define log_buffer_size 8192
FILE *log_open(const char *filename) {
FILE *log_fp = fopen(filename, "a");
if (log_fp == NULL) {
fprintf(stderr, "can not open log file %s", filename);
}
return log_fp;
}
void log_close(FILE *log_fp) {
if (log_fp != NULL) {
fclose(log_fp);
}
}
void log_write(int level, const char *source_filename, const int line, const FILE *log_fp, const char *fmt, ...) {
char LOG_LEVEL_NOTE[][10] = {"FATAL", "WARNING", "INFO", "DEBUG"};
if (log_fp == NULL) {
fprintf(stderr, "can not open log file");
return;
}
static char buffer[log_buffer_size];
static char log_buffer[log_buffer_size];
static char datetime[100];
static char line_str[20];
static time_t now;
now = time(NULL);
strftime(datetime, 99, "%Y-%m-%d %H:%M:%S", localtime(&now));
snprintf(line_str, 19, "%d", line);
va_list ap;
va_start(ap, fmt);
vsnprintf(log_buffer, log_buffer_size, fmt, ap);
va_end(ap);
int count = snprintf(buffer, log_buffer_size,
"%s [%s] [%s:%d]%s\n",
LOG_LEVEL_NOTE[level], datetime, source_filename, line, log_buffer);
fprintf(stdout, "%s", buffer);
int log_fd = fileno((FILE *) log_fp);
if (flock(log_fd, LOCK_EX) == 0) {
if (write(log_fd, buffer, (size_t) count) < 0) {
fprintf(stderr, "write error");
return;
}
flock(log_fd, LOCK_UN);
}
else {
fprintf(stderr, "flock error");
return;
}
}

21
src/logger.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef JUDGER_LOGGER_H
#define JUDGER_LOGGER_H
#define LOG_LEVEL_FATAL 0
#define LOG_LEVEL_WARNING 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
FILE *log_open(const char *);
void log_close(FILE *);
void log_write(int level, const char *source_filename, const int line_number, const FILE *log_fp, const char *, ...);
#define LOG_DEBUG(log_fp, x...) log_write(LOG_LEVEL_DEBUG, __FILE__, __LINE__, log_fp, ##x)
#define LOG_INFO(log_fp, x...) log_write(LOG_LEVEL_INFO, __FILE__ __LINE__, log_fp, ##x)
#define LOG_WARNING(log_fp, x...) log_write(LOG_LEVEL_WARNING, __FILE__, __LINE__, log_fp, ##x)
#define LOG_FATAL(log_fp, x...) log_write(LOG_LEVEL_FATAL, __FILE__, __LINE__, log_fp, ##x)
#endif //JUDGER_LOGGER_H

8
src/rules/Python/rule.c Normal file
View File

@ -0,0 +1,8 @@
#include <seccomp.h>
#include "../../runner.h"
int load_seccomp(void *dl_handler) {
return 0;
}

39
src/rules/c_cpp/rule.c Normal file
View File

@ -0,0 +1,39 @@
#include <stdio.h>
#include <seccomp.h>
#include "../../runner.h"
int load_seccomp(void *dl_handler, runner_config *config) {
int syscalls_whitelist[] = {SCMP_SYS(read), SCMP_SYS(fstat),
SCMP_SYS(mmap), SCMP_SYS(mprotect),
SCMP_SYS(munmap), SCMP_SYS(open),
SCMP_SYS(arch_prctl), SCMP_SYS(brk),
SCMP_SYS(access), SCMP_SYS(exit_group),
SCMP_SYS(close)};
int syscalls_whitelist_length = sizeof(syscalls_whitelist) / sizeof(int);
scmp_filter_ctx ctx = NULL;
// load seccomp rules
ctx = seccomp_init(SCMP_ACT_KILL);
if (!ctx) {
return LOAD_SECCOMP_FAILED;
}
for (int i = 0; i < syscalls_whitelist_length; i++) {
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls_whitelist[i], 0) != 0) {
return LOAD_SECCOMP_FAILED;
}
}
// add extra rule for execve
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve), 1, SCMP_A0(SCMP_CMP_EQ, config->exe_path)) != 0) {
return LOAD_SECCOMP_FAILED;
}
// only fd 0 1 2 are allowed
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_LE, 2)) != 0) {
return LOAD_SECCOMP_FAILED;
}
if (seccomp_load(ctx) != 0) {
return LOAD_SECCOMP_FAILED;
}
seccomp_release(ctx);
return 0;
}

126
src/runner.c Normal file
View File

@ -0,0 +1,126 @@
#define _GNU_SOURCE
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <signal.h>
#include <pthread.h>
#include <wait.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include "runner.h"
#include "killer.h"
#include "child.h"
#include "logger.h"
#define STACK_SIZE (2 * 1024 * 1024)
void init_result(runner_result *result) {
result->error = SUCCESS;
result->cpu_time = result->real_time = result->signal = result->exit_code = 0;
result->memory = 0;
}
void run(runner_config *config, runner_result *result) {
// init log fp
FILE *log_fp = log_open(config->log_path);
// init result
init_result(result);
// check whether current user is root
uid_t uid = getuid();
if (uid != 0) {
ERROR_EXIT(ROOT_REQUIRED);
}
// check args
if ((config->max_cpu_time < 1 && config->max_cpu_time != UNLIMITED) ||
(config->max_real_time < 1 && config->max_real_time != UNLIMITED) ||
(config->max_memory < 1 && config->max_memory != UNLIMITED) ||
(config->max_process_number < 1 && config->max_process_number != UNLIMITED) ||
(config->max_output_size < 1 && config->max_output_size != UNLIMITED)) {
ERROR_EXIT(INVALID_CONFIG);
}
// malloc stack for child process
char *stack = NULL;
stack = malloc(STACK_SIZE);
if (stack == NULL) {
ERROR_EXIT(CLONE_FAILED);
}
// record current time
struct timeval start, end;
gettimeofday(&start, NULL);
// clone
child_args args;
args.config = config;
args.log_fp = log_fp;
pid_t child_pid = clone(child_process, stack + STACK_SIZE, SIGCHLD, (void *) (&args));
// pid < 0 shows clone failed
if (child_pid < 0) {
ERROR_EXIT(CLONE_FAILED);
}
else {
// create new thread to monitor process running time
pthread_t tid = 0;
if (config->max_real_time != UNLIMITED) {
struct timeout_killer_args killer_args;
killer_args.timeout = config->max_real_time;
killer_args.pid = child_pid;
if (pthread_create(&tid, NULL, timeout_killer, (void *) (&killer_args)) != 0) {
kill_pid(child_pid);
ERROR_EXIT(PTHREAD_FAILED);
}
}
int status;
struct rusage resource_usage;
// wait for child process to terminate
// on success, returns the process ID of the child whose state has changed;
// On error, -1 is returned.
if (wait4(child_pid, &status, 0, &resource_usage) == -1) {
kill_pid(child_pid);
ERROR_EXIT(WAIT_FAILED);
}
// process exited, we may need to cancel timeout killer thread
if (config->max_real_time != UNLIMITED) {
if (pthread_cancel(tid) != 0) {
// todo logging
};
}
result->exit_code = WEXITSTATUS(status);
result->cpu_time = (int) (resource_usage.ru_utime.tv_sec * 1000 +
resource_usage.ru_utime.tv_usec / 1000 +
resource_usage.ru_stime.tv_sec * 1000 +
resource_usage.ru_stime.tv_usec / 1000);
result->memory = resource_usage.ru_maxrss * 1024;
// if signaled
if (WIFSIGNALED(status) != 0) {
LOG_DEBUG(log_fp, "signal: %d", WTERMSIG(status));
result->signal = WTERMSIG(status);
}
// get end time
gettimeofday(&end, NULL);
result->real_time = (int) (end.tv_sec * 1000 + end.tv_usec / 1000 - start.tv_sec * 1000 - start.tv_usec / 1000);
log_close(log_fp);
}
}

80
src/runner.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef JUDGER_RUNNER_H
#define JUDGER_RUNNER_H
#include <sys/types.h>
#include <stdio.h>
#define UNLIMITED -1
#define DO_NOT_CHANGE -1
#define LOG_ERROR(error_code) LOG_FATAL(log_fp, "Error: "#error_code);
#define ERROR_EXIT(error_code)\
{\
LOG_ERROR(error_code); \
result->error = error_code; \
log_close(log_fp); \
return; \
}
enum {
SUCCESS = 0,
INVALID_CONFIG = -1,
CLONE_FAILED = -2,
PTHREAD_FAILED = -3,
WAIT_FAILED = -4,
ROOT_REQUIRED = -5,
LOAD_SECCOMP_FAILED = -6,
SETRLIMIT_FAILED = -7,
DUP2_FAILED = -8,
SETUID_FAILED = -9,
EXECVE_FAILED = -10
};
enum {
CPU_TIME_LIMITED = 1,
REAL_TIME_LIMIT_EXCEEDED = 2,
MEMORY_LIMIT_EXCEEDED = 3,
RUNTIME_ERROR = 4,
SYSTEM_ERROR = 5
};
typedef struct config {
int max_cpu_time;
int max_real_time;
long max_memory;
int max_process_number;
long max_output_size;
char *exe_path;
char *input_path;
char *output_path;
char *error_path;
char *args[256];
char *env[256];
char *log_path;
char *seccomp_rule_so_path;
uid_t uid;
gid_t gid;
} runner_config;
typedef struct result {
int cpu_time;
int real_time;
long memory;
int signal;
int exit_code;
int error;
} runner_result;
typedef struct child_args {
FILE *log_fp;
runner_config *config;
} child_args;
void run(runner_config *config, runner_result *result);
#endif //JUDGER_RUNNER_H

30
test/main.c Normal file
View File

@ -0,0 +1,30 @@
#include <stdio.h>
#include "../src/runner.h"
int main() {
runner_config config;
config.max_cpu_time = 100;
config.max_real_time = 100;
config.max_memory = 1024 * 1024 * 1024;
config.max_process_number = 1024;
config.max_output_size = 1024 * 1024 * 64;
config.log_path = "log.log";
config.seccomp_rule_so_path = NULL;//"/home/virusdefender/ClionProjects/Judger/output/lib/librule_c_cpp.so";
config.input_path = "/dev/null";
config.output_path = "output.txt";
config.error_path = "error.txt";
config.exe_path = "/bin/ls";
config.args[0] = "/bin/ls";
config.args[1] = "/dev";
config.args[2] = NULL;
config.env[0] = "PATH=test";
config.env[1] = NULL;
runner_result result;
run(&config, &result);
printf("cpu time:%d\nreal time:%d\nmemory:%ld\nsignal:%d\nexit code:%d\nerror:%d", result.cpu_time, result.real_time, result.memory, result.signal, result.exit_code, result.error);
return 0;
}

57
test/test_helper.h Normal file
View File

@ -0,0 +1,57 @@
/* This is a really minimal testing framework for C.
*
* Example:
*
* test_cond("Check if 1 == 1", 1==1)
* test_cond("Check if 5 > 10", 5 > 10)
* test_report()
*
* ----------------------------------------------------------------------------
*
* Copyright (c) 2010-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JDGER_TESTHELP_H
#define JDGER_TESTHELP_H
int __failed_tests = 0;
int __test_num = 0;
#define test_cond(descr,_c) do { \
__test_num++; printf("%d - %s: ", __test_num, descr); \
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
} while(0);
#define test_report() do { \
printf("%d tests, %d passed, %d failed\n", __test_num, \
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \
} \
} while(0);
#endif

View File

@ -1,15 +0,0 @@
/*
*
*/
#include <stdio.h>
#include <string.h>
int main()
{
char input[100];
scanf("%s", input);
printf("%s\n", input);
printf("Hello world");
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

@ -1 +0,0 @@
1234567890

View File

@ -1,2 +0,0 @@
1234567890
Hello world

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0}

View File

@ -1,11 +0,0 @@
/*
* cpu时间超限
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
while(1);
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 300, "max_memory": 200000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 1, "signal": 26}

View File

@ -1,11 +0,0 @@
/*
*
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
sleep(1000);
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 300, "max_memory": 200000000, "use_sandbox": false}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 2, "signal": 14}

View File

@ -1,18 +0,0 @@
/*
* 2150M
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// 150m
int big_size = 150 * 1024 * 1024;
int *b = NULL;
b = (int *)malloc(big_size);
memset(b, 0, big_size);
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 300, "max_memory": 100000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 3, "signal": 0}

View File

@ -1,18 +0,0 @@
/*
* 2300M
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// 300m
int big_size = 300 * 1024 * 1024;
int *b = NULL;
b = (int *)malloc(big_size);
memset(b, 0, big_size);
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 3000, "max_memory": 50000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 11}

View File

@ -1,15 +0,0 @@
/*
* stdout和stderr重定向
*/
#include <stdio.h>
#include <string.h>
int main()
{
char input[100];
scanf("%s", input);
fprintf(stdout, "%s\n", input);
fprintf(stderr, "%s\n", input);
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

@ -1 +0,0 @@
1234567890

View File

@ -1,2 +0,0 @@
1234567890
1234567890

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0}

View File

@ -1,15 +0,0 @@
/*
*
*/
#include <stdio.h>
#include <string.h>
int main()
{
char input[100];
scanf("%s", input);
fprintf(stdout, "%s\n", input);
fprintf(stderr, "%s\n", input);
return 17;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

@ -1 +0,0 @@
1234567890

View File

@ -1,2 +0,0 @@
1234567890
1234567890

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 0, "exit_status": 17}

View File

@ -1,12 +0,0 @@
/*
* uid gid test
*/
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("uid %d gid %d\n", getuid(), getgid());
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000, "use_sandbox": false, "use_nobody": true}

View File

View File

@ -1 +0,0 @@
uid 65534 gid 65534

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0, "exit_status": 0}

View File

@ -1,29 +0,0 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
int status;
int pid;
if ((pid = fork()) < 0) {
perror("fork error");
return 0;
}
if (pid == 0) {
while (1) {};
}
else {
struct rusage resource_usage;
if (wait4(pid, &status, 0, &resource_usage) == -1) {
perror("wait4 error!");
}
}
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 200000000, "use_sandbox": false}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0}

View File

@ -1,8 +0,0 @@
#include <stdio.h>
#include <unistd.h>
int main()
{
system("id");
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 200000000, "use_sandbox": false, "use_nobody": true}

View File

View File

@ -1 +0,0 @@
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0}

View File

@ -1,36 +0,0 @@
/*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// 1k
int small_size = 1024;
// 150m
int big_size = 150 * 1024 * 1024;
int *s = NULL, *b = NULL;
s = (int *)malloc(small_size);
if(s){
printf("malloc small size succedeed\n");
}
else{
printf("malloc small size failed\n");
return -1;
}
b = (int *)malloc(big_size);
if(b){
printf("malloc big size succedeed\n");
}
else{
printf("malloc big size failed\n");
return -2;
}
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 200000000}

View File

View File

@ -1,2 +0,0 @@
malloc small size succedeed
malloc big size succedeed

View File

@ -1 +0,0 @@
{"flag": 0, "signal": 0}

View File

@ -1,21 +0,0 @@
/*
* clone
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid;
printf("fork test\n");
pid = fork();
if(pid < 0){
printf("fork failed\n");
}
else {
printf("fork succeeded\n");
}
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 31}

View File

@ -1,14 +0,0 @@
/*
* exec
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int arg, char **args) {
char *argv[] = {"/bin/echo", "1234567890", NULL};
char *envp[] = {NULL};
printf("execve test\n");
execve("/bin/echo", argv, envp);
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 31}

View File

@ -1,26 +0,0 @@
/*
* fork
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
__attribute((constructor))
void myinit(void)
{
if(fork() < 0) {
printf("fork failed\n");
}
else {
printf("fork succeeded\n");
}
}
int main(void)
{
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 31}

View File

@ -1,17 +0,0 @@
/*
* write file
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE * fp;
fp = fopen ("/dev/null", "w");
fprintf(fp, "test");
fclose(fp);
printf("write file succeesed");
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

View File

View File

@ -1 +0,0 @@
{"flag": 4, "signal": 31}

View File

@ -1,13 +0,0 @@
/*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
system("/bin/echo test");
return 0;
}

View File

@ -1 +0,0 @@
{"language": "c", "max_cpu_time": 2000, "max_memory": 20000000}

View File

Some files were not shown because too many files have changed in this diff Show More