Date: Sat, 16 Nov 2002 21:03:46 -0500 (EST) From: Dave Andersen <dga@lcs.mit.edu> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/45353: Trivial local DoS via file table exhaustion Message-ID: <200211170203.gAH23kdN003042@eep.lcs.mit.edu>
index | next in thread | raw e-mail
>Number: 45353
>Category: kern
>Synopsis: Trivial local DoS via file table exhaustion
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Sat Nov 16 18:10:01 PST 2002
>Closed-Date:
>Last-Modified:
>Originator: Dave Andersen
>Release: FreeBSD 4.7-STABLE i386
>Organization:
MIT
>Environment:
System: FreeBSD eep.lcs.mit.edu 4.7-STABLE FreeBSD 4.7-STABLE #5: Sat Nov 16 17:31:56 EST 2002 root@eep.lcs.mit.edu:/usr/src/sys/compile/EEP46 i386
>Description:
As noted in earlier security advisories, it's trivial to exhaust
the kernel file table entries and cause a denial of service to
other users, including root. While some accidental occurrences of
this can be reduced using setrlimit / login.conf limits, it's
impractical to prevent a malicious user from stopping the system
dead in its tracks, because to do so would require setting
per-user proc limit * per-proc FD limit < maxproc
Which is impractical.
>How-To-Repeat:
Run as many separate instances of this as necessary:
#include <fcntl.h>
int main() {
while (1) {
open("/tmp", O_RDONLY);
}
}
>Fix:
Attached is a patch that reserves a few file table slots for use
by root. This isn't a perfect solution, but the real solution
(per-user file limits) is invasive, and may impose excessive
accounting overhead. This solution is simple, easy to verify,
and provides a channel by which the system administrator can at
least get in to the machine to clean up.
By default, this patch sets aside the last 5% of the file table
for use only by root (i.e. if it's 95% full, then only root may
open files). The number is configurable by a sysctl. The patch:
diff -r -c sys/kern/kern_descrip.c /usr/src/sys/kern/kern_descrip.c
*** sys/kern/kern_descrip.c Mon Apr 29 09:14:12 2002
--- /usr/src/sys/kern/kern_descrip.c Sat Nov 16 14:44:25 2002
***************
*** 849,854 ****
--- 849,859 ----
register struct file *fp, *fq;
int error, i;
+ if (nfiles >= (maxfiles - reservefiles) &&
+ p->p_ucred->cr_uid != 0) {
+ tablefull("non-root file");
+ return(ENFILE);
+ }
if (nfiles >= maxfiles) {
tablefull("file");
return (ENFILE);
***************
*** 1527,1532 ****
--- 1532,1540 ----
SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW,
&maxfiles, 0, "Maximum number of files");
+
+ SYSCTL_INT(_kern, KERN_RESERVEFILES, reservefiles, CTLFLAG_RW,
+ &reservefiles, 0, "Number of files reserved for root");
SYSCTL_INT(_kern, OID_AUTO, openfiles, CTLFLAG_RD,
&nfiles, 0, "System-wide number of open files");
diff -r -c sys/kern/subr_param.c /usr/src/sys/kern/subr_param.c
*** sys/kern/subr_param.c Sat Mar 9 14:05:47 2002
--- /usr/src/sys/kern/subr_param.c Sat Nov 16 14:50:26 2002
***************
*** 62,67 ****
--- 62,70 ----
#ifndef MAXFILES
#define MAXFILES (maxproc * 2)
#endif
+ #ifndef RESERVEFILES
+ #define RESERVEFILES (maxfiles / 20)
+ #endif
#ifndef NSFBUFS
#define NSFBUFS (512 + maxusers * 16)
#endif
***************
*** 74,79 ****
--- 77,83 ----
int maxprocperuid; /* max # of procs per user */
int maxfiles; /* sys. wide open files limit */
int maxfilesperproc; /* per-proc open files limit */
+ int reservefiles; /* Files reserved for root */
int ncallout; /* maximum # of timer events */
int mbuf_wait = 32; /* mbuf sleep time in ticks */
int nbuf;
***************
*** 163,168 ****
--- 167,174 ----
maxproc = physpages / 12;
maxfiles = MAXFILES;
TUNABLE_INT_FETCH("kern.maxfiles", &maxfiles);
+ reservefiles = RESERVEFILES;
+ TUNABLE_INT_FETCH("kern.reservefiles", &reservefiles);
maxprocperuid = (maxproc * 9) / 10;
maxfilesperproc = (maxfiles * 9) / 10;
diff -r -c sys/sys/file.h /usr/src/sys/sys/file.h
*** sys/sys/file.h Sat Jun 2 23:00:10 2001
--- /usr/src/sys/sys/file.h Sat Nov 16 14:58:21 2002
***************
*** 107,112 ****
--- 107,113 ----
extern int maxfiles; /* kernel limit on number of open files */
extern int maxfilesperproc; /* per process limit on number of open files */
extern int nfiles; /* actual number of open files */
+ extern int reservefiles; /* open files reserved for root */
static __inline void fhold __P((struct file *fp));
int fdrop __P((struct file *fp, struct proc *p));
Only in /usr/src/sys/sys: file.h~
diff -r -c sys/sys/sysctl.h /usr/src/sys/sys/sysctl.h
*** sys/sys/sysctl.h Mon Sep 9 13:27:54 2002
--- /usr/src/sys/sys/sysctl.h Sat Nov 16 14:45:53 2002
***************
*** 331,337 ****
#define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */
#define KERN_USRSTACK 33 /* int: address of USRSTACK */
#define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */
! #define KERN_MAXID 35 /* number of valid kern ids */
#define CTL_KERN_NAMES { \
{ 0, 0 }, \
--- 331,338 ----
#define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */
#define KERN_USRSTACK 33 /* int: address of USRSTACK */
#define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */
! #define KERN_RESERVEFILES 35 /* int: number of root-only files */
! #define KERN_MAXID 36 /* number of valid kern ids */
#define CTL_KERN_NAMES { \
{ 0, 0 }, \
***************
*** 369,374 ****
--- 370,376 ----
{ "ps_strings", CTLTYPE_INT }, \
{ "usrstack", CTLTYPE_INT }, \
{ "logsigexit", CTLTYPE_INT }, \
+ { "reservefiles", CTLTYPE_INT }, \
}
/*
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200211170203.gAH23kdN003042>
