Enforce the maxproc limitation before allocating struct proc, initial

struct thread and kernel stack for the thread.  Otherwise, a load
similar to a fork bomb would exhaust KVA and possibly kmem, mostly due
to the struct proc being type-stable.

The nprocs counter is changed from being protected by allproc_lock sx
to be an atomic variable.  Note that ddb/db_ps.c:db_ps() use of nprocs
was unsafe before, and is still unsafe, but it seems that the only
possible undesired consequence is the harmless warning printed when
allproc linked list length does not match nprocs.

Diagnosed by:	Svatopluk Kraus <onwahe@gmail.com>
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2015-10-08 11:07:09 +00:00
parent 4f621ff9dc
commit 4b48959f9f
2 changed files with 34 additions and 32 deletions

View File

@ -963,9 +963,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
KASSERT(FIRST_THREAD_IN_PROC(p),
("proc_reap: no residual thread!"));
uma_zfree(proc_zone, p);
sx_xlock(&allproc_lock);
nprocs--;
sx_xunlock(&allproc_lock);
atomic_add_int(&nprocs, -1);
}
static int

View File

@ -382,12 +382,6 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
p2_held = 0;
p1 = td->td_proc;
/*
* Increment the nprocs resource before blocking can occur. There
* are hard-limits as to the number of processes that can run.
*/
nprocs++;
trypid = fork_findpid(flags);
sx_sunlock(&proctree_lock);
@ -771,16 +765,14 @@ int
fork1(struct thread *td, int flags, int pages, struct proc **procp,
int *procdescp, int pdflags, struct filecaps *fcaps)
{
struct proc *p1;
struct proc *newproc;
int ok;
struct proc *p1, *newproc;
struct thread *td2;
struct vmspace *vm2;
struct file *fp_procdesc;
vm_ooffset_t mem_charged;
int error;
int error, nprocs_new, ok;
static int curfail;
static struct timeval lastfail;
struct file *fp_procdesc = NULL;
/* Check for the undefined or unimplemented flags. */
if ((flags & ~(RFFLAGS | RFTSIGFLAGS(RFTSIGMASK))) != 0)
@ -819,6 +811,35 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
return (fork_norfproc(td, flags));
}
fp_procdesc = NULL;
newproc = NULL;
vm2 = NULL;
/*
* Increment the nprocs resource before allocations occur.
* Although process entries are dynamically created, we still
* keep a global limit on the maximum number we will
* create. There are hard-limits as to the number of processes
* that can run, established by the KVA and memory usage for
* the process data.
*
* Don't allow a nonprivileged user to use the last ten
* processes; don't let root exceed the limit.
*/
nprocs_new = atomic_fetchadd_int(&nprocs, 1) + 1;
if ((nprocs_new >= maxproc - 10 && priv_check_cred(td->td_ucred,
PRIV_MAXPROC, 0) != 0) || nprocs_new >= maxproc) {
error = EAGAIN;
sx_xlock(&allproc_lock);
if (ppsratecheck(&lastfail, &curfail, 1)) {
printf("maxproc limit exceeded by uid %u (pid %d); "
"see tuning(7) and login.conf(5)\n",
td->td_ucred->cr_ruid, p1->p_pid);
}
sx_xunlock(&allproc_lock);
goto fail2;
}
/*
* If required, create a process descriptor in the parent first; we
* will abandon it if something goes wrong. We don't finit() until
@ -831,7 +852,6 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
}
mem_charged = 0;
vm2 = NULL;
if (pages == 0)
pages = kstack_pages;
/* Allocate new proc. */
@ -898,20 +918,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
/* We have to lock the process tree while we look for a pid. */
sx_slock(&proctree_lock);
/*
* Although process entries are dynamically created, we still keep
* a global limit on the maximum number we will create. Don't allow
* a nonprivileged user to use the last ten processes; don't let root
* exceed the limit. The variable nprocs is the current number of
* processes, maxproc is the limit.
*/
sx_xlock(&allproc_lock);
if ((nprocs >= maxproc - 10 && priv_check_cred(td->td_ucred,
PRIV_MAXPROC, 0) != 0) || nprocs >= maxproc) {
error = EAGAIN;
goto fail;
}
/*
* Increment the count of procs running with this uid. Don't allow
@ -942,11 +949,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
}
error = EAGAIN;
fail:
sx_sunlock(&proctree_lock);
if (ppsratecheck(&lastfail, &curfail, 1))
printf("maxproc limit exceeded by uid %u (pid %d); see tuning(7) and login.conf(5)\n",
td->td_ucred->cr_ruid, p1->p_pid);
sx_xunlock(&allproc_lock);
#ifdef MAC
mac_proc_destroy(newproc);
@ -963,6 +966,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp,
fdclose(td, fp_procdesc, *procdescp);
fdrop(fp_procdesc, td);
}
atomic_add_int(&nprocs, -1);
pause("fork", hz / 2);
return (error);
}