On Sun, 10 Feb 2002, Mike Silbersack wrote:

> On Mon, 11 Feb 2002, Gaspar Chilingarov wrote:
>
> > Hi there!
> >
> > I've implemented suggested limits, and if you are interested, you can
> > try attached patch, if it's OK, i will submit it to PR database.
>
> I finished looking at the patch, and I'm not impressed by it.  It looks
> like the patch I'm working on will work more effectively; I'll post or
> commit it in a few days.
>
> Mike "Silby" Silbersack

For those interested, here's the forkbomb countermeasure patch I've
devised.  It does three things:

1.  Change the number of procs reserved for root from 1 to 10.  Given how
maxprocperuid is set in 4.5, this shouldn't matter much, but it's a safe
change.

2.  Limit the number of procs to an appropriate number.  Previously, it
was easy to set maxproc overly high by setting a large maxusers value.
With this change, proc-related structures will only be able to consume
about 1/2 of all system memory.  Without this limitation, a high maxusers
setting and a forkbomb could easily consume all system memory, leaving
virtually no chance for the system to recover.

3.  Penalize processes / users that hit their maxproc limit.  Whenever a
process tries to fork and that user's proc limit is hit, a tsleep of .5
seconds will occur.  This change causes 1000 madly fork()ing processes
into 1000 nicely sleeping processes if they continue to attempt to fork().

The testing I've done with this patch has proven it to be quite effective
in protecting a system against a simple forkbomb, even if maxusers is set
to inordinantly high values.  Sysadmins who have already imposed low
limits on their users will still be helped by change #3, as it ensures
that less processor time will be wasted by continuous fork()ing.

There are certainly a few remaining issues with more complex resource
exhaustion attacks, but that can be dealt with in future patches.

If you were interested in the fork rate limit thread, please give this
patch a try to see if it helps in the forkbomb-like situations you've
seen.

Stable users:  This won't compile as is for you.  Change

+               tsleep(&forksleep, td->td_kse->ke_priority, "fork", hz / 2);

to

+               tsleep(&forksleep, PUSER, "fork", hz / 2);

Thanks,

Mike "Silby" Silbersack
diff -u -r /usr/src/sys.old/kern/kern_fork.c /usr/src/sys/kern/kern_fork.c
--- /usr/src/sys.old/kern/kern_fork.c   Tue Feb 12 00:24:13 2002
+++ /usr/src/sys/kern/kern_fork.c       Tue Feb 12 00:26:02 2002
@@ -93,6 +93,8 @@
 };
 #endif
 
+int forksleep; /* Place for fork1() to sleep on. */
+
 static void
 init_fork_list(void *data __unused)
 {
@@ -297,8 +299,8 @@
         * processes, maxproc is the limit.
         */
        uid = p1->p_ucred->cr_ruid;
-       if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) {
-               tablefull("proc");
+       if ((nprocs >= maxproc - 10 && uid != 0) || nprocs >= maxproc) {
+               tsleep(&forksleep, td->td_kse->ke_priority, "fork", hz / 2);
                return (EAGAIN);
        }
        /*
@@ -318,6 +320,7 @@
                 * Back out the process count
                 */
                nprocs--;
+               tsleep(&forksleep, td->td_kse->ke_priority, "fork", hz / 2);
                return (EAGAIN);
        }
 
Only in /usr/src/sys/kern/: kern_fork.c.orig
diff -u -r /usr/src/sys.old/kern/subr_param.c /usr/src/sys/kern/subr_param.c
--- /usr/src/sys.old/kern/subr_param.c  Tue Feb 12 00:24:16 2002
+++ /usr/src/sys/kern/subr_param.c      Tue Feb 12 00:35:40 2002
@@ -131,6 +131,7 @@
 void
 init_param2(int physpages)
 {
+       int automaxproc;
 
        /* Base parameters */
        maxusers = MAXUSERS;
@@ -144,11 +145,25 @@
        }
 
        /*
+        * In order to make sure that the system cannot be taken
+        * down by too many processes, we limit the number of
+        * processes so that process-related structures can
+        * only occupy at most 50% of system memory.
+        *
+        * XXX - The 32K value was arrived at experimentally,
+        * and may require changing if pre-proc memory usage
+        * changes substantially.
+        */
+       automaxproc = (physpages / 2) / (32768 / PAGE_SIZE);
+
+       /*
         * The following can be overridden after boot via sysctl.  Note:
         * unless overriden, these macros are ultimately based on maxusers.
         */
        maxproc = NPROC;
        TUNABLE_INT_FETCH("kern.maxproc", &maxproc);
+       if (maxproc > automaxproc)
+               maxproc = automaxproc;
        maxfiles = MAXFILES;
        TUNABLE_INT_FETCH("kern.maxfiles", &maxfiles);
        maxprocperuid = (maxproc * 9) / 10;
Only in /usr/src/sys/kern/: subr_param.c.orig

Reply via email to