From b9ad32cc66bf2f8f6621d4b3cf9b7a2c3d2d59ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20El=C3=ADas?= Date: Sun, 15 Feb 2015 18:08:46 +0000 Subject: [PATCH 1/5] Added MLE errors --- Makefile | 4 ++ isolate.c | 131 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 100 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 7a1f8b8..1e0db31 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,10 @@ isolate: isolate.c gcc -o isolate isolate.c -O2 -Wall -Wno-parentheses -Wno-unused-result -g -std=c99 +install: + cp isolate /usr/local/bin/isolate + chown root /usr/local/bin/isolate + chmod u+s /usr/local/bin/isolate isolate.1: isolate.1.txt a2x -f manpage -D . $< diff --git a/isolate.c b/isolate.c index 0023cbf..a67263b 100644 --- a/isolate.c +++ b/isolate.c @@ -40,6 +40,7 @@ #ifndef MS_REC #define MS_REC (1 << 14) #endif +#define MEM_BUF_SIZE 8192 #define NONRET __attribute__((noreturn)) #define UNUSED __attribute__((unused)) @@ -52,6 +53,7 @@ static int pass_environ; static int verbose; static int fsize_limit; static int memory_limit; +static int soft_memory_limit; static int stack_limit; static int block_quota; static int inode_quota; @@ -316,6 +318,46 @@ chowntree(char *path, uid_t uid, gid_t gid) nftw(path, chowntree_helper, 32, FTW_MOUNT | FTW_PHYS); } +int max (int a, int b) +{ + return (a > b ? a : b); +} + +int memusage (pid_t pid) +{ + char a[MEM_BUF_SIZE], *p, *q; + int data, stack; + int n, v, fd; + + p = a; + sprintf (p, "/proc/%d/status", pid); + fd = open (p, O_RDONLY); + if (fd < 0) + err ("Error while opening status file"); + do + n = read (fd, p, MEM_BUF_SIZE); + while ((n < 0) && (errno == EINTR)); + if (n < 0) + err ("Error while reading status file"); + do + v = close (fd); + while ((v < 0) && (errno == EINTR)); + if (v < 0) + err ("Error closing status file"); + + data = stack = 0; + q = strstr (p, "VmData:"); + if (q != NULL) + { + sscanf (q, "%*s %d", &data); + q = strstr (q, "VmStk:"); + if (q != NULL) + sscanf (q, "%*s %d\n", &stack); + } + + return (data + stack); +} + /*** Environment rules ***/ struct env_rule { @@ -1104,44 +1146,60 @@ box_keeper(void) alarm(1); } - for(;;) + + struct rusage rus; + int stat; + pid_t p; + int mem = 64; + do { + if(timer_tick) { - struct rusage rus; - int stat; - pid_t p; - if (timer_tick) - { - check_timeout(); - timer_tick = 0; - } - p = wait4(box_pid, &stat, 0, &rus); - if (p < 0) - { - if (errno == EINTR) - continue; - die("wait4: %m"); - } - if (p != box_pid) - die("wait4: unknown pid %d exited!", p); - box_pid = 0; - - // Check error pipe if there is an internal error passed from inside the box - char interr[1024]; - int n = read(read_errors_from_fd, interr, sizeof(interr) - 1); - if (n > 0) + check_timeout(); + timer_tick = 0; + } + if(soft_memory_limit) { + mem = max (mem, memusage (box_pid)); + if(mem > soft_memory_limit) { + kill(box_pid, SIGKILL); + kill(-box_pid, SIGKILL); + } + } + + do + p = wait4(box_pid, &stat, WNOHANG | WUNTRACED, &rus); + while ((p < 0 && (errno != EINTR))); + if(p < 0) + { + if(errno == EINTR) + continue; + die("wait4: %m"); + } + } while (p == 0); + if (p != box_pid) + die("wait4: unknown pid %d exited!", p); + box_pid = 0; + + // Check error pipe if there is an internal error passed from inside the box + char interr[1024]; + int n = read(read_errors_from_fd, interr, sizeof(interr) - 1); + if (n > 0) { interr[n] = 0; die("%s", interr); } - if (WIFEXITED(stat)) + if(mem > soft_memory_limit) { + err("MLE: Memory limit exceeded"); + } + + if (WIFEXITED(stat)) { final_stats(&rus); if (WEXITSTATUS(stat)) - { - meta_printf("exitcode:%d\n", WEXITSTATUS(stat)); - err("RE: Exited with error status %d", WEXITSTATUS(stat)); - } + { + meta_printf("exitcode:%d\n", WEXITSTATUS(stat)); + err("RE: Exited with error status %d", WEXITSTATUS(stat)); + } if (timeout && total_ms > timeout) err("TO: Time limit exceeded"); if (wall_timeout && wall_ms > wall_timeout) @@ -1152,21 +1210,20 @@ box_keeper(void) wall_ms/1000, wall_ms%1000); box_exit(0); } - else if (WIFSIGNALED(stat)) + else if (WIFSIGNALED(stat)) { meta_printf("exitsig:%d\n", WTERMSIG(stat)); final_stats(&rus); err("SG: Caught fatal signal %d", WTERMSIG(stat)); } - else if (WIFSTOPPED(stat)) + else if (WIFSTOPPED(stat)) { meta_printf("exitsig:%d\n", WSTOPSIG(stat)); final_stats(&rus); err("SG: Stopped by signal %d", WSTOPSIG(stat)); } - else - die("wait4: unknown status %x, giving up!", stat); - } + else + die("wait4: unknown status %x, giving up!", stat); } /*** The process running inside the box ***/ @@ -1437,7 +1494,7 @@ enum opt_code { OPT_CG_TIMING, }; -static const char short_opts[] = "b:c:d:eE:i:k:m:M:o:p::q:r:t:vw:x:"; +static const char short_opts[] = "b:c:d:eE:i:k:m:M:o:p::q:r:t:vw:x:s:"; static const struct option long_opts[] = { { "box-id", 1, NULL, 'b' }, @@ -1465,6 +1522,7 @@ static const struct option long_opts[] = { { "verbose", 0, NULL, 'v' }, { "version", 0, NULL, OPT_VERSION }, { "wall-time", 1, NULL, 'w' }, + { "soft-mem", 1, NULL, 's'}, { NULL, 0, NULL, 0 } }; @@ -1545,6 +1603,9 @@ main(int argc, char **argv) break; case 'x': extra_timeout = 1000*atof(optarg); + break; + case 's': + soft_memory_limit = atoi(optarg); break; case OPT_INIT: case OPT_RUN: From f03ab1e2f2fdf27be9181c670ab411fe6cca115c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20El=C3=ADas?= Date: Sun, 15 Feb 2015 18:58:19 +0000 Subject: [PATCH 2/5] Fixed some mistakes in output --- isolate.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/isolate.c b/isolate.c index a67263b..b83dfe8 100644 --- a/isolate.c +++ b/isolate.c @@ -41,6 +41,9 @@ #define MS_REC (1 << 14) #endif #define MEM_BUF_SIZE 8192 +#define MEM_INTERVAL 67 /* about 15 times a second * + * Is a good idea to use a prime number, as * + * the users will not notice it (much) */ #define NONRET __attribute__((noreturn)) #define UNUSED __attribute__((unused)) @@ -333,17 +336,17 @@ int memusage (pid_t pid) sprintf (p, "/proc/%d/status", pid); fd = open (p, O_RDONLY); if (fd < 0) - err ("Error while opening status file"); + die ("Error while opening status file"); do n = read (fd, p, MEM_BUF_SIZE); while ((n < 0) && (errno == EINTR)); if (n < 0) - err ("Error while reading status file"); + die ("Error while reading status file"); do v = close (fd); while ((v < 0) && (errno == EINTR)); if (v < 0) - err ("Error closing status file"); + die ("Error closing status file"); data = stack = 0; q = strstr (p, "VmData:"); @@ -1152,6 +1155,7 @@ box_keeper(void) pid_t p; int mem = 64; do { + usleep(MEM_INTERVAL); if(timer_tick) { check_timeout(); @@ -1160,8 +1164,7 @@ box_keeper(void) if(soft_memory_limit) { mem = max (mem, memusage (box_pid)); if(mem > soft_memory_limit) { - kill(box_pid, SIGKILL); - kill(-box_pid, SIGKILL); + err("ML: Memory limit exceeded"); } } @@ -1188,10 +1191,6 @@ box_keeper(void) die("%s", interr); } - if(mem > soft_memory_limit) { - err("MLE: Memory limit exceeded"); - } - if (WIFEXITED(stat)) { final_stats(&rus); From afac6d6692cc81fe9c652e707b97ac7cf0ba8194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20El=C3=ADas?= Date: Sun, 15 Feb 2015 23:17:54 +0000 Subject: [PATCH 3/5] checking memory at end aswell --- isolate.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/isolate.c b/isolate.c index b83dfe8..19a3efa 100644 --- a/isolate.c +++ b/isolate.c @@ -83,6 +83,7 @@ static int cleanup_ownership; static struct timeval start_time; static int ticks_per_sec; static int total_ms, wall_ms; +static int total_memory; static volatile sig_atomic_t timer_tick; static int error_pipes[2]; @@ -1126,6 +1127,19 @@ check_timeout(void) } } +static void +check_memory(void) +{ + if(soft_memory_limit) { + total_memory = max (total_memory, memusage (box_pid)); + if(verbose > 1) + fprintf(stderr, "[memory check: %d bytes", total_memory); + if(total_memory > soft_memory_limit) { + err("ML: Memory limit exceeded"); + } + } +} + static void box_keeper(void) { @@ -1153,20 +1167,13 @@ box_keeper(void) struct rusage rus; int stat; pid_t p; - int mem = 64; do { - usleep(MEM_INTERVAL); if(timer_tick) { + check_memory(); check_timeout(); timer_tick = 0; } - if(soft_memory_limit) { - mem = max (mem, memusage (box_pid)); - if(mem > soft_memory_limit) { - err("ML: Memory limit exceeded"); - } - } do p = wait4(box_pid, &stat, WNOHANG | WUNTRACED, &rus); @@ -1194,6 +1201,8 @@ box_keeper(void) if (WIFEXITED(stat)) { final_stats(&rus); + if (soft_memory_limit && rus.ru_maxrss > soft_memory_limit) + err("ML: Memory limit exceeded"); if (WEXITSTATUS(stat)) { meta_printf("exitcode:%d\n", WEXITSTATUS(stat)); From 8f2efecc62c169dfa450720de6b37af9d6296e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20El=C3=ADas?= Date: Wed, 18 Feb 2015 01:47:29 +0000 Subject: [PATCH 4/5] Using helper functions already in place to read memory --- isolate.c | 81 ++++++++++++++++++++++--------------------------------- 1 file changed, 32 insertions(+), 49 deletions(-) diff --git a/isolate.c b/isolate.c index 19a3efa..1c8eb6c 100644 --- a/isolate.c +++ b/isolate.c @@ -40,10 +40,6 @@ #ifndef MS_REC #define MS_REC (1 << 14) #endif -#define MEM_BUF_SIZE 8192 -#define MEM_INTERVAL 67 /* about 15 times a second * - * Is a good idea to use a prime number, as * - * the users will not notice it (much) */ #define NONRET __attribute__((noreturn)) #define UNUSED __attribute__((unused)) @@ -83,7 +79,7 @@ static int cleanup_ownership; static struct timeval start_time; static int ticks_per_sec; static int total_ms, wall_ms; -static int total_memory; +static long int total_memory; static volatile sig_atomic_t timer_tick; static int error_pipes[2]; @@ -322,46 +318,6 @@ chowntree(char *path, uid_t uid, gid_t gid) nftw(path, chowntree_helper, 32, FTW_MOUNT | FTW_PHYS); } -int max (int a, int b) -{ - return (a > b ? a : b); -} - -int memusage (pid_t pid) -{ - char a[MEM_BUF_SIZE], *p, *q; - int data, stack; - int n, v, fd; - - p = a; - sprintf (p, "/proc/%d/status", pid); - fd = open (p, O_RDONLY); - if (fd < 0) - die ("Error while opening status file"); - do - n = read (fd, p, MEM_BUF_SIZE); - while ((n < 0) && (errno == EINTR)); - if (n < 0) - die ("Error while reading status file"); - do - v = close (fd); - while ((v < 0) && (errno == EINTR)); - if (v < 0) - die ("Error closing status file"); - - data = stack = 0; - q = strstr (p, "VmData:"); - if (q != NULL) - { - sscanf (q, "%*s %d", &data); - q = strstr (q, "VmStk:"); - if (q != NULL) - sscanf (q, "%*s %d\n", &stack); - } - - return (data + stack); -} - /*** Environment rules ***/ struct env_rule { @@ -1042,6 +998,7 @@ signal_int(int unused UNUSED) } #define PROC_BUF_SIZE 4096 + static void read_proc_file(char *buf, char *name, int *fdp) { @@ -1062,6 +1019,28 @@ read_proc_file(char *buf, char *name, int *fdp) buf[c] = 0; } +long int memusage (pid_t pid) +{ + char buf[PROC_BUF_SIZE], *p, *q; + long int data, stack; + static int fd; + p = buf; + + read_proc_file(p, "status", &fd); + + data = stack = 0; + q = strstr (p, "VmData:"); + if (q != NULL) + { + sscanf (q, "%*s %ld", &data); + q = strstr (q, "VmStk:"); + if (q != NULL) + sscanf (q, "%*s %ld\n", &stack); + } + + return (data + stack); +} + static int get_wall_time_ms(void) { @@ -1131,12 +1110,15 @@ static void check_memory(void) { if(soft_memory_limit) { - total_memory = max (total_memory, memusage (box_pid)); + long int m = memusage(box_pid); + if(m > total_memory){ + total_memory = m; if(verbose > 1) - fprintf(stderr, "[memory check: %d bytes", total_memory); + fprintf(stderr, "[memory check: %ld bytes]\n", total_memory); if(total_memory > soft_memory_limit) { err("ML: Memory limit exceeded"); } + } } } @@ -1170,11 +1152,11 @@ box_keeper(void) do { if(timer_tick) { - check_memory(); check_timeout(); timer_tick = 0; } - + usleep(10); + check_memory(); do p = wait4(box_pid, &stat, WNOHANG | WUNTRACED, &rus); while ((p < 0 && (errno != EINTR))); @@ -1201,6 +1183,7 @@ box_keeper(void) if (WIFEXITED(stat)) { final_stats(&rus); + // fprintf(stderr, "%d: %ld > %d\n", soft_memory_limit, rus.ru_maxrss, soft_memory_limit); if (soft_memory_limit && rus.ru_maxrss > soft_memory_limit) err("ML: Memory limit exceeded"); if (WEXITSTATUS(stat)) From 6c187f4b40fafd4b44d27698b67e71191bf2017e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?James=20El=C3=ADas?= Date: Wed, 18 Feb 2015 02:29:02 +0000 Subject: [PATCH 5/5] using statm instead of status for efficiency, switched to polling every 67ms --- isolate.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/isolate.c b/isolate.c index 1c8eb6c..022bc4c 100644 --- a/isolate.c +++ b/isolate.c @@ -78,8 +78,9 @@ static int cleanup_ownership; static struct timeval start_time; static int ticks_per_sec; +static long int page_size_kb; static int total_ms, wall_ms; -static long int total_memory; +static unsigned long total_memory; static volatile sig_atomic_t timer_tick; static int error_pipes[2]; @@ -1019,26 +1020,15 @@ read_proc_file(char *buf, char *name, int *fdp) buf[c] = 0; } -long int memusage (pid_t pid) +unsigned long memusage (pid_t pid) { - char buf[PROC_BUF_SIZE], *p, *q; - long int data, stack; + char buf[PROC_BUF_SIZE]; + unsigned long data = 0; static int fd; - p = buf; - - read_proc_file(p, "status", &fd); - - data = stack = 0; - q = strstr (p, "VmData:"); - if (q != NULL) - { - sscanf (q, "%*s %ld", &data); - q = strstr (q, "VmStk:"); - if (q != NULL) - sscanf (q, "%*s %ld\n", &stack); - } - - return (data + stack); + read_proc_file(buf, "statm", &fd); + if(sscanf(buf, "%*u %*u %*u %*u %*u %lu", &data) != 1) + die("proc statm syntax error 2"); + return data * page_size_kb; } static int @@ -1110,11 +1100,11 @@ static void check_memory(void) { if(soft_memory_limit) { - long int m = memusage(box_pid); + unsigned long m = memusage(box_pid); if(m > total_memory){ total_memory = m; if(verbose > 1) - fprintf(stderr, "[memory check: %ld bytes]\n", total_memory); + fprintf(stderr, "[memory check: %lu kB]\n", total_memory); if(total_memory > soft_memory_limit) { err("ML: Memory limit exceeded"); } @@ -1122,6 +1112,7 @@ check_memory(void) } } +#define INTERVAL 67 // The polling interval (roughly 13 times/sec) static void box_keeper(void) { @@ -1137,6 +1128,9 @@ box_keeper(void) ticks_per_sec = sysconf(_SC_CLK_TCK); if (ticks_per_sec <= 0) die("Invalid ticks_per_sec!"); + page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; + if (page_size_kb <= 0) + die("Invalid page_size_kb!"); if (timeout || wall_timeout) { @@ -1155,7 +1149,7 @@ box_keeper(void) check_timeout(); timer_tick = 0; } - usleep(10); + usleep(INTERVAL); check_memory(); do p = wait4(box_pid, &stat, WNOHANG | WUNTRACED, &rus); @@ -1183,9 +1177,6 @@ box_keeper(void) if (WIFEXITED(stat)) { final_stats(&rus); - // fprintf(stderr, "%d: %ld > %d\n", soft_memory_limit, rus.ru_maxrss, soft_memory_limit); - if (soft_memory_limit && rus.ru_maxrss > soft_memory_limit) - err("ML: Memory limit exceeded"); if (WEXITSTATUS(stat)) { meta_printf("exitcode:%d\n", WEXITSTATUS(stat));