From f65f3204e6b3b65444ca648c4bcff5c7bf9fa1f5 Mon Sep 17 00:00:00 2001 From: Tobias Werth Date: Tue, 27 Aug 2024 21:09:09 +0200 Subject: [PATCH] fix --- judge/runguard.cc | 243 +++++++++++++++++++++++----------------------- 1 file changed, 119 insertions(+), 124 deletions(-) diff --git a/judge/runguard.cc b/judge/runguard.cc index 69090024093..b29a329ee58 100644 --- a/judge/runguard.cc +++ b/judge/runguard.cc @@ -308,15 +308,12 @@ void write_meta(const char *key, const char *format, ...) va_start(ap,format); if ( fprintf(metafile,"%s: ",key)<=0 ) { - outputmeta = 0; error(0,"cannot write to file `%s'",metafilename); } if ( vfprintf(metafile,format,ap)<0 ) { - outputmeta = 0; error(0,"cannot write to file `%s'(vfprintf)",metafilename); } if ( fprintf(metafile,"\n")<=0 ) { - outputmeta = 0; error(0,"cannot write to file `%s'",metafilename); } @@ -439,11 +436,11 @@ void output_exit_time(int exitcode, double cpudiff) void check_remaining_procs() { char path[1024]; - if (is_cgroup_v2) { - snprintf(path, 1023, "/sys/fs/cgroup/%scgroup.procs", cgroupname); - } else { - snprintf(path, 1023, "/sys/fs/cgroup/cpuacct%scgroup.procs", cgroupname); - } + if (is_cgroup_v2) { + snprintf(path, 1023, "/sys/fs/cgroup/%scgroup.procs", cgroupname); + } else { + snprintf(path, 1023, "/sys/fs/cgroup/cpuacct%scgroup.procs", cgroupname); + } FILE *file = fopen(path, "r"); if (file == nullptr) { @@ -486,40 +483,40 @@ void output_cgroup_stats_v1(double *cputime) void output_cgroup_stats_v2(double *cputime) { - struct cgroup *cg; - if ( (cg = cgroup_new_cgroup(cgroupname))==NULL ) error(0,"cgroup_new_cgroup"); - - int ret; - if ((ret = cgroup_get_cgroup(cg)) != 0) error(ret,"get cgroup information"); - - struct cgroup_controller *cg_controller = cgroup_get_controller(cg, "memory"); - int64_t max_usage = 0; - ret = cgroup_get_value_int64(cg_controller, "memory.peak", &max_usage); - if ( ret == ECGROUPVALUENOTEXIST ) { - write_meta("internal-warning", "Kernel too old and does not support memory.peak"); - } else if ( ret!=0 ) { - error(ret,"get cgroup value memory.peak"); - } - - // There is no need to check swap usage, as we limit it to 0. - verbose("total memory used: %" PRId64 " kB", max_usage/1024); - write_meta("memory-bytes","%" PRId64, max_usage); - - struct cgroup_stat stat; - void *handle; - ret = cgroup_read_stats_begin("cpu", cgroupname, &handle, &stat); - while (ret == 0) { - verbose("cpu.stat: %s = %s", stat.name, stat.value); - if (strcmp(stat.name, "usage_usec") == 0) { - long long usec = strtoll(stat.value, NULL, 10); - *cputime = usec / 1e6; - } - ret = cgroup_read_stats_next(&handle, &stat); - } - if ( ret!=ECGEOF ) error(ret,"get cgroup value cpu.stat"); - cgroup_read_stats_end(&handle); - - cgroup_free(&cg); + struct cgroup *cg; + if ( (cg = cgroup_new_cgroup(cgroupname))==NULL ) error(0,"cgroup_new_cgroup"); + + int ret; + if ((ret = cgroup_get_cgroup(cg)) != 0) error(ret,"get cgroup information"); + + struct cgroup_controller *cg_controller = cgroup_get_controller(cg, "memory"); + int64_t max_usage = 0; + ret = cgroup_get_value_int64(cg_controller, "memory.peak", &max_usage); + if ( ret == ECGROUPVALUENOTEXIST ) { + write_meta("internal-warning", "Kernel too old and does not support memory.peak"); + } else if ( ret!=0 ) { + error(ret,"get cgroup value memory.peak"); + } + + // There is no need to check swap usage, as we limit it to 0. + verbose("total memory used: %" PRId64 " kB", max_usage/1024); + write_meta("memory-bytes","%" PRId64, max_usage); + + struct cgroup_stat stat; + void *handle; + ret = cgroup_read_stats_begin("cpu", cgroupname, &handle, &stat); + while (ret == 0) { + verbose("cpu.stat: %s = %s", stat.name, stat.value); + if (strcmp(stat.name, "usage_usec") == 0) { + long long usec = strtoll(stat.value, NULL, 10); + *cputime = usec / 1e6; + } + ret = cgroup_read_stats_next(&handle, &stat); + } + if ( ret!=ECGEOF ) error(ret,"get cgroup value cpu.stat"); + cgroup_read_stats_end(&handle); + + cgroup_free(&cg); } @@ -541,21 +538,21 @@ void cgroup_create() error(0,"cgroup_add_controller memory"); } - int ret; - if (is_cgroup_v2) { - // TODO: do we want to set cpu.weight here as well? - if (memsize != RLIM_INFINITY) { - cgroup_add_value(int64, "memory.max", memsize); - // TODO: Is this the behavior change that JohnB mentioned? - cgroup_add_value(int64, "memory.swap.max", 0); - } else { - cgroup_add_value(string, "memory.max", "max"); - cgroup_add_value(string, "memory.swap.max", "max"); - } - } else { - cgroup_add_value(int64, "memory.limit_in_bytes", memsize); - cgroup_add_value(int64, "memory.memsw.limit_in_bytes", memsize); - } + int ret; + if (is_cgroup_v2) { + // TODO: do we want to set cpu.weight here as well? + if (memsize != RLIM_INFINITY) { + cgroup_add_value(int64, "memory.max", memsize); + // TODO: Is this the behavior change that JohnB mentioned? + cgroup_add_value(int64, "memory.swap.max", 0); + } else { + cgroup_add_value(string, "memory.max", "max"); + cgroup_add_value(string, "memory.swap.max", "max"); + } + } else { + cgroup_add_value(int64, "memory.limit_in_bytes", memsize); + cgroup_add_value(int64, "memory.memsw.limit_in_bytes", memsize); + } /* Set up cpu restrictions; we pin the task to a specific set of cpus. We also give it exclusive access to those cores, and set @@ -608,28 +605,28 @@ void cgroup_attach() void cgroup_kill() { - /* kill any remaining tasks, and wait for them to be gone */ - if (is_cgroup_v2) { - int size; - do { - pid_t* pids; - int ret = cgroup_get_procs(cgroupname, "memory", &pids, &size); - if (ret != 0) error(ret, "cgroup_get_procs"); - for(int i = 0; i < size; i++) { - kill(pids[i], SIGKILL); - } - free(pids); - } while (size > 0); - } else { - while(1) { - void *handle = nullptr; - pid_t pid; - int ret = cgroup_get_task_begin(cgroupname, "memory", &handle, &pid); - cgroup_get_task_end(&handle); - if (ret == ECGEOF) break; - kill(pid, SIGKILL); - } - } + /* kill any remaining tasks, and wait for them to be gone */ + if (is_cgroup_v2) { + int size; + do { + pid_t* pids; + int ret = cgroup_get_procs(cgroupname, "memory", &pids, &size); + if (ret != 0) error(ret, "cgroup_get_procs"); + for(int i = 0; i < size; i++) { + kill(pids[i], SIGKILL); + } + free(pids); + } while (size > 0); + } else { + while(1) { + void *handle = nullptr; + pid_t pid; + int ret = cgroup_get_task_begin(cgroupname, "memory", &handle, &pid); + cgroup_get_task_end(&handle); + if (ret == ECGEOF) break; + kill(pid, SIGKILL); + } + } } void cgroup_delete() @@ -638,10 +635,10 @@ void cgroup_delete() cg = cgroup_new_cgroup(cgroupname); if (!cg) error(0,"cgroup_new_cgroup"); - if (cgroup_add_controller(cg, "cpu") == nullptr) error(0, "cgroup_add_controller cpu"); - if (!is_cgroup_v2) { - if (cgroup_add_controller(cg, "cpuacct") == nullptr) error(0, "cgroup_add_controller cpuacct"); - } + if (cgroup_add_controller(cg, "cpu") == nullptr) error(0, "cgroup_add_controller cpu"); + if (!is_cgroup_v2) { + if (cgroup_add_controller(cg, "cpuacct") == nullptr) error(0, "cgroup_add_controller cpuacct"); + } if ( cgroup_add_controller(cg, "memory")==nullptr ) error(0,"cgroup_add_controller memory"); if ( cpuset!=nullptr && strlen(cpuset)>0 ) { @@ -649,8 +646,8 @@ void cgroup_delete() } /* Clean up our cgroup */ nanosleep(&cg_delete_delay,nullptr); - int ret = cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION | CGFLAG_DELETE_RECURSIVE); - // TODO: is this actually benign? + int ret = cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_IGNORE_MIGRATION | CGFLAG_DELETE_RECURSIVE); + // TODO: is this actually benign to ignore ECGOTHER here? if ( ret!=0 && ret!=ECGOTHER ) error(ret,"deleting cgroup"); cgroup_free(&cg); @@ -865,14 +862,14 @@ void setrestrictions() } /* Put the child process in the cgroup */ - if (is_cgroup_v2) { - const char *controllers[] = { "memory", NULL }; - if (cgroup_change_cgroup_path(cgroupname, getpid(), controllers) != 0) { - error(0, "Failed to move the process to the cgroup"); - } - } else { - cgroup_attach(); - } + if (is_cgroup_v2) { + const char *controllers[] = { "memory", NULL }; + if (cgroup_change_cgroup_path(cgroupname, getpid(), controllers) != 0) { + error(0, "Failed to move the process to the cgroup"); + } + } else { + cgroup_attach(); + } /* Run the command in a separate process group so that the command and all its children can be killed off with one signal. */ @@ -1019,26 +1016,26 @@ void pump_pipes(fd_set* readfds, size_t data_read[], size_t data_passed[]) } bool cgroup_is_v2() { - bool ret = false; - FILE *fp = setmntent("/proc/mounts", "r"); - if (!fp) { - perror("Error opening /proc/mounts"); - return false; - } - - struct mntent *entry; - while ((entry = getmntent(fp)) != nullptr) { - if (strcmp(entry->mnt_dir, "/sys/fs/cgroup") == 0) { - if (strcmp(entry->mnt_type, "cgroup2") == 0) { - ret = true; - } - break; - } - } - - endmntent(fp); - - return ret; + bool ret = false; + FILE *fp = setmntent("/proc/mounts", "r"); + if (!fp) { + perror("Error opening /proc/mounts"); + return false; + } + + struct mntent *entry; + while ((entry = getmntent(fp)) != nullptr) { + if (strcmp(entry->mnt_dir, "/sys/fs/cgroup") == 0) { + if (strcmp(entry->mnt_type, "cgroup2") == 0) { + ret = true; + } + break; + } + } + + endmntent(fp); + + return ret; } int main(int argc, char **argv) @@ -1215,7 +1212,7 @@ int main(int argc, char **argv) cmdname = argv[optind]; cmdargs = argv+optind; - is_cgroup_v2 = cgroup_is_v2(); + is_cgroup_v2 = cgroup_is_v2(); if ( outputmeta && (metafile = fopen(metafilename,"w"))==nullptr ) { error(errno,"cannot open `%s'",metafilename); @@ -1277,8 +1274,6 @@ int main(int argc, char **argv) } } -// cgroup_set_default_logger(CGROUP_LOG_DEBUG); - /* Make libcgroup ready for use */ ret = cgroup_init(); if ( ret!=0 ) { @@ -1292,8 +1287,8 @@ int main(int argc, char **argv) } else { str[0] = 0; } - snprintf(cgroupname, 255, "domjudge/dj_cgroup_%d_%.16s_%d.%06d/", - getpid(), str, (int) progstarttime.tv_sec, (int) progstarttime.tv_usec); + snprintf(cgroupname, 255, "domjudge/dj_cgroup_%d_%.16s_%d.%06d/", + getpid(), str, (int) progstarttime.tv_sec, (int) progstarttime.tv_usec); cgroup_create(); @@ -1358,7 +1353,7 @@ int main(int argc, char **argv) error(errno,"cannot start `%s', limit: %ld/%ld | ",cmdname, limit.rlim_cur, limit.rlim_max); default: /* become watchdog */ - verbose("child pid = %d", child_pid); + verbose("child pid = %d", child_pid); /* Shed privileges, only if not using a separate child uid, because in that case we may need root privileges to kill the child process. Do not use Linux specific setresuid() @@ -1542,11 +1537,11 @@ int main(int argc, char **argv) check_remaining_procs(); double cputime = -1; - if (is_cgroup_v2) { - output_cgroup_stats_v2(&cputime); - } else { - output_cgroup_stats_v1(&cputime); - } + if (is_cgroup_v2) { + output_cgroup_stats_v2(&cputime); + } else { + output_cgroup_stats_v1(&cputime); + } cgroup_kill(); cgroup_delete();