From owner-svn-src-all@FreeBSD.ORG Mon Oct 21 16:44:54 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 88163404; Mon, 21 Oct 2013 16:44:54 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 67662249A; Mon, 21 Oct 2013 16:44:54 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9LGisc0012477; Mon, 21 Oct 2013 16:44:54 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9LGirtR012470; Mon, 21 Oct 2013 16:44:53 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201310211644.r9LGirtR012470@svn.freebsd.org> From: Konstantin Belousov Date: Mon, 21 Oct 2013 16:44:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r256849 - in head/sys: kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Oct 2013 16:44:54 -0000 Author: kib Date: Mon Oct 21 16:44:53 2013 New Revision: 256849 URL: http://svnweb.freebsd.org/changeset/base/256849 Log: Add a resource limit for the total number of kqueues available to the user. Kqueue now saves the ucred of the allocating thread, to correctly decrement the counter on close. Under some specific and not real-world use scenario for kqueue, it is possible for the kqueues to consume memory proportional to the square of the number of the filedescriptors available to the process. Limit allows administrator to prevent the abuse. This is kernel-mode side of the change, with the user-mode enabling commit following. Reported and tested by: pho Discussed with: jmg Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Modified: head/sys/kern/kern_event.c head/sys/kern/kern_resource.c head/sys/sys/eventvar.h head/sys/sys/resource.h head/sys/sys/resourcevar.h Modified: head/sys/kern/kern_event.c ============================================================================== --- head/sys/kern/kern_event.c Mon Oct 21 16:22:51 2013 (r256848) +++ head/sys/kern/kern_event.c Mon Oct 21 16:44:53 2013 (r256849) @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -699,9 +700,23 @@ sys_kqueue(struct thread *td, struct kqu struct filedesc *fdp; struct kqueue *kq; struct file *fp; + struct proc *p; + struct ucred *cred; int fd, error; - fdp = td->td_proc->p_fd; + p = td->td_proc; + cred = td->td_ucred; + crhold(cred); + PROC_LOCK(p); + if (!chgkqcnt(cred->cr_ruidinfo, 1, lim_cur(td->td_proc, + RLIMIT_KQUEUES))) { + PROC_UNLOCK(p); + crfree(cred); + return (EMFILE); + } + PROC_UNLOCK(p); + + fdp = p->p_fd; error = falloc(td, &fp, &fd, 0); if (error) goto done2; @@ -711,6 +726,7 @@ sys_kqueue(struct thread *td, struct kqu mtx_init(&kq->kq_lock, "kqueue", NULL, MTX_DEF|MTX_DUPOK); TAILQ_INIT(&kq->kq_head); kq->kq_fdp = fdp; + kq->kq_cred = cred; knlist_init_mtx(&kq->kq_sel.si_note, &kq->kq_lock); TASK_INIT(&kq->kq_task, 0, kqueue_task, kq); @@ -723,6 +739,10 @@ sys_kqueue(struct thread *td, struct kqu td->td_retval[0] = fd; done2: + if (error != 0) { + chgkqcnt(cred->cr_ruidinfo, -1, 0); + crfree(cred); + } return (error); } @@ -1767,6 +1787,8 @@ kqueue_close(struct file *fp, struct thr free(kq->kq_knlist, M_KQUEUE); funsetown(&kq->kq_sigio); + chgkqcnt(kq->kq_cred->cr_ruidinfo, -1, 0); + crfree(kq->kq_cred); free(kq, M_KQUEUE); fp->f_data = NULL; Modified: head/sys/kern/kern_resource.c ============================================================================== --- head/sys/kern/kern_resource.c Mon Oct 21 16:22:51 2013 (r256848) +++ head/sys/kern/kern_resource.c Mon Oct 21 16:44:53 2013 (r256849) @@ -1432,3 +1432,21 @@ chgptscnt(uip, diff, max) } return (1); } + +int +chgkqcnt(struct uidinfo *uip, int diff, rlim_t max) +{ + + if (diff > 0 && max != 0) { + if (atomic_fetchadd_long(&uip->ui_kqcnt, (long)diff) + + diff > max) { + atomic_subtract_long(&uip->ui_kqcnt, (long)diff); + return (0); + } + } else { + atomic_add_long(&uip->ui_kqcnt, (long)diff); + if (uip->ui_kqcnt < 0) + printf("negative kqcnt for uid = %d\n", uip->ui_uid); + } + return (1); +} Modified: head/sys/sys/eventvar.h ============================================================================== --- head/sys/sys/eventvar.h Mon Oct 21 16:22:51 2013 (r256848) +++ head/sys/sys/eventvar.h Mon Oct 21 16:44:53 2013 (r256849) @@ -60,6 +60,7 @@ struct kqueue { u_long kq_knhashmask; /* size of knhash */ struct klist *kq_knhash; /* hash table for knotes */ struct task kq_task; + struct ucred *kq_cred; }; #endif /* !_SYS_EVENTVAR_H_ */ Modified: head/sys/sys/resource.h ============================================================================== --- head/sys/sys/resource.h Mon Oct 21 16:22:51 2013 (r256848) +++ head/sys/sys/resource.h Mon Oct 21 16:44:53 2013 (r256849) @@ -103,8 +103,9 @@ struct __wrusage { #define RLIMIT_AS RLIMIT_VMEM /* standard name for RLIMIT_VMEM */ #define RLIMIT_NPTS 11 /* pseudo-terminals */ #define RLIMIT_SWAP 12 /* swap used */ +#define RLIMIT_KQUEUES 13 /* kqueues allocated */ -#define RLIM_NLIMITS 13 /* number of resource limits */ +#define RLIM_NLIMITS 14 /* number of resource limits */ #define RLIM_INFINITY ((rlim_t)(((uint64_t)1 << 63) - 1)) /* XXX Missing: RLIM_SAVED_MAX, RLIM_SAVED_CUR */ @@ -129,6 +130,7 @@ static const char *rlimit_ident[RLIM_NLI "vmem", "npts", "swap", + "kqueues", }; #endif Modified: head/sys/sys/resourcevar.h ============================================================================== --- head/sys/sys/resourcevar.h Mon Oct 21 16:22:51 2013 (r256848) +++ head/sys/sys/resourcevar.h Mon Oct 21 16:44:53 2013 (r256849) @@ -99,6 +99,7 @@ struct uidinfo { long ui_sbsize; /* (b) socket buffer space consumed */ long ui_proccnt; /* (b) number of processes */ long ui_ptscnt; /* (b) number of pseudo-terminals */ + long ui_kqcnt; /* (b) number of kqueues */ uid_t ui_uid; /* (a) uid */ u_int ui_ref; /* (b) reference count */ struct racct *ui_racct; /* (a) resource accounting */ @@ -115,6 +116,7 @@ void addupc_intr(struct thread *td, uin void addupc_task(struct thread *td, uintfptr_t pc, u_int ticks); void calccru(struct proc *p, struct timeval *up, struct timeval *sp); void calcru(struct proc *p, struct timeval *up, struct timeval *sp); +int chgkqcnt(struct uidinfo *uip, int diff, rlim_t max); int chgproccnt(struct uidinfo *uip, int diff, rlim_t maxval); int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t maxval);