Hi
I made some tests and almost all Linux distros brings down while freebsd survive!Forkbombing is a big problem but i don't think that something like
max_threads = mempages / (16 * THREAD_SIZE / PAGE_SIZE);
is good solution!!!
How about add max_user_threads to the kernel? It could be tunable via proc filesystem. Limit is set only for users.
I made a fast:) patch - see below - and test it on 2.6.11, 2.6.11ac4,2.6.12rc1...works great!!!New forks are stoped in copy_process() before dup_task_struct() and EAGAIN is returned. System works without any problems and root can killall -9 forkbomb.
Regards, Jacek Luczak
--- linux-2.6.12-rc1/kernel/fork.c 2005-03-29 00:53:37.000000000 +0200 +++ linux/kernel/fork.c 2005-03-29 00:54:19.000000000 +0200 @@ -57,6 +57,8 @@ int max_threads; /* tunable limit on nr_threads */ +int max_user_threads; /* tunable limit on nr_threads per user */ + DEFINE_PER_CPU(unsigned long, process_counts) = 0; __cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */ @@ -146,6 +148,21 @@ if(max_threads < 20) max_threads = 20; + /* + * The default maximum number of threads per user. + * + * FIXME: this value is based on my experiments and is + * rather good on desktop system; it should be fixed to + * the more universal value. + */ + max_user_threads = 300; + + /* + * default value is too high - set to max_threads + */ + if (max_threads < max_user_threads) + max_user_threads = max_threads; + init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; init_task.signal->rlim[RLIMIT_SIGPENDING] = @@ -179,6 +196,16 @@ return tsk; } +/* + * This is used to get number of user processes + * from current running task. + */ +static inline int get_user_processes(void) +{ + return atomic_read(¤t->user->processes); +} +#define user_nr_processes get_user_processes() + #ifdef CONFIG_MMU static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) { @@ -869,6 +896,13 @@ goto fork_out; retval = -ENOMEM; + + /* + * Stop creation of new user process if limit is reached. + */ + if ( (current->user != &root_user) && (user_nr_processes >= max_user_threads) ) + goto max_user_fork; + p = dup_task_struct(current); if (!p) goto fork_out; @@ -1109,6 +1143,9 @@ return ERR_PTR(retval); return p; +max_user_fork: + retval = -EAGAIN; + return ERR_PTR(retval); bad_fork_cleanup_namespace: exit_namespace(p); bad_fork_cleanup_keys: --- linux-2.6.12-rc1/kernel/sysctl.c 2005-03-29 00:53:38.000000000 +0200 +++ linux/kernel/sysctl.c 2005-03-29 00:54:19.000000000 +0200 @@ -56,6 +56,7 @@ extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; extern int max_threads; +extern int max_user_threads; extern int sysrq_enabled; extern int core_uses_pid; extern char core_pattern[]; @@ -642,6 +643,14 @@ .mode = 0644, .proc_handler = &proc_dointvec, }, + { + .ctl_name = KERN_MAX_USER_THREADS, + .procname = "user_threads_max", + .data = &max_user_threads, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; --- linux-2.6.12-rc1/include/linux/sysctl.h 2005-03-29 00:54:06.000000000 +0200 +++ linux/include/linux/sysctl.h 2005-03-29 00:54:36.000000000 +0200 @@ -136,6 +136,7 @@ KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ KERN_BOOTLOADER_TYPE=67, /* int: boot loader type */ KERN_RANDOMIZE=68, /* int: randomize virtual address space */ + KERN_MAX_USER_THREADS=69, /* int: Maximum nr of threads per user in the system */ };
begin:vcard fn;quoted-printable:Jacek =C5=81uczak n;quoted-printable:=C5=81uczak;Jacek adr:;;Prof. Z. Szafrana 4a;Zielona Gora;;65-516;Poland email;internet:[EMAIL PROTECTED] title:Linux Registered User # 337142 x-mozilla-html:FALSE url:http://pin.if.uz.zgora.pl/~difrost version:2.1 end:vcard