Skip to content

Commit ea8f0c7

Browse files
ubergeek42eldering
authored andcommitted
Use cgroups to provide memory limits in runguard
1 parent 5def362 commit ea8f0c7

File tree

4 files changed

+150
-2
lines changed

4 files changed

+150
-2
lines changed

configure.ac

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ AC_PROG_MKDIR_P
225225
# check for htpasswd/htpasswd2
226226
AC_CHECK_PROGS(HTPASSWD,[htpasswd htpasswd2],[no htpasswd binary found])
227227

228+
# Check for including optional libcgroup
229+
AC_CHECK_LIB(cgroup, cgroup_init, AC_SUBST(LIBCGROUP,[-lcgroup]))
230+
228231
# Check for including optional libmagic.
229232
AC_CHECK_LIB(magic,magic_open,AC_SUBST(LIBMAGIC,[-lmagic]))
230233

@@ -275,7 +278,7 @@ AC_DEFINE_UNQUOTED(_XOPEN_SOURCE, 500, [Include SUSv2 (UNIX 98) extensions
275278

276279
# Checks for header files.
277280
AC_HEADER_STDBOOL
278-
AC_CHECK_HEADERS([fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h magic.h])
281+
AC_CHECK_HEADERS([fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h termios.h unistd.h magic.h libcgroup.h])
279282

280283
# Checks for typedefs, structures, and compiler characteristics.
281284
AC_C_INLINE

judge/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ compare$(OBJEXT): $(LIBHEADERS)
2121
check_float: -lm $(LIBOBJECTS)
2222
check_float$(OBJEXT): -lm $(LIBHEADERS)
2323

24-
runguard: -lm
24+
runguard: -lm $(LIBCGROUP)
2525
runguard$(OBJEXT): $(TOPDIR)/etc/runguard-config.h
2626

2727
# FIXME: compile with diet libc to produce a static binary which is

judge/runguard.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
#include <time.h>
6565
#include <math.h>
6666
#include <limits.h>
67+
#ifdef HAVE_LIBCGROUP_H
68+
#include <inttypes.h>
69+
#include <libcgroup.h>
70+
#endif
6771

6872
/* Some system/site specific config: VALID_USERS, CHROOT_PREFIX */
6973
#include "runguard-config.h"
@@ -99,6 +103,9 @@ char *stdoutfilename;
99103
char *stderrfilename;
100104
char *exitfilename;
101105
char *timefilename;
106+
#ifdef HAVE_LIBCGROUP_H
107+
char *cgroupname;
108+
#endif
102109

103110
int runuid;
104111
int rungid;
@@ -119,7 +126,11 @@ int show_help;
119126
int show_version;
120127

121128
double runtime, cputime; /* in seconds */
129+
#ifdef HAVE_LIBCGROUP_H
130+
int64_t memsize;
131+
#else
122132
rlim_t memsize;
133+
#endif
123134
rlim_t filesize;
124135
rlim_t nproc;
125136
size_t streamsize;
@@ -305,6 +316,31 @@ void output_exit_time(int exitcode, double timediff)
305316
}
306317
}
307318
}
319+
#ifdef HAVE_LIBCGROUP_H
320+
void output_cgroup_stats() {
321+
int ret;
322+
int64_t max_usage;
323+
struct cgroup *cg;
324+
struct cgroup_controller *cg_controller;
325+
326+
cg = cgroup_new_cgroup(cgroupname);
327+
if (!cg) {
328+
error(0,"cgroup_new_cgroup");
329+
}
330+
if ((ret = cgroup_get_cgroup(cg)) != 0) {
331+
error(0,"get cgroup information - %s(%d)", cgroup_strerror(ret), ret);
332+
}
333+
cg_controller = cgroup_get_controller(cg, "memory");
334+
ret = cgroup_get_value_int64(cg_controller, "memory.memsw.max_usage_in_bytes", &max_usage);
335+
if ( ret!=0 ) {
336+
error(0,"get cgroup value - %s(%d)", cgroup_strerror(ret), ret);
337+
}
338+
339+
fprintf(stderr, "Total memory used: %" PRId64 " kb\n", max_usage/1024);
340+
341+
cgroup_free(&cg);
342+
}
343+
#endif
308344

309345
void terminate(int sig)
310346
{
@@ -411,13 +447,22 @@ void setrestrictions()
411447
setlim(CPU);
412448
}
413449

450+
/* Memory limits may be handled by cgroups now */
451+
#ifndef HAVE_LIBCGROUP_H
414452
if ( memsize!=RLIM_INFINITY ) {
415453
verbose("setting memory limits to %d bytes",(int)memsize);
416454
lim.rlim_cur = lim.rlim_max = memsize;
417455
setlim(AS);
418456
setlim(DATA);
419457
setlim(STACK);
420458
}
459+
#else
460+
/* Memory limits should be unlimited when using cgroups */
461+
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
462+
setlim(AS);
463+
setlim(DATA);
464+
setlim(STACK);
465+
#endif
421466

422467
if ( filesize!=RLIM_INFINITY ) {
423468
verbose("setting filesize limit to %d bytes",(int)filesize);
@@ -488,12 +533,82 @@ void setrestrictions()
488533
if ( geteuid()==0 || getuid()==0 ) error(0,"root privileges not dropped. Do not run judgedaemon as root.");
489534
}
490535

536+
#ifdef HAVE_LIBCGROUP_H
537+
void cgroup_create() {
538+
int ret;
539+
struct cgroup *cg;
540+
struct cgroup_controller *cg_controller;
541+
542+
cg = cgroup_new_cgroup(cgroupname);
543+
if (!cg) {
544+
error(0,"cgroup_new_cgroup");
545+
}
546+
547+
/* Set up the memory restrictions; these two options limit ram use
548+
and ram+swap use. They are the same so no swapping can occur */
549+
cg_controller = cgroup_add_controller(cg, "memory");
550+
cgroup_add_value_int64(cg_controller, "memory.limit_in_bytes", memsize);
551+
cgroup_add_value_int64(cg_controller, "memory.memsw.limit_in_bytes", memsize);
552+
553+
/* Perform the actual creation of the cgroup */
554+
ret = cgroup_create_cgroup(cg, 1);
555+
if ( ret!=0) {
556+
error(0,"creating cgroup - %s(%d)", cgroup_strerror(ret), ret);
557+
}
558+
559+
cgroup_free(&cg);
560+
}
561+
void cgroup_attach() {
562+
int ret;
563+
struct cgroup *cg;
564+
565+
cg = cgroup_new_cgroup(cgroupname);
566+
if (!cg) {
567+
error(0,"cgroup_new_cgroup");
568+
}
569+
ret = cgroup_get_cgroup(cg);
570+
if ( ret!=0 ) {
571+
error(0,"get cgroup information - %s(%d)", cgroup_strerror(ret), ret);
572+
}
573+
574+
/* Attach task to the cgroup */
575+
ret = cgroup_attach_task(cg);
576+
if ( ret!=0 ) {
577+
error(0,"attach task to cgroup - %s(%d)", cgroup_strerror(ret), ret);
578+
}
579+
580+
cgroup_free(&cg);
581+
}
582+
void cgroup_delete() {
583+
int ret;
584+
struct cgroup *cg;
585+
586+
cg = cgroup_new_cgroup(cgroupname);
587+
if (!cg) {
588+
error(0,"cgroup_new_cgroup");
589+
}
590+
ret = cgroup_get_cgroup(cg);
591+
if ( ret!=0 ) {
592+
error(0,"get cgroup information - %s(%d)", cgroup_strerror(ret), ret);
593+
}
594+
/* Clean up our cgroup */
595+
ret = cgroup_delete_cgroup(cg, 1);
596+
if ( ret!=0 ) {
597+
error(0,"deleting cgroup - %s(%d)", cgroup_strerror(ret), ret);
598+
}
599+
cgroup_free(&cg);
600+
}
601+
#endif
602+
491603
int main(int argc, char **argv)
492604
{
493605
sigset_t sigmask, emptymask;
494606
fd_set readfds;
495607
pid_t pid;
496608
int i, r, nfds;
609+
#ifdef HAVE_LIBCGROUP_H
610+
int ret;
611+
#endif
497612
int status;
498613
int exitcode;
499614
char *valid_users;
@@ -657,6 +772,23 @@ int main(int argc, char **argv)
657772
error(errno,"installing signal handler");
658773
}
659774

775+
#ifdef HAVE_LIBCGROUP_H
776+
/* Make libcgroup ready for use */
777+
ret = cgroup_init();
778+
if ( ret!=0 ) {
779+
error(0,"libcgroup initialization failed: %s(%d)\n", cgroup_strerror(ret), ret);
780+
}
781+
/* Define the cgroup name that we will use */
782+
cgroupname = (char*)malloc(256);
783+
if ( cgroupname==NULL ) {
784+
error(errno,"allocating memory for cgroupname");
785+
}
786+
/* Note: group names must have slashes! */
787+
snprintf(cgroupname, 256, "/domjudge/dj_cgroup_%d/", getpid());
788+
789+
cgroup_create();
790+
#endif
791+
660792
switch ( child_pid = fork() ) {
661793
case -1: /* error */
662794
error(errno,"cannot fork");
@@ -676,6 +808,11 @@ int main(int argc, char **argv)
676808
and all its children can be killed off with one signal. */
677809
if ( setsid()==-1 ) error(errno,"setsid failed");
678810

811+
#ifdef HAVE_LIBCGROUP_H
812+
/* Put the child process in the cgroup */
813+
cgroup_attach();
814+
#endif
815+
679816
/* Apply all restrictions for child process. */
680817
setrestrictions();
681818

@@ -831,6 +968,11 @@ int main(int argc, char **argv)
831968
exitcode = WEXITSTATUS(status);
832969
}
833970

971+
#ifdef HAVE_LIBCGROUP_H
972+
output_cgroup_stats();
973+
cgroup_delete();
974+
#endif
975+
834976
/* Drop root before writing to output file(s). */
835977
if ( setuid(getuid())!=0 ) error(errno,"dropping root privileges");
836978

paths.mk.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ SUBMIT_DEFAULT = @SUBMIT_DEFAULT@
4343
SUBMIT_ENABLE_CMD = @SUBMIT_ENABLE_CMD@
4444
SUBMIT_ENABLE_WEB = @SUBMIT_ENABLE_WEB@
4545

46+
# libcgroup
47+
LIBCGROUP = @LIBCGROUP@
48+
4649
# libmagic
4750
LIBMAGIC = @LIBMAGIC@
4851

0 commit comments

Comments
 (0)