From: Timo Kokkonen Date: Sun, 28 Oct 2012 16:12:08 +0000 (+0200) Subject: jobcontrol: Fork bomb prevental X-Git-Url: http://git.itanic.dy.fi/?p=rrdd;a=commitdiff_plain;h=d5f03d9c3a441beee543e1aceaf4bf3d3bccc994 jobcontrol: Fork bomb prevental If something happens that prevents existing jobs from terminating, it is generally bad practice to keep on forking more processes indefinitely. To alleviate the problem, implement a somewhat trivial process limitation feature. This will define a limit of maximum number for the processes pending execution. If the number exceeds the global limit, new processes are to be terminate itself immediately. This however prevents only "limited forks" for creating too many processes for waiting execution. Normal forks still have no limit. This should still make the system to stay alive longer during situations where something prevents (temporarily) executing processes to finish in time. Signed-off-by: Timo Kokkonen --- diff --git a/process.c b/process.c index 070b5f0..27e9400 100644 --- a/process.c +++ b/process.c @@ -19,6 +19,7 @@ static int epoll_fd; static unsigned int max_jobs; static unsigned int job_count; static unsigned int jobs_pending; +static unsigned int max_jobs_pending; int get_child_count(void) { @@ -70,6 +71,24 @@ static int grant_new_job(void) return 0; } +static int deny_job(void) +{ + int ret; + char byte = -1; + + pr_info("Denying new job. %d jobs currently and %d pending, " + "limit of pending jobs is %d\n", + job_count, jobs_pending, max_jobs_pending); + + ret = write(job_get_permission_fd[1], &byte, 1); + if (ret != 1) { + pr_err("Failed to write 1 byte: %m\n"); + return -1; + } + + return 0; +} + static int handle_job_request(struct event_handler *h) { int ret, pid; @@ -87,7 +106,10 @@ static int handle_job_request(struct event_handler *h) if (pid > 0) { if (job_count >= max_jobs) { - jobs_pending++; + if (jobs_pending < max_jobs_pending) + jobs_pending++; + else + deny_job(); } else { ret = grant_new_job(); return 0; @@ -208,6 +230,9 @@ read_fail: no_count_cpus: pr_info("Set maximum number of parallel jobs to %d\n", max_jobs); + max_jobs_pending = max_jobs * 50 + 25; + pr_info("Set maximum number of pending jobs to %d\n", max_jobs_pending); + return 0; } @@ -370,6 +395,17 @@ int do_fork_limited(void) if (ret < 0) pr_err("Job control request failure: %m\n"); + if (byte < 0) { + pr_info("Did not get permission to execute. Terminating\n"); + + /* + * Avoid running exit handler, that would tell the + * parent we died normally and decrement the job + * counters. + */ + raise(SIGKILL); + } + pr_info("Continuing\n"); return child; }