xref: /freebsd/sys/kern/kern_rctl.c (revision ec125fbbc5b9f92be4cffec770e6312d38aa98b7)
1*ec125fbbSEdward Tomasz Napierala /*-
2*ec125fbbSEdward Tomasz Napierala  * Copyright (c) 2010 The FreeBSD Foundation
3*ec125fbbSEdward Tomasz Napierala  * All rights reserved.
4*ec125fbbSEdward Tomasz Napierala  *
5*ec125fbbSEdward Tomasz Napierala  * This software was developed by Edward Tomasz Napierala under sponsorship
6*ec125fbbSEdward Tomasz Napierala  * from the FreeBSD Foundation.
7*ec125fbbSEdward Tomasz Napierala  *
8*ec125fbbSEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
9*ec125fbbSEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
10*ec125fbbSEdward Tomasz Napierala  * are met:
11*ec125fbbSEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
12*ec125fbbSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer.
13*ec125fbbSEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
14*ec125fbbSEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
15*ec125fbbSEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
16*ec125fbbSEdward Tomasz Napierala  *
17*ec125fbbSEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*ec125fbbSEdward Tomasz Napierala  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*ec125fbbSEdward Tomasz Napierala  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*ec125fbbSEdward Tomasz Napierala  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*ec125fbbSEdward Tomasz Napierala  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*ec125fbbSEdward Tomasz Napierala  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*ec125fbbSEdward Tomasz Napierala  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*ec125fbbSEdward Tomasz Napierala  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*ec125fbbSEdward Tomasz Napierala  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*ec125fbbSEdward Tomasz Napierala  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*ec125fbbSEdward Tomasz Napierala  * SUCH DAMAGE.
28*ec125fbbSEdward Tomasz Napierala  *
29*ec125fbbSEdward Tomasz Napierala  * $FreeBSD$
30*ec125fbbSEdward Tomasz Napierala  */
31*ec125fbbSEdward Tomasz Napierala 
32*ec125fbbSEdward Tomasz Napierala #include <sys/cdefs.h>
33*ec125fbbSEdward Tomasz Napierala __FBSDID("$FreeBSD$");
34*ec125fbbSEdward Tomasz Napierala 
35*ec125fbbSEdward Tomasz Napierala #include <sys/param.h>
36*ec125fbbSEdward Tomasz Napierala #include <sys/bus.h>
37*ec125fbbSEdward Tomasz Napierala #include <sys/malloc.h>
38*ec125fbbSEdward Tomasz Napierala #include <sys/queue.h>
39*ec125fbbSEdward Tomasz Napierala #include <sys/refcount.h>
40*ec125fbbSEdward Tomasz Napierala #include <sys/jail.h>
41*ec125fbbSEdward Tomasz Napierala #include <sys/kernel.h>
42*ec125fbbSEdward Tomasz Napierala #include <sys/limits.h>
43*ec125fbbSEdward Tomasz Napierala #include <sys/loginclass.h>
44*ec125fbbSEdward Tomasz Napierala #include <sys/priv.h>
45*ec125fbbSEdward Tomasz Napierala #include <sys/proc.h>
46*ec125fbbSEdward Tomasz Napierala #include <sys/racct.h>
47*ec125fbbSEdward Tomasz Napierala #include <sys/rctl.h>
48*ec125fbbSEdward Tomasz Napierala #include <sys/resourcevar.h>
49*ec125fbbSEdward Tomasz Napierala #include <sys/sx.h>
50*ec125fbbSEdward Tomasz Napierala #include <sys/sysent.h>
51*ec125fbbSEdward Tomasz Napierala #include <sys/sysproto.h>
52*ec125fbbSEdward Tomasz Napierala #include <sys/systm.h>
53*ec125fbbSEdward Tomasz Napierala #include <sys/types.h>
54*ec125fbbSEdward Tomasz Napierala #include <sys/eventhandler.h>
55*ec125fbbSEdward Tomasz Napierala #include <sys/lock.h>
56*ec125fbbSEdward Tomasz Napierala #include <sys/mutex.h>
57*ec125fbbSEdward Tomasz Napierala #include <sys/rwlock.h>
58*ec125fbbSEdward Tomasz Napierala #include <sys/sbuf.h>
59*ec125fbbSEdward Tomasz Napierala #include <sys/taskqueue.h>
60*ec125fbbSEdward Tomasz Napierala #include <sys/tree.h>
61*ec125fbbSEdward Tomasz Napierala #include <vm/uma.h>
62*ec125fbbSEdward Tomasz Napierala 
63*ec125fbbSEdward Tomasz Napierala #ifdef RCTL
64*ec125fbbSEdward Tomasz Napierala #ifndef RACCT
65*ec125fbbSEdward Tomasz Napierala #error "The RCTL option requires the RACCT option"
66*ec125fbbSEdward Tomasz Napierala #endif
67*ec125fbbSEdward Tomasz Napierala 
68*ec125fbbSEdward Tomasz Napierala FEATURE(rctl, "Resource Limits");
69*ec125fbbSEdward Tomasz Napierala 
70*ec125fbbSEdward Tomasz Napierala #define	HRF_DEFAULT		0
71*ec125fbbSEdward Tomasz Napierala #define	HRF_DONT_INHERIT	1
72*ec125fbbSEdward Tomasz Napierala #define	HRF_DONT_ACCUMULATE	2
73*ec125fbbSEdward Tomasz Napierala 
74*ec125fbbSEdward Tomasz Napierala /* Default buffer size for rctl_get_rules(2). */
75*ec125fbbSEdward Tomasz Napierala #define	RCTL_DEFAULT_BUFSIZE	4096
76*ec125fbbSEdward Tomasz Napierala #define	RCTL_LOG_BUFSIZE	128
77*ec125fbbSEdward Tomasz Napierala 
78*ec125fbbSEdward Tomasz Napierala /*
79*ec125fbbSEdward Tomasz Napierala  * 'rctl_rule_link' connects a rule with every racct it's related to.
80*ec125fbbSEdward Tomasz Napierala  * For example, rule 'user:X:openfiles:deny=N/process' is linked
81*ec125fbbSEdward Tomasz Napierala  * with uidinfo for user X, and to each process of that user.
82*ec125fbbSEdward Tomasz Napierala  */
83*ec125fbbSEdward Tomasz Napierala struct rctl_rule_link {
84*ec125fbbSEdward Tomasz Napierala 	LIST_ENTRY(rctl_rule_link)	rrl_next;
85*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule		*rrl_rule;
86*ec125fbbSEdward Tomasz Napierala 	int				rrl_exceeded;
87*ec125fbbSEdward Tomasz Napierala };
88*ec125fbbSEdward Tomasz Napierala 
89*ec125fbbSEdward Tomasz Napierala struct dict {
90*ec125fbbSEdward Tomasz Napierala 	const char	*d_name;
91*ec125fbbSEdward Tomasz Napierala 	int		d_value;
92*ec125fbbSEdward Tomasz Napierala };
93*ec125fbbSEdward Tomasz Napierala 
94*ec125fbbSEdward Tomasz Napierala static struct dict subjectnames[] = {
95*ec125fbbSEdward Tomasz Napierala 	{ "process", RCTL_SUBJECT_TYPE_PROCESS },
96*ec125fbbSEdward Tomasz Napierala 	{ "user", RCTL_SUBJECT_TYPE_USER },
97*ec125fbbSEdward Tomasz Napierala 	{ "loginclass", RCTL_SUBJECT_TYPE_LOGINCLASS },
98*ec125fbbSEdward Tomasz Napierala 	{ "jail", RCTL_SUBJECT_TYPE_JAIL },
99*ec125fbbSEdward Tomasz Napierala 	{ NULL, -1 }};
100*ec125fbbSEdward Tomasz Napierala 
101*ec125fbbSEdward Tomasz Napierala static struct dict resourcenames[] = {
102*ec125fbbSEdward Tomasz Napierala 	{ "cpu", RACCT_CPU },
103*ec125fbbSEdward Tomasz Napierala 	{ "fsize", RACCT_FSIZE },
104*ec125fbbSEdward Tomasz Napierala 	{ "data", RACCT_DATA },
105*ec125fbbSEdward Tomasz Napierala 	{ "stack", RACCT_STACK },
106*ec125fbbSEdward Tomasz Napierala 	{ "core", RACCT_CORE },
107*ec125fbbSEdward Tomasz Napierala 	{ "rss", RACCT_RSS },
108*ec125fbbSEdward Tomasz Napierala 	{ "memlock", RACCT_MEMLOCK },
109*ec125fbbSEdward Tomasz Napierala 	{ "nproc", RACCT_NPROC },
110*ec125fbbSEdward Tomasz Napierala 	{ "nofile", RACCT_NOFILE },
111*ec125fbbSEdward Tomasz Napierala 	{ "sbsize", RACCT_SBSIZE },
112*ec125fbbSEdward Tomasz Napierala 	{ "vmem", RACCT_VMEM },
113*ec125fbbSEdward Tomasz Napierala 	{ "npts", RACCT_NPTS },
114*ec125fbbSEdward Tomasz Napierala 	{ "swap", RACCT_SWAP },
115*ec125fbbSEdward Tomasz Napierala 	{ "nthr", RACCT_NTHR },
116*ec125fbbSEdward Tomasz Napierala 	{ "msgqqueued", RACCT_MSGQQUEUED },
117*ec125fbbSEdward Tomasz Napierala 	{ "msgqsize", RACCT_MSGQSIZE },
118*ec125fbbSEdward Tomasz Napierala 	{ "nmsgq", RACCT_NMSGQ },
119*ec125fbbSEdward Tomasz Napierala 	{ "nsem", RACCT_NSEM },
120*ec125fbbSEdward Tomasz Napierala 	{ "nsemop", RACCT_NSEMOP },
121*ec125fbbSEdward Tomasz Napierala 	{ "nshm", RACCT_NSHM },
122*ec125fbbSEdward Tomasz Napierala 	{ "shmsize", RACCT_SHMSIZE },
123*ec125fbbSEdward Tomasz Napierala 	{ "wallclock", RACCT_WALLCLOCK },
124*ec125fbbSEdward Tomasz Napierala 	{ NULL, -1 }};
125*ec125fbbSEdward Tomasz Napierala 
126*ec125fbbSEdward Tomasz Napierala static struct dict actionnames[] = {
127*ec125fbbSEdward Tomasz Napierala 	{ "sighup", RCTL_ACTION_SIGHUP },
128*ec125fbbSEdward Tomasz Napierala 	{ "sigint", RCTL_ACTION_SIGINT },
129*ec125fbbSEdward Tomasz Napierala 	{ "sigquit", RCTL_ACTION_SIGQUIT },
130*ec125fbbSEdward Tomasz Napierala 	{ "sigill", RCTL_ACTION_SIGILL },
131*ec125fbbSEdward Tomasz Napierala 	{ "sigtrap", RCTL_ACTION_SIGTRAP },
132*ec125fbbSEdward Tomasz Napierala 	{ "sigabrt", RCTL_ACTION_SIGABRT },
133*ec125fbbSEdward Tomasz Napierala 	{ "sigemt", RCTL_ACTION_SIGEMT },
134*ec125fbbSEdward Tomasz Napierala 	{ "sigfpe", RCTL_ACTION_SIGFPE },
135*ec125fbbSEdward Tomasz Napierala 	{ "sigkill", RCTL_ACTION_SIGKILL },
136*ec125fbbSEdward Tomasz Napierala 	{ "sigbus", RCTL_ACTION_SIGBUS },
137*ec125fbbSEdward Tomasz Napierala 	{ "sigsegv", RCTL_ACTION_SIGSEGV },
138*ec125fbbSEdward Tomasz Napierala 	{ "sigsys", RCTL_ACTION_SIGSYS },
139*ec125fbbSEdward Tomasz Napierala 	{ "sigpipe", RCTL_ACTION_SIGPIPE },
140*ec125fbbSEdward Tomasz Napierala 	{ "sigalrm", RCTL_ACTION_SIGALRM },
141*ec125fbbSEdward Tomasz Napierala 	{ "sigterm", RCTL_ACTION_SIGTERM },
142*ec125fbbSEdward Tomasz Napierala 	{ "sigurg", RCTL_ACTION_SIGURG },
143*ec125fbbSEdward Tomasz Napierala 	{ "sigstop", RCTL_ACTION_SIGSTOP },
144*ec125fbbSEdward Tomasz Napierala 	{ "sigtstp", RCTL_ACTION_SIGTSTP },
145*ec125fbbSEdward Tomasz Napierala 	{ "sigchld", RCTL_ACTION_SIGCHLD },
146*ec125fbbSEdward Tomasz Napierala 	{ "sigttin", RCTL_ACTION_SIGTTIN },
147*ec125fbbSEdward Tomasz Napierala 	{ "sigttou", RCTL_ACTION_SIGTTOU },
148*ec125fbbSEdward Tomasz Napierala 	{ "sigio", RCTL_ACTION_SIGIO },
149*ec125fbbSEdward Tomasz Napierala 	{ "sigxcpu", RCTL_ACTION_SIGXCPU },
150*ec125fbbSEdward Tomasz Napierala 	{ "sigxfsz", RCTL_ACTION_SIGXFSZ },
151*ec125fbbSEdward Tomasz Napierala 	{ "sigvtalrm", RCTL_ACTION_SIGVTALRM },
152*ec125fbbSEdward Tomasz Napierala 	{ "sigprof", RCTL_ACTION_SIGPROF },
153*ec125fbbSEdward Tomasz Napierala 	{ "sigwinch", RCTL_ACTION_SIGWINCH },
154*ec125fbbSEdward Tomasz Napierala 	{ "siginfo", RCTL_ACTION_SIGINFO },
155*ec125fbbSEdward Tomasz Napierala 	{ "sigusr1", RCTL_ACTION_SIGUSR1 },
156*ec125fbbSEdward Tomasz Napierala 	{ "sigusr2", RCTL_ACTION_SIGUSR2 },
157*ec125fbbSEdward Tomasz Napierala 	{ "sigthr", RCTL_ACTION_SIGTHR },
158*ec125fbbSEdward Tomasz Napierala 	{ "deny", RCTL_ACTION_DENY },
159*ec125fbbSEdward Tomasz Napierala 	{ "log", RCTL_ACTION_LOG },
160*ec125fbbSEdward Tomasz Napierala 	{ "devctl", RCTL_ACTION_DEVCTL },
161*ec125fbbSEdward Tomasz Napierala 	{ NULL, -1 }};
162*ec125fbbSEdward Tomasz Napierala 
163*ec125fbbSEdward Tomasz Napierala static void rctl_init(void);
164*ec125fbbSEdward Tomasz Napierala SYSINIT(rctl, SI_SUB_RACCT, SI_ORDER_FIRST, rctl_init, NULL);
165*ec125fbbSEdward Tomasz Napierala 
166*ec125fbbSEdward Tomasz Napierala static uma_zone_t rctl_rule_link_zone;
167*ec125fbbSEdward Tomasz Napierala static uma_zone_t rctl_rule_zone;
168*ec125fbbSEdward Tomasz Napierala static struct rwlock rctl_lock;
169*ec125fbbSEdward Tomasz Napierala RW_SYSINIT(rctl_lock, &rctl_lock, "RCTL lock");
170*ec125fbbSEdward Tomasz Napierala 
171*ec125fbbSEdward Tomasz Napierala static int rctl_rule_fully_specified(const struct rctl_rule *rule);
172*ec125fbbSEdward Tomasz Napierala static void rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule);
173*ec125fbbSEdward Tomasz Napierala 
174*ec125fbbSEdward Tomasz Napierala MALLOC_DEFINE(M_RCTL, "rctl", "Resource Limits");
175*ec125fbbSEdward Tomasz Napierala 
176*ec125fbbSEdward Tomasz Napierala static const char *
177*ec125fbbSEdward Tomasz Napierala rctl_subject_type_name(int subject)
178*ec125fbbSEdward Tomasz Napierala {
179*ec125fbbSEdward Tomasz Napierala 	int i;
180*ec125fbbSEdward Tomasz Napierala 
181*ec125fbbSEdward Tomasz Napierala 	for (i = 0; subjectnames[i].d_name != NULL; i++) {
182*ec125fbbSEdward Tomasz Napierala 		if (subjectnames[i].d_value == subject)
183*ec125fbbSEdward Tomasz Napierala 			return (subjectnames[i].d_name);
184*ec125fbbSEdward Tomasz Napierala 	}
185*ec125fbbSEdward Tomasz Napierala 
186*ec125fbbSEdward Tomasz Napierala 	panic("rctl_subject_type_name: unknown subject type %d", subject);
187*ec125fbbSEdward Tomasz Napierala }
188*ec125fbbSEdward Tomasz Napierala 
189*ec125fbbSEdward Tomasz Napierala static const char *
190*ec125fbbSEdward Tomasz Napierala rctl_action_name(int action)
191*ec125fbbSEdward Tomasz Napierala {
192*ec125fbbSEdward Tomasz Napierala 	int i;
193*ec125fbbSEdward Tomasz Napierala 
194*ec125fbbSEdward Tomasz Napierala 	for (i = 0; actionnames[i].d_name != NULL; i++) {
195*ec125fbbSEdward Tomasz Napierala 		if (actionnames[i].d_value == action)
196*ec125fbbSEdward Tomasz Napierala 			return (actionnames[i].d_name);
197*ec125fbbSEdward Tomasz Napierala 	}
198*ec125fbbSEdward Tomasz Napierala 
199*ec125fbbSEdward Tomasz Napierala 	panic("rctl_action_name: unknown action %d", action);
200*ec125fbbSEdward Tomasz Napierala }
201*ec125fbbSEdward Tomasz Napierala 
202*ec125fbbSEdward Tomasz Napierala const char *
203*ec125fbbSEdward Tomasz Napierala rctl_resource_name(int resource)
204*ec125fbbSEdward Tomasz Napierala {
205*ec125fbbSEdward Tomasz Napierala 	int i;
206*ec125fbbSEdward Tomasz Napierala 
207*ec125fbbSEdward Tomasz Napierala 	for (i = 0; resourcenames[i].d_name != NULL; i++) {
208*ec125fbbSEdward Tomasz Napierala 		if (resourcenames[i].d_value == resource)
209*ec125fbbSEdward Tomasz Napierala 			return (resourcenames[i].d_name);
210*ec125fbbSEdward Tomasz Napierala 	}
211*ec125fbbSEdward Tomasz Napierala 
212*ec125fbbSEdward Tomasz Napierala 	panic("rctl_resource_name: unknown resource %d", resource);
213*ec125fbbSEdward Tomasz Napierala }
214*ec125fbbSEdward Tomasz Napierala 
215*ec125fbbSEdward Tomasz Napierala /*
216*ec125fbbSEdward Tomasz Napierala  * Return the amount of resource that can be allocated by 'p' before
217*ec125fbbSEdward Tomasz Napierala  * hitting 'rule'.
218*ec125fbbSEdward Tomasz Napierala  */
219*ec125fbbSEdward Tomasz Napierala static int64_t
220*ec125fbbSEdward Tomasz Napierala rctl_available_resource(const struct proc *p, const struct rctl_rule *rule)
221*ec125fbbSEdward Tomasz Napierala {
222*ec125fbbSEdward Tomasz Napierala 	int resource;
223*ec125fbbSEdward Tomasz Napierala 	int64_t available = INT64_MAX;
224*ec125fbbSEdward Tomasz Napierala 	struct ucred *cred = p->p_ucred;
225*ec125fbbSEdward Tomasz Napierala 
226*ec125fbbSEdward Tomasz Napierala 	rw_assert(&rctl_lock, RA_LOCKED);
227*ec125fbbSEdward Tomasz Napierala 
228*ec125fbbSEdward Tomasz Napierala 	resource = rule->rr_resource;
229*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_per) {
230*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
231*ec125fbbSEdward Tomasz Napierala 		available = rule->rr_amount -
232*ec125fbbSEdward Tomasz Napierala 		    p->p_racct->r_resources[resource];
233*ec125fbbSEdward Tomasz Napierala 		break;
234*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
235*ec125fbbSEdward Tomasz Napierala 		available = rule->rr_amount -
236*ec125fbbSEdward Tomasz Napierala 		    cred->cr_ruidinfo->ui_racct->r_resources[resource];
237*ec125fbbSEdward Tomasz Napierala 		break;
238*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
239*ec125fbbSEdward Tomasz Napierala 		available = rule->rr_amount -
240*ec125fbbSEdward Tomasz Napierala 		    cred->cr_loginclass->lc_racct->r_resources[resource];
241*ec125fbbSEdward Tomasz Napierala 		break;
242*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
243*ec125fbbSEdward Tomasz Napierala 		available = rule->rr_amount -
244*ec125fbbSEdward Tomasz Napierala 		    cred->cr_prison->pr_racct->r_resources[resource];
245*ec125fbbSEdward Tomasz Napierala 		break;
246*ec125fbbSEdward Tomasz Napierala 	default:
247*ec125fbbSEdward Tomasz Napierala 		panic("rctl_compute_available: unknown per %d",
248*ec125fbbSEdward Tomasz Napierala 		    rule->rr_per);
249*ec125fbbSEdward Tomasz Napierala 	}
250*ec125fbbSEdward Tomasz Napierala 
251*ec125fbbSEdward Tomasz Napierala 	return (available);
252*ec125fbbSEdward Tomasz Napierala }
253*ec125fbbSEdward Tomasz Napierala 
254*ec125fbbSEdward Tomasz Napierala /*
255*ec125fbbSEdward Tomasz Napierala  * Return non-zero if allocating 'amount' by proc 'p' would exceed
256*ec125fbbSEdward Tomasz Napierala  * resource limit specified by 'rule'.
257*ec125fbbSEdward Tomasz Napierala  */
258*ec125fbbSEdward Tomasz Napierala static int
259*ec125fbbSEdward Tomasz Napierala rctl_would_exceed(const struct proc *p, const struct rctl_rule *rule,
260*ec125fbbSEdward Tomasz Napierala     int64_t amount)
261*ec125fbbSEdward Tomasz Napierala {
262*ec125fbbSEdward Tomasz Napierala 	int64_t available;
263*ec125fbbSEdward Tomasz Napierala 
264*ec125fbbSEdward Tomasz Napierala 	rw_assert(&rctl_lock, RA_LOCKED);
265*ec125fbbSEdward Tomasz Napierala 
266*ec125fbbSEdward Tomasz Napierala 	available = rctl_available_resource(p, rule);
267*ec125fbbSEdward Tomasz Napierala 	if (available >= amount)
268*ec125fbbSEdward Tomasz Napierala 		return (0);
269*ec125fbbSEdward Tomasz Napierala 
270*ec125fbbSEdward Tomasz Napierala 	return (1);
271*ec125fbbSEdward Tomasz Napierala }
272*ec125fbbSEdward Tomasz Napierala 
273*ec125fbbSEdward Tomasz Napierala /*
274*ec125fbbSEdward Tomasz Napierala  * Check whether the proc 'p' can allocate 'amount' of 'resource' in addition
275*ec125fbbSEdward Tomasz Napierala  * to what it keeps allocated now.  Returns non-zero if the allocation should
276*ec125fbbSEdward Tomasz Napierala  * be denied, 0 otherwise.
277*ec125fbbSEdward Tomasz Napierala  */
278*ec125fbbSEdward Tomasz Napierala int
279*ec125fbbSEdward Tomasz Napierala rctl_enforce(struct proc *p, int resource, uint64_t amount)
280*ec125fbbSEdward Tomasz Napierala {
281*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
282*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
283*ec125fbbSEdward Tomasz Napierala 	struct sbuf sb;
284*ec125fbbSEdward Tomasz Napierala 	int should_deny = 0;
285*ec125fbbSEdward Tomasz Napierala 	char *buf;
286*ec125fbbSEdward Tomasz Napierala 	static int curtime = 0;
287*ec125fbbSEdward Tomasz Napierala 	static struct timeval lasttime;
288*ec125fbbSEdward Tomasz Napierala 
289*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
290*ec125fbbSEdward Tomasz Napierala 
291*ec125fbbSEdward Tomasz Napierala 	/*
292*ec125fbbSEdward Tomasz Napierala 	 * There may be more than one matching rule; go through all of them.
293*ec125fbbSEdward Tomasz Napierala 	 * Denial should be done last, after logging and sending signals.
294*ec125fbbSEdward Tomasz Napierala 	 */
295*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
296*ec125fbbSEdward Tomasz Napierala 		rule = link->rrl_rule;
297*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_resource != resource)
298*ec125fbbSEdward Tomasz Napierala 			continue;
299*ec125fbbSEdward Tomasz Napierala 		if (!rctl_would_exceed(p, rule, amount)) {
300*ec125fbbSEdward Tomasz Napierala 			link->rrl_exceeded = 0;
301*ec125fbbSEdward Tomasz Napierala 			continue;
302*ec125fbbSEdward Tomasz Napierala 		}
303*ec125fbbSEdward Tomasz Napierala 
304*ec125fbbSEdward Tomasz Napierala 		switch (rule->rr_action) {
305*ec125fbbSEdward Tomasz Napierala 		case RCTL_ACTION_DENY:
306*ec125fbbSEdward Tomasz Napierala 			should_deny = 1;
307*ec125fbbSEdward Tomasz Napierala 			continue;
308*ec125fbbSEdward Tomasz Napierala 		case RCTL_ACTION_LOG:
309*ec125fbbSEdward Tomasz Napierala 			/*
310*ec125fbbSEdward Tomasz Napierala 			 * If rrl_exceeded != 0, it means we've already
311*ec125fbbSEdward Tomasz Napierala 			 * logged a warning for this process.
312*ec125fbbSEdward Tomasz Napierala 			 */
313*ec125fbbSEdward Tomasz Napierala 			if (link->rrl_exceeded != 0)
314*ec125fbbSEdward Tomasz Napierala 				continue;
315*ec125fbbSEdward Tomasz Napierala 
316*ec125fbbSEdward Tomasz Napierala 			if (!ppsratecheck(&lasttime, &curtime, 10))
317*ec125fbbSEdward Tomasz Napierala 				continue;
318*ec125fbbSEdward Tomasz Napierala 
319*ec125fbbSEdward Tomasz Napierala 			buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
320*ec125fbbSEdward Tomasz Napierala 			if (buf == NULL) {
321*ec125fbbSEdward Tomasz Napierala 				printf("rctl_enforce: out of memory\n");
322*ec125fbbSEdward Tomasz Napierala 				continue;
323*ec125fbbSEdward Tomasz Napierala 			}
324*ec125fbbSEdward Tomasz Napierala 			sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN);
325*ec125fbbSEdward Tomasz Napierala 			rctl_rule_to_sbuf(&sb, rule);
326*ec125fbbSEdward Tomasz Napierala 			sbuf_finish(&sb);
327*ec125fbbSEdward Tomasz Napierala 			printf("rctl: rule \"%s\" matched by pid %d "
328*ec125fbbSEdward Tomasz Napierala 			    "(%s), uid %d, jail %s\n", sbuf_data(&sb),
329*ec125fbbSEdward Tomasz Napierala 			    p->p_pid, p->p_comm, p->p_ucred->cr_uid,
330*ec125fbbSEdward Tomasz Napierala 			    p->p_ucred->cr_prison->pr_name);
331*ec125fbbSEdward Tomasz Napierala 			sbuf_delete(&sb);
332*ec125fbbSEdward Tomasz Napierala 			free(buf, M_RCTL);
333*ec125fbbSEdward Tomasz Napierala 			link->rrl_exceeded = 1;
334*ec125fbbSEdward Tomasz Napierala 			continue;
335*ec125fbbSEdward Tomasz Napierala 		case RCTL_ACTION_DEVCTL:
336*ec125fbbSEdward Tomasz Napierala 			if (link->rrl_exceeded != 0)
337*ec125fbbSEdward Tomasz Napierala 				continue;
338*ec125fbbSEdward Tomasz Napierala 
339*ec125fbbSEdward Tomasz Napierala 			buf = malloc(RCTL_LOG_BUFSIZE, M_RCTL, M_NOWAIT);
340*ec125fbbSEdward Tomasz Napierala 			if (buf == NULL) {
341*ec125fbbSEdward Tomasz Napierala 				printf("rctl_enforce: out of memory\n");
342*ec125fbbSEdward Tomasz Napierala 				continue;
343*ec125fbbSEdward Tomasz Napierala 			}
344*ec125fbbSEdward Tomasz Napierala 			sbuf_new(&sb, buf, RCTL_LOG_BUFSIZE, SBUF_FIXEDLEN);
345*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(&sb, "rule=");
346*ec125fbbSEdward Tomasz Napierala 			rctl_rule_to_sbuf(&sb, rule);
347*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(&sb, " pid=%d ruid=%d jail=%s",
348*ec125fbbSEdward Tomasz Napierala 			    p->p_pid, p->p_ucred->cr_ruid,
349*ec125fbbSEdward Tomasz Napierala 			    p->p_ucred->cr_prison->pr_name);
350*ec125fbbSEdward Tomasz Napierala 			sbuf_finish(&sb);
351*ec125fbbSEdward Tomasz Napierala 			devctl_notify_f("RCTL", "rule", "matched",
352*ec125fbbSEdward Tomasz Napierala 			    sbuf_data(&sb), M_NOWAIT);
353*ec125fbbSEdward Tomasz Napierala 			sbuf_delete(&sb);
354*ec125fbbSEdward Tomasz Napierala 			free(buf, M_RCTL);
355*ec125fbbSEdward Tomasz Napierala 			link->rrl_exceeded = 1;
356*ec125fbbSEdward Tomasz Napierala 			continue;
357*ec125fbbSEdward Tomasz Napierala 		default:
358*ec125fbbSEdward Tomasz Napierala 			if (link->rrl_exceeded != 0)
359*ec125fbbSEdward Tomasz Napierala 				continue;
360*ec125fbbSEdward Tomasz Napierala 
361*ec125fbbSEdward Tomasz Napierala 			KASSERT(rule->rr_action > 0 &&
362*ec125fbbSEdward Tomasz Napierala 			    rule->rr_action <= RCTL_ACTION_SIGNAL_MAX,
363*ec125fbbSEdward Tomasz Napierala 			    ("rctl_enforce: unknown action %d",
364*ec125fbbSEdward Tomasz Napierala 			     rule->rr_action));
365*ec125fbbSEdward Tomasz Napierala 
366*ec125fbbSEdward Tomasz Napierala 			/*
367*ec125fbbSEdward Tomasz Napierala 			 * We're using the fact that RCTL_ACTION_SIG* values
368*ec125fbbSEdward Tomasz Napierala 			 * are equal to their counterparts from sys/signal.h.
369*ec125fbbSEdward Tomasz Napierala 			 */
370*ec125fbbSEdward Tomasz Napierala 			psignal(p, rule->rr_action);
371*ec125fbbSEdward Tomasz Napierala 			link->rrl_exceeded = 1;
372*ec125fbbSEdward Tomasz Napierala 			continue;
373*ec125fbbSEdward Tomasz Napierala 		}
374*ec125fbbSEdward Tomasz Napierala 	}
375*ec125fbbSEdward Tomasz Napierala 
376*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
377*ec125fbbSEdward Tomasz Napierala 
378*ec125fbbSEdward Tomasz Napierala 	if (should_deny) {
379*ec125fbbSEdward Tomasz Napierala 		/*
380*ec125fbbSEdward Tomasz Napierala 		 * Return fake error code; the caller should change it
381*ec125fbbSEdward Tomasz Napierala 		 * into one proper for the situation - EFSIZ, ENOMEM etc.
382*ec125fbbSEdward Tomasz Napierala 		 */
383*ec125fbbSEdward Tomasz Napierala 		return (EDOOFUS);
384*ec125fbbSEdward Tomasz Napierala 	}
385*ec125fbbSEdward Tomasz Napierala 
386*ec125fbbSEdward Tomasz Napierala 	return (0);
387*ec125fbbSEdward Tomasz Napierala }
388*ec125fbbSEdward Tomasz Napierala 
389*ec125fbbSEdward Tomasz Napierala uint64_t
390*ec125fbbSEdward Tomasz Napierala rctl_get_limit(struct proc *p, int resource)
391*ec125fbbSEdward Tomasz Napierala {
392*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
393*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
394*ec125fbbSEdward Tomasz Napierala 	uint64_t amount = UINT64_MAX;
395*ec125fbbSEdward Tomasz Napierala 
396*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
397*ec125fbbSEdward Tomasz Napierala 
398*ec125fbbSEdward Tomasz Napierala 	/*
399*ec125fbbSEdward Tomasz Napierala 	 * There may be more than one matching rule; go through all of them.
400*ec125fbbSEdward Tomasz Napierala 	 * Denial should be done last, after logging and sending signals.
401*ec125fbbSEdward Tomasz Napierala 	 */
402*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
403*ec125fbbSEdward Tomasz Napierala 		rule = link->rrl_rule;
404*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_resource != resource)
405*ec125fbbSEdward Tomasz Napierala 			continue;
406*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_action != RCTL_ACTION_DENY)
407*ec125fbbSEdward Tomasz Napierala 			continue;
408*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_amount < amount)
409*ec125fbbSEdward Tomasz Napierala 			amount = rule->rr_amount;
410*ec125fbbSEdward Tomasz Napierala 	}
411*ec125fbbSEdward Tomasz Napierala 
412*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
413*ec125fbbSEdward Tomasz Napierala 
414*ec125fbbSEdward Tomasz Napierala 	return (amount);
415*ec125fbbSEdward Tomasz Napierala }
416*ec125fbbSEdward Tomasz Napierala 
417*ec125fbbSEdward Tomasz Napierala uint64_t
418*ec125fbbSEdward Tomasz Napierala rctl_get_available(struct proc *p, int resource)
419*ec125fbbSEdward Tomasz Napierala {
420*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
421*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
422*ec125fbbSEdward Tomasz Napierala 	int64_t available, minavailable, allocated;
423*ec125fbbSEdward Tomasz Napierala 
424*ec125fbbSEdward Tomasz Napierala 	minavailable = INT64_MAX;
425*ec125fbbSEdward Tomasz Napierala 
426*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
427*ec125fbbSEdward Tomasz Napierala 
428*ec125fbbSEdward Tomasz Napierala 	/*
429*ec125fbbSEdward Tomasz Napierala 	 * There may be more than one matching rule; go through all of them.
430*ec125fbbSEdward Tomasz Napierala 	 * Denial should be done last, after logging and sending signals.
431*ec125fbbSEdward Tomasz Napierala 	 */
432*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
433*ec125fbbSEdward Tomasz Napierala 		rule = link->rrl_rule;
434*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_resource != resource)
435*ec125fbbSEdward Tomasz Napierala 			continue;
436*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_action != RCTL_ACTION_DENY)
437*ec125fbbSEdward Tomasz Napierala 			continue;
438*ec125fbbSEdward Tomasz Napierala 		available = rctl_available_resource(p, rule);
439*ec125fbbSEdward Tomasz Napierala 		if (available < minavailable)
440*ec125fbbSEdward Tomasz Napierala 			minavailable = available;
441*ec125fbbSEdward Tomasz Napierala 	}
442*ec125fbbSEdward Tomasz Napierala 
443*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
444*ec125fbbSEdward Tomasz Napierala 
445*ec125fbbSEdward Tomasz Napierala 	/*
446*ec125fbbSEdward Tomasz Napierala 	 * XXX: Think about this _hard_.
447*ec125fbbSEdward Tomasz Napierala 	 */
448*ec125fbbSEdward Tomasz Napierala 	allocated = p->p_racct->r_resources[resource];
449*ec125fbbSEdward Tomasz Napierala 	if (minavailable < INT64_MAX - allocated)
450*ec125fbbSEdward Tomasz Napierala 		minavailable += allocated;
451*ec125fbbSEdward Tomasz Napierala 	if (minavailable < 0)
452*ec125fbbSEdward Tomasz Napierala 		minavailable = 0;
453*ec125fbbSEdward Tomasz Napierala 	return (minavailable);
454*ec125fbbSEdward Tomasz Napierala }
455*ec125fbbSEdward Tomasz Napierala 
456*ec125fbbSEdward Tomasz Napierala static int
457*ec125fbbSEdward Tomasz Napierala rctl_rule_matches(const struct rctl_rule *rule, const struct rctl_rule *filter)
458*ec125fbbSEdward Tomasz Napierala {
459*ec125fbbSEdward Tomasz Napierala 
460*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED) {
461*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject_type != filter->rr_subject_type)
462*ec125fbbSEdward Tomasz Napierala 			return (0);
463*ec125fbbSEdward Tomasz Napierala 
464*ec125fbbSEdward Tomasz Napierala 		switch (filter->rr_subject_type) {
465*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_PROCESS:
466*ec125fbbSEdward Tomasz Napierala 			if (filter->rr_subject.rs_proc != NULL &&
467*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_proc !=
468*ec125fbbSEdward Tomasz Napierala 			    filter->rr_subject.rs_proc)
469*ec125fbbSEdward Tomasz Napierala 				return (0);
470*ec125fbbSEdward Tomasz Napierala 			break;
471*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_USER:
472*ec125fbbSEdward Tomasz Napierala 			if (filter->rr_subject.rs_uip != NULL &&
473*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_uip !=
474*ec125fbbSEdward Tomasz Napierala 			    filter->rr_subject.rs_uip)
475*ec125fbbSEdward Tomasz Napierala 				return (0);
476*ec125fbbSEdward Tomasz Napierala 			break;
477*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_LOGINCLASS:
478*ec125fbbSEdward Tomasz Napierala 			if (filter->rr_subject.hr_loginclass != NULL &&
479*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.hr_loginclass !=
480*ec125fbbSEdward Tomasz Napierala 			    filter->rr_subject.hr_loginclass)
481*ec125fbbSEdward Tomasz Napierala 				return (0);
482*ec125fbbSEdward Tomasz Napierala 			break;
483*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_JAIL:
484*ec125fbbSEdward Tomasz Napierala 			if (filter->rr_subject.rs_prison != NULL &&
485*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_prison !=
486*ec125fbbSEdward Tomasz Napierala 			    filter->rr_subject.rs_prison)
487*ec125fbbSEdward Tomasz Napierala 				return (0);
488*ec125fbbSEdward Tomasz Napierala 			break;
489*ec125fbbSEdward Tomasz Napierala 		default:
490*ec125fbbSEdward Tomasz Napierala 			panic("rctl_rule_matches: unknown subject type %d",
491*ec125fbbSEdward Tomasz Napierala 			    filter->rr_subject_type);
492*ec125fbbSEdward Tomasz Napierala 		}
493*ec125fbbSEdward Tomasz Napierala 	}
494*ec125fbbSEdward Tomasz Napierala 
495*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_resource != RACCT_UNDEFINED) {
496*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_resource != filter->rr_resource)
497*ec125fbbSEdward Tomasz Napierala 			return (0);
498*ec125fbbSEdward Tomasz Napierala 	}
499*ec125fbbSEdward Tomasz Napierala 
500*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_action != RCTL_ACTION_UNDEFINED) {
501*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_action != filter->rr_action)
502*ec125fbbSEdward Tomasz Napierala 			return (0);
503*ec125fbbSEdward Tomasz Napierala 	}
504*ec125fbbSEdward Tomasz Napierala 
505*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_amount != RCTL_AMOUNT_UNDEFINED) {
506*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_amount != filter->rr_amount)
507*ec125fbbSEdward Tomasz Napierala 			return (0);
508*ec125fbbSEdward Tomasz Napierala 	}
509*ec125fbbSEdward Tomasz Napierala 
510*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_per != RCTL_SUBJECT_TYPE_UNDEFINED) {
511*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_per != filter->rr_per)
512*ec125fbbSEdward Tomasz Napierala 			return (0);
513*ec125fbbSEdward Tomasz Napierala 	}
514*ec125fbbSEdward Tomasz Napierala 
515*ec125fbbSEdward Tomasz Napierala 	return (1);
516*ec125fbbSEdward Tomasz Napierala }
517*ec125fbbSEdward Tomasz Napierala 
518*ec125fbbSEdward Tomasz Napierala static int
519*ec125fbbSEdward Tomasz Napierala str2value(const char *str, int *value, struct dict *table)
520*ec125fbbSEdward Tomasz Napierala {
521*ec125fbbSEdward Tomasz Napierala 	int i;
522*ec125fbbSEdward Tomasz Napierala 
523*ec125fbbSEdward Tomasz Napierala 	if (value == NULL)
524*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
525*ec125fbbSEdward Tomasz Napierala 
526*ec125fbbSEdward Tomasz Napierala 	for (i = 0; table[i].d_name != NULL; i++) {
527*ec125fbbSEdward Tomasz Napierala 		if (strcasecmp(table[i].d_name, str) == 0) {
528*ec125fbbSEdward Tomasz Napierala 			*value =  table[i].d_value;
529*ec125fbbSEdward Tomasz Napierala 			return (0);
530*ec125fbbSEdward Tomasz Napierala 		}
531*ec125fbbSEdward Tomasz Napierala 	}
532*ec125fbbSEdward Tomasz Napierala 
533*ec125fbbSEdward Tomasz Napierala 	return (EINVAL);
534*ec125fbbSEdward Tomasz Napierala }
535*ec125fbbSEdward Tomasz Napierala 
536*ec125fbbSEdward Tomasz Napierala static int
537*ec125fbbSEdward Tomasz Napierala str2id(const char *str, id_t *value)
538*ec125fbbSEdward Tomasz Napierala {
539*ec125fbbSEdward Tomasz Napierala 	char *end;
540*ec125fbbSEdward Tomasz Napierala 
541*ec125fbbSEdward Tomasz Napierala 	if (str == NULL)
542*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
543*ec125fbbSEdward Tomasz Napierala 
544*ec125fbbSEdward Tomasz Napierala 	*value = strtoul(str, &end, 10);
545*ec125fbbSEdward Tomasz Napierala 	if ((size_t)(end - str) != strlen(str))
546*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
547*ec125fbbSEdward Tomasz Napierala 
548*ec125fbbSEdward Tomasz Napierala 	return (0);
549*ec125fbbSEdward Tomasz Napierala }
550*ec125fbbSEdward Tomasz Napierala 
551*ec125fbbSEdward Tomasz Napierala static int
552*ec125fbbSEdward Tomasz Napierala str2int64(const char *str, int64_t *value)
553*ec125fbbSEdward Tomasz Napierala {
554*ec125fbbSEdward Tomasz Napierala 	char *end;
555*ec125fbbSEdward Tomasz Napierala 
556*ec125fbbSEdward Tomasz Napierala 	if (str == NULL)
557*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
558*ec125fbbSEdward Tomasz Napierala 
559*ec125fbbSEdward Tomasz Napierala 	*value = strtoul(str, &end, 10);
560*ec125fbbSEdward Tomasz Napierala 	if ((size_t)(end - str) != strlen(str))
561*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
562*ec125fbbSEdward Tomasz Napierala 
563*ec125fbbSEdward Tomasz Napierala 	return (0);
564*ec125fbbSEdward Tomasz Napierala }
565*ec125fbbSEdward Tomasz Napierala 
566*ec125fbbSEdward Tomasz Napierala /*
567*ec125fbbSEdward Tomasz Napierala  * Connect the rule to the racct, increasing refcount for the rule.
568*ec125fbbSEdward Tomasz Napierala  */
569*ec125fbbSEdward Tomasz Napierala static void
570*ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule(struct racct *racct, struct rctl_rule *rule)
571*ec125fbbSEdward Tomasz Napierala {
572*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
573*ec125fbbSEdward Tomasz Napierala 
574*ec125fbbSEdward Tomasz Napierala 	KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
575*ec125fbbSEdward Tomasz Napierala 
576*ec125fbbSEdward Tomasz Napierala 	rctl_rule_acquire(rule);
577*ec125fbbSEdward Tomasz Napierala 	link = uma_zalloc(rctl_rule_link_zone, M_WAITOK);
578*ec125fbbSEdward Tomasz Napierala 	link->rrl_rule = rule;
579*ec125fbbSEdward Tomasz Napierala 	link->rrl_exceeded = 0;
580*ec125fbbSEdward Tomasz Napierala 
581*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
582*ec125fbbSEdward Tomasz Napierala 	LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next);
583*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
584*ec125fbbSEdward Tomasz Napierala }
585*ec125fbbSEdward Tomasz Napierala 
586*ec125fbbSEdward Tomasz Napierala static int
587*ec125fbbSEdward Tomasz Napierala rctl_racct_add_rule_locked(struct racct *racct, struct rctl_rule *rule)
588*ec125fbbSEdward Tomasz Napierala {
589*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
590*ec125fbbSEdward Tomasz Napierala 
591*ec125fbbSEdward Tomasz Napierala 	KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
592*ec125fbbSEdward Tomasz Napierala 	rw_assert(&rctl_lock, RA_WLOCKED);
593*ec125fbbSEdward Tomasz Napierala 
594*ec125fbbSEdward Tomasz Napierala 	link = uma_zalloc(rctl_rule_link_zone, M_NOWAIT);
595*ec125fbbSEdward Tomasz Napierala 	if (link == NULL)
596*ec125fbbSEdward Tomasz Napierala 		return (ENOMEM);
597*ec125fbbSEdward Tomasz Napierala 	rctl_rule_acquire(rule);
598*ec125fbbSEdward Tomasz Napierala 	link->rrl_rule = rule;
599*ec125fbbSEdward Tomasz Napierala 	link->rrl_exceeded = 0;
600*ec125fbbSEdward Tomasz Napierala 
601*ec125fbbSEdward Tomasz Napierala 	LIST_INSERT_HEAD(&racct->r_rule_links, link, rrl_next);
602*ec125fbbSEdward Tomasz Napierala 	return (0);
603*ec125fbbSEdward Tomasz Napierala }
604*ec125fbbSEdward Tomasz Napierala 
605*ec125fbbSEdward Tomasz Napierala /*
606*ec125fbbSEdward Tomasz Napierala  * Remove limits for a rules matching the filter and release
607*ec125fbbSEdward Tomasz Napierala  * the refcounts for the rules, possibly freeing them.  Returns
608*ec125fbbSEdward Tomasz Napierala  * the number of limit structures removed.
609*ec125fbbSEdward Tomasz Napierala  */
610*ec125fbbSEdward Tomasz Napierala static int
611*ec125fbbSEdward Tomasz Napierala rctl_racct_remove_rules(struct racct *racct,
612*ec125fbbSEdward Tomasz Napierala     const struct rctl_rule *filter)
613*ec125fbbSEdward Tomasz Napierala {
614*ec125fbbSEdward Tomasz Napierala 	int removed = 0;
615*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link, *linktmp;
616*ec125fbbSEdward Tomasz Napierala 
617*ec125fbbSEdward Tomasz Napierala 	rw_assert(&rctl_lock, RA_WLOCKED);
618*ec125fbbSEdward Tomasz Napierala 
619*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH_SAFE(link, &racct->r_rule_links, rrl_next, linktmp) {
620*ec125fbbSEdward Tomasz Napierala 		if (!rctl_rule_matches(link->rrl_rule, filter))
621*ec125fbbSEdward Tomasz Napierala 			continue;
622*ec125fbbSEdward Tomasz Napierala 
623*ec125fbbSEdward Tomasz Napierala 		LIST_REMOVE(link, rrl_next);
624*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(link->rrl_rule);
625*ec125fbbSEdward Tomasz Napierala 		uma_zfree(rctl_rule_link_zone, link);
626*ec125fbbSEdward Tomasz Napierala 		removed++;
627*ec125fbbSEdward Tomasz Napierala 	}
628*ec125fbbSEdward Tomasz Napierala 	return (removed);
629*ec125fbbSEdward Tomasz Napierala }
630*ec125fbbSEdward Tomasz Napierala 
631*ec125fbbSEdward Tomasz Napierala static void
632*ec125fbbSEdward Tomasz Napierala rctl_rule_acquire_subject(struct rctl_rule *rule)
633*ec125fbbSEdward Tomasz Napierala {
634*ec125fbbSEdward Tomasz Napierala 
635*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_subject_type) {
636*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_UNDEFINED:
637*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
638*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
639*ec125fbbSEdward Tomasz Napierala 		break;
640*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
641*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_uip != NULL)
642*ec125fbbSEdward Tomasz Napierala 			uihold(rule->rr_subject.rs_uip);
643*ec125fbbSEdward Tomasz Napierala 		break;
644*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
645*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.hr_loginclass != NULL)
646*ec125fbbSEdward Tomasz Napierala 			loginclass_hold(rule->rr_subject.hr_loginclass);
647*ec125fbbSEdward Tomasz Napierala 		break;
648*ec125fbbSEdward Tomasz Napierala 	default:
649*ec125fbbSEdward Tomasz Napierala 		panic("rctl_rule_acquire_subject: unknown subject type %d",
650*ec125fbbSEdward Tomasz Napierala 		    rule->rr_subject_type);
651*ec125fbbSEdward Tomasz Napierala 	}
652*ec125fbbSEdward Tomasz Napierala }
653*ec125fbbSEdward Tomasz Napierala 
654*ec125fbbSEdward Tomasz Napierala static void
655*ec125fbbSEdward Tomasz Napierala rctl_rule_release_subject(struct rctl_rule *rule)
656*ec125fbbSEdward Tomasz Napierala {
657*ec125fbbSEdward Tomasz Napierala 
658*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_subject_type) {
659*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_UNDEFINED:
660*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
661*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
662*ec125fbbSEdward Tomasz Napierala 		break;
663*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
664*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_uip != NULL)
665*ec125fbbSEdward Tomasz Napierala 			uifree(rule->rr_subject.rs_uip);
666*ec125fbbSEdward Tomasz Napierala 		break;
667*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
668*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.hr_loginclass != NULL)
669*ec125fbbSEdward Tomasz Napierala 			loginclass_free(rule->rr_subject.hr_loginclass);
670*ec125fbbSEdward Tomasz Napierala 		break;
671*ec125fbbSEdward Tomasz Napierala 	default:
672*ec125fbbSEdward Tomasz Napierala 		panic("rctl_rule_release_subject: unknown subject type %d",
673*ec125fbbSEdward Tomasz Napierala 		    rule->rr_subject_type);
674*ec125fbbSEdward Tomasz Napierala 	}
675*ec125fbbSEdward Tomasz Napierala }
676*ec125fbbSEdward Tomasz Napierala 
677*ec125fbbSEdward Tomasz Napierala struct rctl_rule *
678*ec125fbbSEdward Tomasz Napierala rctl_rule_alloc(int flags)
679*ec125fbbSEdward Tomasz Napierala {
680*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
681*ec125fbbSEdward Tomasz Napierala 
682*ec125fbbSEdward Tomasz Napierala 	rule = uma_zalloc(rctl_rule_zone, flags);
683*ec125fbbSEdward Tomasz Napierala 	if (rule == NULL)
684*ec125fbbSEdward Tomasz Napierala 		return (NULL);
685*ec125fbbSEdward Tomasz Napierala 	rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED;
686*ec125fbbSEdward Tomasz Napierala 	rule->rr_subject.rs_proc = NULL;
687*ec125fbbSEdward Tomasz Napierala 	rule->rr_subject.rs_uip = NULL;
688*ec125fbbSEdward Tomasz Napierala 	rule->rr_subject.hr_loginclass = NULL;
689*ec125fbbSEdward Tomasz Napierala 	rule->rr_subject.rs_prison = NULL;
690*ec125fbbSEdward Tomasz Napierala 	rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED;
691*ec125fbbSEdward Tomasz Napierala 	rule->rr_resource = RACCT_UNDEFINED;
692*ec125fbbSEdward Tomasz Napierala 	rule->rr_action = RCTL_ACTION_UNDEFINED;
693*ec125fbbSEdward Tomasz Napierala 	rule->rr_amount = RCTL_AMOUNT_UNDEFINED;
694*ec125fbbSEdward Tomasz Napierala 	refcount_init(&rule->rr_refcount, 1);
695*ec125fbbSEdward Tomasz Napierala 
696*ec125fbbSEdward Tomasz Napierala 	return (rule);
697*ec125fbbSEdward Tomasz Napierala }
698*ec125fbbSEdward Tomasz Napierala 
699*ec125fbbSEdward Tomasz Napierala struct rctl_rule *
700*ec125fbbSEdward Tomasz Napierala rctl_rule_duplicate(const struct rctl_rule *rule, int flags)
701*ec125fbbSEdward Tomasz Napierala {
702*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *copy;
703*ec125fbbSEdward Tomasz Napierala 
704*ec125fbbSEdward Tomasz Napierala 	copy = uma_zalloc(rctl_rule_zone, flags);
705*ec125fbbSEdward Tomasz Napierala 	if (copy == NULL)
706*ec125fbbSEdward Tomasz Napierala 		return (NULL);
707*ec125fbbSEdward Tomasz Napierala 	copy->rr_subject_type = rule->rr_subject_type;
708*ec125fbbSEdward Tomasz Napierala 	copy->rr_subject.rs_proc = rule->rr_subject.rs_proc;
709*ec125fbbSEdward Tomasz Napierala 	copy->rr_subject.rs_uip = rule->rr_subject.rs_uip;
710*ec125fbbSEdward Tomasz Napierala 	copy->rr_subject.hr_loginclass = rule->rr_subject.hr_loginclass;
711*ec125fbbSEdward Tomasz Napierala 	copy->rr_subject.rs_prison = rule->rr_subject.rs_prison;
712*ec125fbbSEdward Tomasz Napierala 	copy->rr_per = rule->rr_per;
713*ec125fbbSEdward Tomasz Napierala 	copy->rr_resource = rule->rr_resource;
714*ec125fbbSEdward Tomasz Napierala 	copy->rr_action = rule->rr_action;
715*ec125fbbSEdward Tomasz Napierala 	copy->rr_amount = rule->rr_amount;
716*ec125fbbSEdward Tomasz Napierala 	refcount_init(&copy->rr_refcount, 1);
717*ec125fbbSEdward Tomasz Napierala 	rctl_rule_acquire_subject(copy);
718*ec125fbbSEdward Tomasz Napierala 
719*ec125fbbSEdward Tomasz Napierala 	return (copy);
720*ec125fbbSEdward Tomasz Napierala }
721*ec125fbbSEdward Tomasz Napierala 
722*ec125fbbSEdward Tomasz Napierala void
723*ec125fbbSEdward Tomasz Napierala rctl_rule_acquire(struct rctl_rule *rule)
724*ec125fbbSEdward Tomasz Napierala {
725*ec125fbbSEdward Tomasz Napierala 
726*ec125fbbSEdward Tomasz Napierala 	KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
727*ec125fbbSEdward Tomasz Napierala 
728*ec125fbbSEdward Tomasz Napierala 	refcount_acquire(&rule->rr_refcount);
729*ec125fbbSEdward Tomasz Napierala }
730*ec125fbbSEdward Tomasz Napierala 
731*ec125fbbSEdward Tomasz Napierala static void
732*ec125fbbSEdward Tomasz Napierala rctl_rule_free(void *context, int pending)
733*ec125fbbSEdward Tomasz Napierala {
734*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
735*ec125fbbSEdward Tomasz Napierala 
736*ec125fbbSEdward Tomasz Napierala 	rule = (struct rctl_rule *)context;
737*ec125fbbSEdward Tomasz Napierala 
738*ec125fbbSEdward Tomasz Napierala 	KASSERT(rule->rr_refcount == 0, ("rule->rr_refcount != 0"));
739*ec125fbbSEdward Tomasz Napierala 
740*ec125fbbSEdward Tomasz Napierala 	/*
741*ec125fbbSEdward Tomasz Napierala 	 * We don't need locking here; rule is guaranteed to be inaccessible.
742*ec125fbbSEdward Tomasz Napierala 	 */
743*ec125fbbSEdward Tomasz Napierala 
744*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release_subject(rule);
745*ec125fbbSEdward Tomasz Napierala 	uma_zfree(rctl_rule_zone, rule);
746*ec125fbbSEdward Tomasz Napierala }
747*ec125fbbSEdward Tomasz Napierala 
748*ec125fbbSEdward Tomasz Napierala void
749*ec125fbbSEdward Tomasz Napierala rctl_rule_release(struct rctl_rule *rule)
750*ec125fbbSEdward Tomasz Napierala {
751*ec125fbbSEdward Tomasz Napierala 
752*ec125fbbSEdward Tomasz Napierala 	KASSERT(rule->rr_refcount > 0, ("rule->rr_refcount <= 0"));
753*ec125fbbSEdward Tomasz Napierala 
754*ec125fbbSEdward Tomasz Napierala 	if (refcount_release(&rule->rr_refcount)) {
755*ec125fbbSEdward Tomasz Napierala 		/*
756*ec125fbbSEdward Tomasz Napierala 		 * rctl_rule_release() is often called when iterating
757*ec125fbbSEdward Tomasz Napierala 		 * over all the uidinfo structures in the system,
758*ec125fbbSEdward Tomasz Napierala 		 * holding uihashtbl_lock.  Since rctl_rule_free()
759*ec125fbbSEdward Tomasz Napierala 		 * might end up calling uifree(), this would lead
760*ec125fbbSEdward Tomasz Napierala 		 * to lock recursion.  Use taskqueue to avoid this.
761*ec125fbbSEdward Tomasz Napierala 		 */
762*ec125fbbSEdward Tomasz Napierala 		TASK_INIT(&rule->rr_task, 0, rctl_rule_free, rule);
763*ec125fbbSEdward Tomasz Napierala 		taskqueue_enqueue(taskqueue_thread, &rule->rr_task);
764*ec125fbbSEdward Tomasz Napierala 	}
765*ec125fbbSEdward Tomasz Napierala }
766*ec125fbbSEdward Tomasz Napierala 
767*ec125fbbSEdward Tomasz Napierala static int
768*ec125fbbSEdward Tomasz Napierala rctl_rule_fully_specified(const struct rctl_rule *rule)
769*ec125fbbSEdward Tomasz Napierala {
770*ec125fbbSEdward Tomasz Napierala 
771*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_subject_type) {
772*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_UNDEFINED:
773*ec125fbbSEdward Tomasz Napierala 		return (0);
774*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
775*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_proc == NULL)
776*ec125fbbSEdward Tomasz Napierala 			return (0);
777*ec125fbbSEdward Tomasz Napierala 		break;
778*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
779*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_uip == NULL)
780*ec125fbbSEdward Tomasz Napierala 			return (0);
781*ec125fbbSEdward Tomasz Napierala 		break;
782*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
783*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.hr_loginclass == NULL)
784*ec125fbbSEdward Tomasz Napierala 			return (0);
785*ec125fbbSEdward Tomasz Napierala 		break;
786*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
787*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_prison == NULL)
788*ec125fbbSEdward Tomasz Napierala 			return (0);
789*ec125fbbSEdward Tomasz Napierala 		break;
790*ec125fbbSEdward Tomasz Napierala 	default:
791*ec125fbbSEdward Tomasz Napierala 		panic("rctl_rule_fully_specified: unknown subject type %d",
792*ec125fbbSEdward Tomasz Napierala 		    rule->rr_subject_type);
793*ec125fbbSEdward Tomasz Napierala 	}
794*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_resource == RACCT_UNDEFINED)
795*ec125fbbSEdward Tomasz Napierala 		return (0);
796*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_action == RCTL_ACTION_UNDEFINED)
797*ec125fbbSEdward Tomasz Napierala 		return (0);
798*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_amount == RCTL_AMOUNT_UNDEFINED)
799*ec125fbbSEdward Tomasz Napierala 		return (0);
800*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED)
801*ec125fbbSEdward Tomasz Napierala 		return (0);
802*ec125fbbSEdward Tomasz Napierala 
803*ec125fbbSEdward Tomasz Napierala 	return (1);
804*ec125fbbSEdward Tomasz Napierala }
805*ec125fbbSEdward Tomasz Napierala 
806*ec125fbbSEdward Tomasz Napierala static int
807*ec125fbbSEdward Tomasz Napierala rctl_string_to_rule(char *rulestr, struct rctl_rule **rulep)
808*ec125fbbSEdward Tomasz Napierala {
809*ec125fbbSEdward Tomasz Napierala 	int error = 0;
810*ec125fbbSEdward Tomasz Napierala 	char *subjectstr, *subject_idstr, *resourcestr, *actionstr,
811*ec125fbbSEdward Tomasz Napierala 	     *amountstr, *perstr;
812*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
813*ec125fbbSEdward Tomasz Napierala 	id_t id;
814*ec125fbbSEdward Tomasz Napierala 
815*ec125fbbSEdward Tomasz Napierala 	rule = rctl_rule_alloc(M_WAITOK);
816*ec125fbbSEdward Tomasz Napierala 
817*ec125fbbSEdward Tomasz Napierala 	subjectstr = strsep(&rulestr, ":");
818*ec125fbbSEdward Tomasz Napierala 	subject_idstr = strsep(&rulestr, ":");
819*ec125fbbSEdward Tomasz Napierala 	resourcestr = strsep(&rulestr, ":");
820*ec125fbbSEdward Tomasz Napierala 	actionstr = strsep(&rulestr, "=/");
821*ec125fbbSEdward Tomasz Napierala 	amountstr = strsep(&rulestr, "/");
822*ec125fbbSEdward Tomasz Napierala 	perstr = rulestr;
823*ec125fbbSEdward Tomasz Napierala 
824*ec125fbbSEdward Tomasz Napierala 	if (subjectstr == NULL || subjectstr[0] == '\0')
825*ec125fbbSEdward Tomasz Napierala 		rule->rr_subject_type = RCTL_SUBJECT_TYPE_UNDEFINED;
826*ec125fbbSEdward Tomasz Napierala 	else {
827*ec125fbbSEdward Tomasz Napierala 		error = str2value(subjectstr, &rule->rr_subject_type, subjectnames);
828*ec125fbbSEdward Tomasz Napierala 		if (error != 0)
829*ec125fbbSEdward Tomasz Napierala 			goto out;
830*ec125fbbSEdward Tomasz Napierala 	}
831*ec125fbbSEdward Tomasz Napierala 
832*ec125fbbSEdward Tomasz Napierala 	if (subject_idstr == NULL || subject_idstr[0] == '\0') {
833*ec125fbbSEdward Tomasz Napierala 		rule->rr_subject.rs_proc = NULL;
834*ec125fbbSEdward Tomasz Napierala 		rule->rr_subject.rs_uip = NULL;
835*ec125fbbSEdward Tomasz Napierala 		rule->rr_subject.hr_loginclass = NULL;
836*ec125fbbSEdward Tomasz Napierala 		rule->rr_subject.rs_prison = NULL;
837*ec125fbbSEdward Tomasz Napierala 	} else {
838*ec125fbbSEdward Tomasz Napierala 		switch (rule->rr_subject_type) {
839*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_UNDEFINED:
840*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
841*ec125fbbSEdward Tomasz Napierala 			goto out;
842*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_PROCESS:
843*ec125fbbSEdward Tomasz Napierala 			error = str2id(subject_idstr, &id);
844*ec125fbbSEdward Tomasz Napierala 			if (error != 0)
845*ec125fbbSEdward Tomasz Napierala 				goto out;
846*ec125fbbSEdward Tomasz Napierala 			sx_assert(&allproc_lock, SA_LOCKED);
847*ec125fbbSEdward Tomasz Napierala 			rule->rr_subject.rs_proc = pfind(id);
848*ec125fbbSEdward Tomasz Napierala 			if (rule->rr_subject.rs_proc == NULL) {
849*ec125fbbSEdward Tomasz Napierala 				error = ESRCH;
850*ec125fbbSEdward Tomasz Napierala 				goto out;
851*ec125fbbSEdward Tomasz Napierala 			}
852*ec125fbbSEdward Tomasz Napierala 			PROC_UNLOCK(rule->rr_subject.rs_proc);
853*ec125fbbSEdward Tomasz Napierala 			break;
854*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_USER:
855*ec125fbbSEdward Tomasz Napierala 			error = str2id(subject_idstr, &id);
856*ec125fbbSEdward Tomasz Napierala 			if (error != 0)
857*ec125fbbSEdward Tomasz Napierala 				goto out;
858*ec125fbbSEdward Tomasz Napierala 			rule->rr_subject.rs_uip = uifind(id);
859*ec125fbbSEdward Tomasz Napierala 			break;
860*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_LOGINCLASS:
861*ec125fbbSEdward Tomasz Napierala 			rule->rr_subject.hr_loginclass =
862*ec125fbbSEdward Tomasz Napierala 			    loginclass_find(subject_idstr);
863*ec125fbbSEdward Tomasz Napierala 			if (rule->rr_subject.hr_loginclass == NULL) {
864*ec125fbbSEdward Tomasz Napierala 				error = ENAMETOOLONG;
865*ec125fbbSEdward Tomasz Napierala 				goto out;
866*ec125fbbSEdward Tomasz Napierala 			}
867*ec125fbbSEdward Tomasz Napierala 			break;
868*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_JAIL:
869*ec125fbbSEdward Tomasz Napierala 			rule->rr_subject.rs_prison =
870*ec125fbbSEdward Tomasz Napierala 			    prison_find_name(&prison0, subject_idstr);
871*ec125fbbSEdward Tomasz Napierala 			if (rule->rr_subject.rs_prison == NULL) {
872*ec125fbbSEdward Tomasz Napierala 				/*
873*ec125fbbSEdward Tomasz Napierala 				 * No jail with that name; try with the JID.
874*ec125fbbSEdward Tomasz Napierala 				 */
875*ec125fbbSEdward Tomasz Napierala 				error = str2id(subject_idstr, &id);
876*ec125fbbSEdward Tomasz Napierala 				if (error != 0)
877*ec125fbbSEdward Tomasz Napierala 					goto out;
878*ec125fbbSEdward Tomasz Napierala 				rule->rr_subject.rs_prison = prison_find(id);
879*ec125fbbSEdward Tomasz Napierala 				if (rule->rr_subject.rs_prison == NULL) {
880*ec125fbbSEdward Tomasz Napierala 					error = ESRCH;
881*ec125fbbSEdward Tomasz Napierala 					goto out;
882*ec125fbbSEdward Tomasz Napierala 				}
883*ec125fbbSEdward Tomasz Napierala 			}
884*ec125fbbSEdward Tomasz Napierala 			/* prison_find() returns with mutex held. */
885*ec125fbbSEdward Tomasz Napierala 			mtx_unlock(&rule->rr_subject.rs_prison->pr_mtx);
886*ec125fbbSEdward Tomasz Napierala 			break;
887*ec125fbbSEdward Tomasz Napierala                default:
888*ec125fbbSEdward Tomasz Napierala                        panic("rctl_string_to_rule: unknown subject type %d",
889*ec125fbbSEdward Tomasz Napierala                            rule->rr_subject_type);
890*ec125fbbSEdward Tomasz Napierala                }
891*ec125fbbSEdward Tomasz Napierala 	}
892*ec125fbbSEdward Tomasz Napierala 
893*ec125fbbSEdward Tomasz Napierala 	if (resourcestr == NULL || resourcestr[0] == '\0')
894*ec125fbbSEdward Tomasz Napierala 		rule->rr_resource = RACCT_UNDEFINED;
895*ec125fbbSEdward Tomasz Napierala 	else {
896*ec125fbbSEdward Tomasz Napierala 		error = str2value(resourcestr, &rule->rr_resource,
897*ec125fbbSEdward Tomasz Napierala 		    resourcenames);
898*ec125fbbSEdward Tomasz Napierala 		if (error != 0)
899*ec125fbbSEdward Tomasz Napierala 			goto out;
900*ec125fbbSEdward Tomasz Napierala 	}
901*ec125fbbSEdward Tomasz Napierala 
902*ec125fbbSEdward Tomasz Napierala 	if (actionstr == NULL || actionstr[0] == '\0')
903*ec125fbbSEdward Tomasz Napierala 		rule->rr_action = RCTL_ACTION_UNDEFINED;
904*ec125fbbSEdward Tomasz Napierala 	else {
905*ec125fbbSEdward Tomasz Napierala 		error = str2value(actionstr, &rule->rr_action, actionnames);
906*ec125fbbSEdward Tomasz Napierala 		if (error != 0)
907*ec125fbbSEdward Tomasz Napierala 			goto out;
908*ec125fbbSEdward Tomasz Napierala 	}
909*ec125fbbSEdward Tomasz Napierala 
910*ec125fbbSEdward Tomasz Napierala 	if (amountstr == NULL || amountstr[0] == '\0')
911*ec125fbbSEdward Tomasz Napierala 		rule->rr_amount = RCTL_AMOUNT_UNDEFINED;
912*ec125fbbSEdward Tomasz Napierala 	else {
913*ec125fbbSEdward Tomasz Napierala 		error = str2int64(amountstr, &rule->rr_amount);
914*ec125fbbSEdward Tomasz Napierala 		if (error != 0)
915*ec125fbbSEdward Tomasz Napierala 			goto out;
916*ec125fbbSEdward Tomasz Napierala 		if (racct_is_in_thousands(rule->rr_resource))
917*ec125fbbSEdward Tomasz Napierala 			rule->rr_amount *= 1000;
918*ec125fbbSEdward Tomasz Napierala 	}
919*ec125fbbSEdward Tomasz Napierala 
920*ec125fbbSEdward Tomasz Napierala 	if (perstr == NULL || perstr[0] == '\0')
921*ec125fbbSEdward Tomasz Napierala 		rule->rr_per = RCTL_SUBJECT_TYPE_UNDEFINED;
922*ec125fbbSEdward Tomasz Napierala 	else {
923*ec125fbbSEdward Tomasz Napierala 		error = str2value(perstr, &rule->rr_per, subjectnames);
924*ec125fbbSEdward Tomasz Napierala 		if (error != 0)
925*ec125fbbSEdward Tomasz Napierala 			goto out;
926*ec125fbbSEdward Tomasz Napierala 	}
927*ec125fbbSEdward Tomasz Napierala 
928*ec125fbbSEdward Tomasz Napierala out:
929*ec125fbbSEdward Tomasz Napierala 	if (error == 0)
930*ec125fbbSEdward Tomasz Napierala 		*rulep = rule;
931*ec125fbbSEdward Tomasz Napierala 	else
932*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(rule);
933*ec125fbbSEdward Tomasz Napierala 
934*ec125fbbSEdward Tomasz Napierala 	return (error);
935*ec125fbbSEdward Tomasz Napierala }
936*ec125fbbSEdward Tomasz Napierala 
937*ec125fbbSEdward Tomasz Napierala /*
938*ec125fbbSEdward Tomasz Napierala  * Link a rule with all the subjects it applies to.
939*ec125fbbSEdward Tomasz Napierala  */
940*ec125fbbSEdward Tomasz Napierala int
941*ec125fbbSEdward Tomasz Napierala rctl_rule_add(struct rctl_rule *rule)
942*ec125fbbSEdward Tomasz Napierala {
943*ec125fbbSEdward Tomasz Napierala 	struct proc *p;
944*ec125fbbSEdward Tomasz Napierala 	struct ucred *cred;
945*ec125fbbSEdward Tomasz Napierala 	struct uidinfo *uip;
946*ec125fbbSEdward Tomasz Napierala 	struct prison *pr;
947*ec125fbbSEdward Tomasz Napierala 	struct loginclass *lc;
948*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule2;
949*ec125fbbSEdward Tomasz Napierala 	int match;
950*ec125fbbSEdward Tomasz Napierala 
951*ec125fbbSEdward Tomasz Napierala 	KASSERT(rctl_rule_fully_specified(rule), ("rule not fully specified"));
952*ec125fbbSEdward Tomasz Napierala 
953*ec125fbbSEdward Tomasz Napierala 	/*
954*ec125fbbSEdward Tomasz Napierala 	 * Some rules just don't make sense.  Note that the one below
955*ec125fbbSEdward Tomasz Napierala 	 * cannot be rewritten using racct_is_deniable(); the RACCT_PCTCPU,
956*ec125fbbSEdward Tomasz Napierala 	 * for example, is not deniable in the racct sense, but the
957*ec125fbbSEdward Tomasz Napierala 	 * limit is enforced in a different way, so "deny" rules for %CPU
958*ec125fbbSEdward Tomasz Napierala 	 * do make sense.
959*ec125fbbSEdward Tomasz Napierala 	 */
960*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_action == RCTL_ACTION_DENY &&
961*ec125fbbSEdward Tomasz Napierala 	    (rule->rr_resource == RACCT_CPU ||
962*ec125fbbSEdward Tomasz Napierala 	    rule->rr_resource == RACCT_WALLCLOCK))
963*ec125fbbSEdward Tomasz Napierala 		return (EOPNOTSUPP);
964*ec125fbbSEdward Tomasz Napierala 
965*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_per == RCTL_SUBJECT_TYPE_PROCESS &&
966*ec125fbbSEdward Tomasz Napierala 	    racct_is_sloppy(rule->rr_resource))
967*ec125fbbSEdward Tomasz Napierala 		return (EOPNOTSUPP);
968*ec125fbbSEdward Tomasz Napierala 
969*ec125fbbSEdward Tomasz Napierala 	/*
970*ec125fbbSEdward Tomasz Napierala 	 * Make sure there are no duplicated rules.  Also, for the "deny"
971*ec125fbbSEdward Tomasz Napierala 	 * rules, remove ones differing only by "amount".
972*ec125fbbSEdward Tomasz Napierala 	 */
973*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_action == RCTL_ACTION_DENY) {
974*ec125fbbSEdward Tomasz Napierala 		rule2 = rctl_rule_duplicate(rule, M_WAITOK);
975*ec125fbbSEdward Tomasz Napierala 		rule2->rr_amount = RCTL_AMOUNT_UNDEFINED;
976*ec125fbbSEdward Tomasz Napierala 		rctl_rule_remove(rule2);
977*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(rule2);
978*ec125fbbSEdward Tomasz Napierala 	} else
979*ec125fbbSEdward Tomasz Napierala 		rctl_rule_remove(rule);
980*ec125fbbSEdward Tomasz Napierala 
981*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_subject_type) {
982*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
983*ec125fbbSEdward Tomasz Napierala 		p = rule->rr_subject.rs_proc;
984*ec125fbbSEdward Tomasz Napierala 		KASSERT(p != NULL, ("rctl_rule_add: NULL proc"));
985*ec125fbbSEdward Tomasz Napierala 		/*
986*ec125fbbSEdward Tomasz Napierala 		 * No resource limits for system processes.
987*ec125fbbSEdward Tomasz Napierala 		 */
988*ec125fbbSEdward Tomasz Napierala 		if (p->p_flag & P_SYSTEM)
989*ec125fbbSEdward Tomasz Napierala 			return (EPERM);
990*ec125fbbSEdward Tomasz Napierala 
991*ec125fbbSEdward Tomasz Napierala 		rctl_racct_add_rule(p->p_racct, rule);
992*ec125fbbSEdward Tomasz Napierala 		/*
993*ec125fbbSEdward Tomasz Napierala 		 * In case of per-process rule, we don't have anything more
994*ec125fbbSEdward Tomasz Napierala 		 * to do.
995*ec125fbbSEdward Tomasz Napierala 		 */
996*ec125fbbSEdward Tomasz Napierala 		return (0);
997*ec125fbbSEdward Tomasz Napierala 
998*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
999*ec125fbbSEdward Tomasz Napierala 		uip = rule->rr_subject.rs_uip;
1000*ec125fbbSEdward Tomasz Napierala 		KASSERT(uip != NULL, ("rctl_rule_add: NULL uip"));
1001*ec125fbbSEdward Tomasz Napierala 		rctl_racct_add_rule(uip->ui_racct, rule);
1002*ec125fbbSEdward Tomasz Napierala 		break;
1003*ec125fbbSEdward Tomasz Napierala 
1004*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
1005*ec125fbbSEdward Tomasz Napierala 		lc = rule->rr_subject.hr_loginclass;
1006*ec125fbbSEdward Tomasz Napierala 		KASSERT(lc != NULL, ("rctl_rule_add: NULL loginclass"));
1007*ec125fbbSEdward Tomasz Napierala 		rctl_racct_add_rule(lc->lc_racct, rule);
1008*ec125fbbSEdward Tomasz Napierala 		break;
1009*ec125fbbSEdward Tomasz Napierala 
1010*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
1011*ec125fbbSEdward Tomasz Napierala 		pr = rule->rr_subject.rs_prison;
1012*ec125fbbSEdward Tomasz Napierala 		KASSERT(pr != NULL, ("rctl_rule_add: NULL pr"));
1013*ec125fbbSEdward Tomasz Napierala 		rctl_racct_add_rule(pr->pr_racct, rule);
1014*ec125fbbSEdward Tomasz Napierala 		break;
1015*ec125fbbSEdward Tomasz Napierala 
1016*ec125fbbSEdward Tomasz Napierala 	default:
1017*ec125fbbSEdward Tomasz Napierala 		panic("rctl_rule_add: unknown subject type %d",
1018*ec125fbbSEdward Tomasz Napierala 		    rule->rr_subject_type);
1019*ec125fbbSEdward Tomasz Napierala 	}
1020*ec125fbbSEdward Tomasz Napierala 
1021*ec125fbbSEdward Tomasz Napierala 	/*
1022*ec125fbbSEdward Tomasz Napierala 	 * Now go through all the processes and add the new rule to the ones
1023*ec125fbbSEdward Tomasz Napierala 	 * it applies to.
1024*ec125fbbSEdward Tomasz Napierala 	 */
1025*ec125fbbSEdward Tomasz Napierala 	sx_assert(&allproc_lock, SA_LOCKED);
1026*ec125fbbSEdward Tomasz Napierala 	FOREACH_PROC_IN_SYSTEM(p) {
1027*ec125fbbSEdward Tomasz Napierala 		if (p->p_flag & P_SYSTEM)
1028*ec125fbbSEdward Tomasz Napierala 			continue;
1029*ec125fbbSEdward Tomasz Napierala 		cred = p->p_ucred;
1030*ec125fbbSEdward Tomasz Napierala 		switch (rule->rr_subject_type) {
1031*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_USER:
1032*ec125fbbSEdward Tomasz Napierala 			if (cred->cr_uidinfo == rule->rr_subject.rs_uip ||
1033*ec125fbbSEdward Tomasz Napierala 			    cred->cr_ruidinfo == rule->rr_subject.rs_uip)
1034*ec125fbbSEdward Tomasz Napierala 				break;
1035*ec125fbbSEdward Tomasz Napierala 			continue;
1036*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_LOGINCLASS:
1037*ec125fbbSEdward Tomasz Napierala 			if (cred->cr_loginclass == rule->rr_subject.hr_loginclass)
1038*ec125fbbSEdward Tomasz Napierala 				break;
1039*ec125fbbSEdward Tomasz Napierala 			continue;
1040*ec125fbbSEdward Tomasz Napierala 		case RCTL_SUBJECT_TYPE_JAIL:
1041*ec125fbbSEdward Tomasz Napierala 			match = 0;
1042*ec125fbbSEdward Tomasz Napierala 			for (pr = cred->cr_prison; pr != NULL; pr = pr->pr_parent) {
1043*ec125fbbSEdward Tomasz Napierala 				if (pr == rule->rr_subject.rs_prison) {
1044*ec125fbbSEdward Tomasz Napierala 					match = 1;
1045*ec125fbbSEdward Tomasz Napierala 					break;
1046*ec125fbbSEdward Tomasz Napierala 				}
1047*ec125fbbSEdward Tomasz Napierala 			}
1048*ec125fbbSEdward Tomasz Napierala 			if (match)
1049*ec125fbbSEdward Tomasz Napierala 				break;
1050*ec125fbbSEdward Tomasz Napierala 			continue;
1051*ec125fbbSEdward Tomasz Napierala 		default:
1052*ec125fbbSEdward Tomasz Napierala 			panic("rctl_rule_add: unknown subject type %d",
1053*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject_type);
1054*ec125fbbSEdward Tomasz Napierala 		}
1055*ec125fbbSEdward Tomasz Napierala 
1056*ec125fbbSEdward Tomasz Napierala 		rctl_racct_add_rule(p->p_racct, rule);
1057*ec125fbbSEdward Tomasz Napierala 	}
1058*ec125fbbSEdward Tomasz Napierala 
1059*ec125fbbSEdward Tomasz Napierala 	return (0);
1060*ec125fbbSEdward Tomasz Napierala }
1061*ec125fbbSEdward Tomasz Napierala 
1062*ec125fbbSEdward Tomasz Napierala static void
1063*ec125fbbSEdward Tomasz Napierala rctl_rule_remove_callback(struct racct *racct, void *arg2, void *arg3)
1064*ec125fbbSEdward Tomasz Napierala {
1065*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter = (struct rctl_rule *)arg2;
1066*ec125fbbSEdward Tomasz Napierala 	int found = 0;
1067*ec125fbbSEdward Tomasz Napierala 
1068*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
1069*ec125fbbSEdward Tomasz Napierala 	found += rctl_racct_remove_rules(racct, filter);
1070*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1071*ec125fbbSEdward Tomasz Napierala 
1072*ec125fbbSEdward Tomasz Napierala 	*((int *)arg3) += found;
1073*ec125fbbSEdward Tomasz Napierala }
1074*ec125fbbSEdward Tomasz Napierala 
1075*ec125fbbSEdward Tomasz Napierala /*
1076*ec125fbbSEdward Tomasz Napierala  * Remove all rules that match the filter.
1077*ec125fbbSEdward Tomasz Napierala  */
1078*ec125fbbSEdward Tomasz Napierala int
1079*ec125fbbSEdward Tomasz Napierala rctl_rule_remove(struct rctl_rule *filter)
1080*ec125fbbSEdward Tomasz Napierala {
1081*ec125fbbSEdward Tomasz Napierala 	int found = 0;
1082*ec125fbbSEdward Tomasz Napierala 	struct proc *p;
1083*ec125fbbSEdward Tomasz Napierala 
1084*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_PROCESS &&
1085*ec125fbbSEdward Tomasz Napierala 	    filter->rr_subject.rs_proc != NULL) {
1086*ec125fbbSEdward Tomasz Napierala 		p = filter->rr_subject.rs_proc;
1087*ec125fbbSEdward Tomasz Napierala 		rw_wlock(&rctl_lock);
1088*ec125fbbSEdward Tomasz Napierala 		found = rctl_racct_remove_rules(p->p_racct, filter);
1089*ec125fbbSEdward Tomasz Napierala 		rw_wunlock(&rctl_lock);
1090*ec125fbbSEdward Tomasz Napierala 		if (found)
1091*ec125fbbSEdward Tomasz Napierala 			return (0);
1092*ec125fbbSEdward Tomasz Napierala 		return (ESRCH);
1093*ec125fbbSEdward Tomasz Napierala 	}
1094*ec125fbbSEdward Tomasz Napierala 
1095*ec125fbbSEdward Tomasz Napierala 	loginclass_racct_foreach(rctl_rule_remove_callback, filter,
1096*ec125fbbSEdward Tomasz Napierala 	    (void *)&found);
1097*ec125fbbSEdward Tomasz Napierala 	ui_racct_foreach(rctl_rule_remove_callback, filter,
1098*ec125fbbSEdward Tomasz Napierala 	    (void *)&found);
1099*ec125fbbSEdward Tomasz Napierala 	prison_racct_foreach(rctl_rule_remove_callback, filter,
1100*ec125fbbSEdward Tomasz Napierala 	    (void *)&found);
1101*ec125fbbSEdward Tomasz Napierala 
1102*ec125fbbSEdward Tomasz Napierala 	sx_assert(&allproc_lock, SA_LOCKED);
1103*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
1104*ec125fbbSEdward Tomasz Napierala 	FOREACH_PROC_IN_SYSTEM(p) {
1105*ec125fbbSEdward Tomasz Napierala 		found += rctl_racct_remove_rules(p->p_racct, filter);
1106*ec125fbbSEdward Tomasz Napierala 	}
1107*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1108*ec125fbbSEdward Tomasz Napierala 
1109*ec125fbbSEdward Tomasz Napierala 	if (found)
1110*ec125fbbSEdward Tomasz Napierala 		return (0);
1111*ec125fbbSEdward Tomasz Napierala 	return (ESRCH);
1112*ec125fbbSEdward Tomasz Napierala }
1113*ec125fbbSEdward Tomasz Napierala 
1114*ec125fbbSEdward Tomasz Napierala /*
1115*ec125fbbSEdward Tomasz Napierala  * Appends a rule to the sbuf.
1116*ec125fbbSEdward Tomasz Napierala  */
1117*ec125fbbSEdward Tomasz Napierala static void
1118*ec125fbbSEdward Tomasz Napierala rctl_rule_to_sbuf(struct sbuf *sb, const struct rctl_rule *rule)
1119*ec125fbbSEdward Tomasz Napierala {
1120*ec125fbbSEdward Tomasz Napierala 	int64_t amount;
1121*ec125fbbSEdward Tomasz Napierala 
1122*ec125fbbSEdward Tomasz Napierala 	sbuf_printf(sb, "%s:", rctl_subject_type_name(rule->rr_subject_type));
1123*ec125fbbSEdward Tomasz Napierala 
1124*ec125fbbSEdward Tomasz Napierala 	switch (rule->rr_subject_type) {
1125*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
1126*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_proc == NULL)
1127*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, ":");
1128*ec125fbbSEdward Tomasz Napierala 		else
1129*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, "%d:",
1130*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_proc->p_pid);
1131*ec125fbbSEdward Tomasz Napierala 		break;
1132*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
1133*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_uip == NULL)
1134*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, ":");
1135*ec125fbbSEdward Tomasz Napierala 		else
1136*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, "%d:",
1137*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_uip->ui_uid);
1138*ec125fbbSEdward Tomasz Napierala 		break;
1139*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
1140*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.hr_loginclass == NULL)
1141*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, ":");
1142*ec125fbbSEdward Tomasz Napierala 		else
1143*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, "%s:",
1144*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.hr_loginclass->lc_name);
1145*ec125fbbSEdward Tomasz Napierala 		break;
1146*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
1147*ec125fbbSEdward Tomasz Napierala 		if (rule->rr_subject.rs_prison == NULL)
1148*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, ":");
1149*ec125fbbSEdward Tomasz Napierala 		else
1150*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, "%s:",
1151*ec125fbbSEdward Tomasz Napierala 			    rule->rr_subject.rs_prison->pr_name);
1152*ec125fbbSEdward Tomasz Napierala 		break;
1153*ec125fbbSEdward Tomasz Napierala 	default:
1154*ec125fbbSEdward Tomasz Napierala 		panic("rctl_rule_to_sbuf: unknown subject type %d",
1155*ec125fbbSEdward Tomasz Napierala 		    rule->rr_subject_type);
1156*ec125fbbSEdward Tomasz Napierala 	}
1157*ec125fbbSEdward Tomasz Napierala 
1158*ec125fbbSEdward Tomasz Napierala 	amount = rule->rr_amount;
1159*ec125fbbSEdward Tomasz Napierala 	if (amount != RCTL_AMOUNT_UNDEFINED &&
1160*ec125fbbSEdward Tomasz Napierala 	    racct_is_in_thousands(rule->rr_resource))
1161*ec125fbbSEdward Tomasz Napierala 		amount /= 1000;
1162*ec125fbbSEdward Tomasz Napierala 
1163*ec125fbbSEdward Tomasz Napierala 	sbuf_printf(sb, "%s:%s=%jd",
1164*ec125fbbSEdward Tomasz Napierala 	    rctl_resource_name(rule->rr_resource),
1165*ec125fbbSEdward Tomasz Napierala 	    rctl_action_name(rule->rr_action),
1166*ec125fbbSEdward Tomasz Napierala 	    amount);
1167*ec125fbbSEdward Tomasz Napierala 
1168*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_per != rule->rr_subject_type)
1169*ec125fbbSEdward Tomasz Napierala 		sbuf_printf(sb, "/%s", rctl_subject_type_name(rule->rr_per));
1170*ec125fbbSEdward Tomasz Napierala }
1171*ec125fbbSEdward Tomasz Napierala 
1172*ec125fbbSEdward Tomasz Napierala /*
1173*ec125fbbSEdward Tomasz Napierala  * Routine used by RCTL syscalls to read in input string.
1174*ec125fbbSEdward Tomasz Napierala  */
1175*ec125fbbSEdward Tomasz Napierala static int
1176*ec125fbbSEdward Tomasz Napierala rctl_read_inbuf(char **inputstr, const char *inbufp, size_t inbuflen)
1177*ec125fbbSEdward Tomasz Napierala {
1178*ec125fbbSEdward Tomasz Napierala 	int error;
1179*ec125fbbSEdward Tomasz Napierala 	char *str;
1180*ec125fbbSEdward Tomasz Napierala 
1181*ec125fbbSEdward Tomasz Napierala 	if (inbuflen <= 0)
1182*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
1183*ec125fbbSEdward Tomasz Napierala 
1184*ec125fbbSEdward Tomasz Napierala 	str = malloc(inbuflen + 1, M_RCTL, M_WAITOK);
1185*ec125fbbSEdward Tomasz Napierala 	error = copyinstr(inbufp, str, inbuflen, NULL);
1186*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1187*ec125fbbSEdward Tomasz Napierala 		free(str, M_RCTL);
1188*ec125fbbSEdward Tomasz Napierala 		return (error);
1189*ec125fbbSEdward Tomasz Napierala 	}
1190*ec125fbbSEdward Tomasz Napierala 
1191*ec125fbbSEdward Tomasz Napierala 	*inputstr = str;
1192*ec125fbbSEdward Tomasz Napierala 
1193*ec125fbbSEdward Tomasz Napierala 	return (0);
1194*ec125fbbSEdward Tomasz Napierala }
1195*ec125fbbSEdward Tomasz Napierala 
1196*ec125fbbSEdward Tomasz Napierala /*
1197*ec125fbbSEdward Tomasz Napierala  * Routine used by RCTL syscalls to write out output string.
1198*ec125fbbSEdward Tomasz Napierala  */
1199*ec125fbbSEdward Tomasz Napierala static int
1200*ec125fbbSEdward Tomasz Napierala rctl_write_outbuf(struct sbuf *outputsbuf, char *outbufp, size_t outbuflen)
1201*ec125fbbSEdward Tomasz Napierala {
1202*ec125fbbSEdward Tomasz Napierala 	int error;
1203*ec125fbbSEdward Tomasz Napierala 
1204*ec125fbbSEdward Tomasz Napierala 	if (outputsbuf == NULL)
1205*ec125fbbSEdward Tomasz Napierala 		return (0);
1206*ec125fbbSEdward Tomasz Napierala 
1207*ec125fbbSEdward Tomasz Napierala 	sbuf_finish(outputsbuf);
1208*ec125fbbSEdward Tomasz Napierala 	if (outbuflen < sbuf_len(outputsbuf) + 1) {
1209*ec125fbbSEdward Tomasz Napierala 		sbuf_delete(outputsbuf);
1210*ec125fbbSEdward Tomasz Napierala 		return (ERANGE);
1211*ec125fbbSEdward Tomasz Napierala 	}
1212*ec125fbbSEdward Tomasz Napierala 	error = copyout(sbuf_data(outputsbuf), outbufp,
1213*ec125fbbSEdward Tomasz Napierala 	    sbuf_len(outputsbuf) + 1);
1214*ec125fbbSEdward Tomasz Napierala 	sbuf_delete(outputsbuf);
1215*ec125fbbSEdward Tomasz Napierala 	return (error);
1216*ec125fbbSEdward Tomasz Napierala }
1217*ec125fbbSEdward Tomasz Napierala 
1218*ec125fbbSEdward Tomasz Napierala static struct sbuf *
1219*ec125fbbSEdward Tomasz Napierala rctl_racct_to_sbuf(struct racct *racct, int sloppy)
1220*ec125fbbSEdward Tomasz Napierala {
1221*ec125fbbSEdward Tomasz Napierala 	int i;
1222*ec125fbbSEdward Tomasz Napierala 	int64_t amount;
1223*ec125fbbSEdward Tomasz Napierala 	struct sbuf *sb;
1224*ec125fbbSEdward Tomasz Napierala 
1225*ec125fbbSEdward Tomasz Napierala 	sb = sbuf_new_auto();
1226*ec125fbbSEdward Tomasz Napierala 	for (i = 0; i <= RACCT_MAX; i++) {
1227*ec125fbbSEdward Tomasz Napierala 		if (sloppy == 0 && racct_is_sloppy(i))
1228*ec125fbbSEdward Tomasz Napierala 			continue;
1229*ec125fbbSEdward Tomasz Napierala 		amount = racct->r_resources[i];
1230*ec125fbbSEdward Tomasz Napierala 		if (racct_is_in_thousands(i))
1231*ec125fbbSEdward Tomasz Napierala 			amount /= 1000;
1232*ec125fbbSEdward Tomasz Napierala 		sbuf_printf(sb, "%s=%jd,", rctl_resource_name(i), amount);
1233*ec125fbbSEdward Tomasz Napierala 	}
1234*ec125fbbSEdward Tomasz Napierala 	sbuf_setpos(sb, sbuf_len(sb) - 1);
1235*ec125fbbSEdward Tomasz Napierala 	return (sb);
1236*ec125fbbSEdward Tomasz Napierala }
1237*ec125fbbSEdward Tomasz Napierala 
1238*ec125fbbSEdward Tomasz Napierala int
1239*ec125fbbSEdward Tomasz Napierala rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
1240*ec125fbbSEdward Tomasz Napierala {
1241*ec125fbbSEdward Tomasz Napierala 	int error;
1242*ec125fbbSEdward Tomasz Napierala 	char *inputstr;
1243*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter;
1244*ec125fbbSEdward Tomasz Napierala 	struct sbuf *outputsbuf = NULL;
1245*ec125fbbSEdward Tomasz Napierala 	struct proc *p;
1246*ec125fbbSEdward Tomasz Napierala 	struct uidinfo *uip;
1247*ec125fbbSEdward Tomasz Napierala 	struct loginclass *lc;
1248*ec125fbbSEdward Tomasz Napierala 	struct prison *pr;
1249*ec125fbbSEdward Tomasz Napierala 
1250*ec125fbbSEdward Tomasz Napierala 	error = priv_check(td, PRIV_RCTL_GET_USAGE);
1251*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1252*ec125fbbSEdward Tomasz Napierala 		return (error);
1253*ec125fbbSEdward Tomasz Napierala 
1254*ec125fbbSEdward Tomasz Napierala 	error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
1255*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1256*ec125fbbSEdward Tomasz Napierala 		return (error);
1257*ec125fbbSEdward Tomasz Napierala 
1258*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allproc_lock);
1259*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allprison_lock);
1260*ec125fbbSEdward Tomasz Napierala 	error = rctl_string_to_rule(inputstr, &filter);
1261*ec125fbbSEdward Tomasz Napierala 	free(inputstr, M_RCTL);
1262*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1263*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1264*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1265*ec125fbbSEdward Tomasz Napierala 		return (error);
1266*ec125fbbSEdward Tomasz Napierala 	}
1267*ec125fbbSEdward Tomasz Napierala 
1268*ec125fbbSEdward Tomasz Napierala 	switch (filter->rr_subject_type) {
1269*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_PROCESS:
1270*ec125fbbSEdward Tomasz Napierala 		p = filter->rr_subject.rs_proc;
1271*ec125fbbSEdward Tomasz Napierala 		if (p == NULL) {
1272*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
1273*ec125fbbSEdward Tomasz Napierala 			goto out;
1274*ec125fbbSEdward Tomasz Napierala 		}
1275*ec125fbbSEdward Tomasz Napierala 		if (p->p_flag & P_SYSTEM) {
1276*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
1277*ec125fbbSEdward Tomasz Napierala 			goto out;
1278*ec125fbbSEdward Tomasz Napierala 		}
1279*ec125fbbSEdward Tomasz Napierala 		outputsbuf = rctl_racct_to_sbuf(p->p_racct, 0);
1280*ec125fbbSEdward Tomasz Napierala 		break;
1281*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_USER:
1282*ec125fbbSEdward Tomasz Napierala 		uip = filter->rr_subject.rs_uip;
1283*ec125fbbSEdward Tomasz Napierala 		if (uip == NULL) {
1284*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
1285*ec125fbbSEdward Tomasz Napierala 			goto out;
1286*ec125fbbSEdward Tomasz Napierala 		}
1287*ec125fbbSEdward Tomasz Napierala 		outputsbuf = rctl_racct_to_sbuf(uip->ui_racct, 1);
1288*ec125fbbSEdward Tomasz Napierala 		break;
1289*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_LOGINCLASS:
1290*ec125fbbSEdward Tomasz Napierala 		lc = filter->rr_subject.hr_loginclass;
1291*ec125fbbSEdward Tomasz Napierala 		if (lc == NULL) {
1292*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
1293*ec125fbbSEdward Tomasz Napierala 			goto out;
1294*ec125fbbSEdward Tomasz Napierala 		}
1295*ec125fbbSEdward Tomasz Napierala 		outputsbuf = rctl_racct_to_sbuf(lc->lc_racct, 1);
1296*ec125fbbSEdward Tomasz Napierala 		break;
1297*ec125fbbSEdward Tomasz Napierala 	case RCTL_SUBJECT_TYPE_JAIL:
1298*ec125fbbSEdward Tomasz Napierala 		pr = filter->rr_subject.rs_prison;
1299*ec125fbbSEdward Tomasz Napierala 		if (pr == NULL) {
1300*ec125fbbSEdward Tomasz Napierala 			error = EINVAL;
1301*ec125fbbSEdward Tomasz Napierala 			goto out;
1302*ec125fbbSEdward Tomasz Napierala 		}
1303*ec125fbbSEdward Tomasz Napierala 		outputsbuf = rctl_racct_to_sbuf(pr->pr_racct, 1);
1304*ec125fbbSEdward Tomasz Napierala 		break;
1305*ec125fbbSEdward Tomasz Napierala 	default:
1306*ec125fbbSEdward Tomasz Napierala 		error = EINVAL;
1307*ec125fbbSEdward Tomasz Napierala 	}
1308*ec125fbbSEdward Tomasz Napierala out:
1309*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release(filter);
1310*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allprison_lock);
1311*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allproc_lock);
1312*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1313*ec125fbbSEdward Tomasz Napierala 		return (error);
1314*ec125fbbSEdward Tomasz Napierala 
1315*ec125fbbSEdward Tomasz Napierala 	error = rctl_write_outbuf(outputsbuf, uap->outbufp, uap->outbuflen);
1316*ec125fbbSEdward Tomasz Napierala 
1317*ec125fbbSEdward Tomasz Napierala 	return (error);
1318*ec125fbbSEdward Tomasz Napierala }
1319*ec125fbbSEdward Tomasz Napierala 
1320*ec125fbbSEdward Tomasz Napierala static void
1321*ec125fbbSEdward Tomasz Napierala rctl_get_rules_callback(struct racct *racct, void *arg2, void *arg3)
1322*ec125fbbSEdward Tomasz Napierala {
1323*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter = (struct rctl_rule *)arg2;
1324*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
1325*ec125fbbSEdward Tomasz Napierala 	struct sbuf *sb = (struct sbuf *)arg3;
1326*ec125fbbSEdward Tomasz Napierala 
1327*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
1328*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &racct->r_rule_links, rrl_next) {
1329*ec125fbbSEdward Tomasz Napierala 		if (!rctl_rule_matches(link->rrl_rule, filter))
1330*ec125fbbSEdward Tomasz Napierala 			continue;
1331*ec125fbbSEdward Tomasz Napierala 		rctl_rule_to_sbuf(sb, link->rrl_rule);
1332*ec125fbbSEdward Tomasz Napierala 		sbuf_printf(sb, ",");
1333*ec125fbbSEdward Tomasz Napierala 	}
1334*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
1335*ec125fbbSEdward Tomasz Napierala }
1336*ec125fbbSEdward Tomasz Napierala 
1337*ec125fbbSEdward Tomasz Napierala int
1338*ec125fbbSEdward Tomasz Napierala rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
1339*ec125fbbSEdward Tomasz Napierala {
1340*ec125fbbSEdward Tomasz Napierala 	int error;
1341*ec125fbbSEdward Tomasz Napierala 	size_t bufsize = RCTL_DEFAULT_BUFSIZE;
1342*ec125fbbSEdward Tomasz Napierala 	char *inputstr, *buf;
1343*ec125fbbSEdward Tomasz Napierala 	struct sbuf *sb;
1344*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter;
1345*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
1346*ec125fbbSEdward Tomasz Napierala 	struct proc *p;
1347*ec125fbbSEdward Tomasz Napierala 
1348*ec125fbbSEdward Tomasz Napierala 	error = priv_check(td, PRIV_RCTL_GET_RULES);
1349*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1350*ec125fbbSEdward Tomasz Napierala 		return (error);
1351*ec125fbbSEdward Tomasz Napierala 
1352*ec125fbbSEdward Tomasz Napierala 	error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
1353*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1354*ec125fbbSEdward Tomasz Napierala 		return (error);
1355*ec125fbbSEdward Tomasz Napierala 
1356*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allproc_lock);
1357*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allprison_lock);
1358*ec125fbbSEdward Tomasz Napierala 	error = rctl_string_to_rule(inputstr, &filter);
1359*ec125fbbSEdward Tomasz Napierala 	free(inputstr, M_RCTL);
1360*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1361*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1362*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1363*ec125fbbSEdward Tomasz Napierala 		return (error);
1364*ec125fbbSEdward Tomasz Napierala 	}
1365*ec125fbbSEdward Tomasz Napierala 
1366*ec125fbbSEdward Tomasz Napierala again:
1367*ec125fbbSEdward Tomasz Napierala 	buf = malloc(bufsize, M_RCTL, M_WAITOK);
1368*ec125fbbSEdward Tomasz Napierala 	sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
1369*ec125fbbSEdward Tomasz Napierala 	KASSERT(sb != NULL, ("sbuf_new failed"));
1370*ec125fbbSEdward Tomasz Napierala 
1371*ec125fbbSEdward Tomasz Napierala 	sx_assert(&allproc_lock, SA_LOCKED);
1372*ec125fbbSEdward Tomasz Napierala 	FOREACH_PROC_IN_SYSTEM(p) {
1373*ec125fbbSEdward Tomasz Napierala 		rw_rlock(&rctl_lock);
1374*ec125fbbSEdward Tomasz Napierala 		LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
1375*ec125fbbSEdward Tomasz Napierala 			/*
1376*ec125fbbSEdward Tomasz Napierala 			 * Non-process rules will be added to the buffer later.
1377*ec125fbbSEdward Tomasz Napierala 			 * Adding them here would result in duplicated output.
1378*ec125fbbSEdward Tomasz Napierala 			 */
1379*ec125fbbSEdward Tomasz Napierala 			if (link->rrl_rule->rr_subject_type !=
1380*ec125fbbSEdward Tomasz Napierala 			    RCTL_SUBJECT_TYPE_PROCESS)
1381*ec125fbbSEdward Tomasz Napierala 				continue;
1382*ec125fbbSEdward Tomasz Napierala 			if (!rctl_rule_matches(link->rrl_rule, filter))
1383*ec125fbbSEdward Tomasz Napierala 				continue;
1384*ec125fbbSEdward Tomasz Napierala 			rctl_rule_to_sbuf(sb, link->rrl_rule);
1385*ec125fbbSEdward Tomasz Napierala 			sbuf_printf(sb, ",");
1386*ec125fbbSEdward Tomasz Napierala 		}
1387*ec125fbbSEdward Tomasz Napierala 		rw_runlock(&rctl_lock);
1388*ec125fbbSEdward Tomasz Napierala 	}
1389*ec125fbbSEdward Tomasz Napierala 
1390*ec125fbbSEdward Tomasz Napierala 	loginclass_racct_foreach(rctl_get_rules_callback, filter, sb);
1391*ec125fbbSEdward Tomasz Napierala 	ui_racct_foreach(rctl_get_rules_callback, filter, sb);
1392*ec125fbbSEdward Tomasz Napierala 	prison_racct_foreach(rctl_get_rules_callback, filter, sb);
1393*ec125fbbSEdward Tomasz Napierala 	if (sbuf_error(sb) == ENOMEM) {
1394*ec125fbbSEdward Tomasz Napierala 		sbuf_delete(sb);
1395*ec125fbbSEdward Tomasz Napierala 		free(buf, M_RCTL);
1396*ec125fbbSEdward Tomasz Napierala 		bufsize *= 4;
1397*ec125fbbSEdward Tomasz Napierala 		goto again;
1398*ec125fbbSEdward Tomasz Napierala 	}
1399*ec125fbbSEdward Tomasz Napierala 
1400*ec125fbbSEdward Tomasz Napierala 	/*
1401*ec125fbbSEdward Tomasz Napierala 	 * Remove trailing ",".
1402*ec125fbbSEdward Tomasz Napierala 	 */
1403*ec125fbbSEdward Tomasz Napierala 	if (sbuf_len(sb) > 0)
1404*ec125fbbSEdward Tomasz Napierala 		sbuf_setpos(sb, sbuf_len(sb) - 1);
1405*ec125fbbSEdward Tomasz Napierala 
1406*ec125fbbSEdward Tomasz Napierala 	error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
1407*ec125fbbSEdward Tomasz Napierala 
1408*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release(filter);
1409*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allprison_lock);
1410*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allproc_lock);
1411*ec125fbbSEdward Tomasz Napierala 	free(buf, M_RCTL);
1412*ec125fbbSEdward Tomasz Napierala 	return (error);
1413*ec125fbbSEdward Tomasz Napierala }
1414*ec125fbbSEdward Tomasz Napierala 
1415*ec125fbbSEdward Tomasz Napierala int
1416*ec125fbbSEdward Tomasz Napierala rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
1417*ec125fbbSEdward Tomasz Napierala {
1418*ec125fbbSEdward Tomasz Napierala 	int error;
1419*ec125fbbSEdward Tomasz Napierala 	size_t bufsize = RCTL_DEFAULT_BUFSIZE;
1420*ec125fbbSEdward Tomasz Napierala 	char *inputstr, *buf;
1421*ec125fbbSEdward Tomasz Napierala 	struct sbuf *sb;
1422*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter;
1423*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
1424*ec125fbbSEdward Tomasz Napierala 
1425*ec125fbbSEdward Tomasz Napierala 	error = priv_check(td, PRIV_RCTL_GET_LIMITS);
1426*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1427*ec125fbbSEdward Tomasz Napierala 		return (error);
1428*ec125fbbSEdward Tomasz Napierala 
1429*ec125fbbSEdward Tomasz Napierala 	error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
1430*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1431*ec125fbbSEdward Tomasz Napierala 		return (error);
1432*ec125fbbSEdward Tomasz Napierala 
1433*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allproc_lock);
1434*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allprison_lock);
1435*ec125fbbSEdward Tomasz Napierala 	error = rctl_string_to_rule(inputstr, &filter);
1436*ec125fbbSEdward Tomasz Napierala 	free(inputstr, M_RCTL);
1437*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1438*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1439*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1440*ec125fbbSEdward Tomasz Napierala 		return (error);
1441*ec125fbbSEdward Tomasz Napierala 	}
1442*ec125fbbSEdward Tomasz Napierala 
1443*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_subject_type == RCTL_SUBJECT_TYPE_UNDEFINED) {
1444*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(filter);
1445*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1446*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1447*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
1448*ec125fbbSEdward Tomasz Napierala 	}
1449*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_subject_type != RCTL_SUBJECT_TYPE_PROCESS) {
1450*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(filter);
1451*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1452*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1453*ec125fbbSEdward Tomasz Napierala 		return (EOPNOTSUPP);
1454*ec125fbbSEdward Tomasz Napierala 	}
1455*ec125fbbSEdward Tomasz Napierala 	if (filter->rr_subject.rs_proc == NULL) {
1456*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(filter);
1457*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1458*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1459*ec125fbbSEdward Tomasz Napierala 		return (EINVAL);
1460*ec125fbbSEdward Tomasz Napierala 	}
1461*ec125fbbSEdward Tomasz Napierala 
1462*ec125fbbSEdward Tomasz Napierala again:
1463*ec125fbbSEdward Tomasz Napierala 	buf = malloc(bufsize, M_RCTL, M_WAITOK);
1464*ec125fbbSEdward Tomasz Napierala 	sb = sbuf_new(NULL, buf, bufsize, SBUF_FIXEDLEN);
1465*ec125fbbSEdward Tomasz Napierala 	KASSERT(sb != NULL, ("sbuf_new failed"));
1466*ec125fbbSEdward Tomasz Napierala 
1467*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
1468*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &filter->rr_subject.rs_proc->p_racct->r_rule_links,
1469*ec125fbbSEdward Tomasz Napierala 	    rrl_next) {
1470*ec125fbbSEdward Tomasz Napierala 		rctl_rule_to_sbuf(sb, link->rrl_rule);
1471*ec125fbbSEdward Tomasz Napierala 		sbuf_printf(sb, ",");
1472*ec125fbbSEdward Tomasz Napierala 	}
1473*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
1474*ec125fbbSEdward Tomasz Napierala 	if (sbuf_error(sb) == ENOMEM) {
1475*ec125fbbSEdward Tomasz Napierala 		sbuf_delete(sb);
1476*ec125fbbSEdward Tomasz Napierala 		free(buf, M_RCTL);
1477*ec125fbbSEdward Tomasz Napierala 		bufsize *= 4;
1478*ec125fbbSEdward Tomasz Napierala 		goto again;
1479*ec125fbbSEdward Tomasz Napierala 	}
1480*ec125fbbSEdward Tomasz Napierala 
1481*ec125fbbSEdward Tomasz Napierala 	/*
1482*ec125fbbSEdward Tomasz Napierala 	 * Remove trailing ",".
1483*ec125fbbSEdward Tomasz Napierala 	 */
1484*ec125fbbSEdward Tomasz Napierala 	if (sbuf_len(sb) > 0)
1485*ec125fbbSEdward Tomasz Napierala 		sbuf_setpos(sb, sbuf_len(sb) - 1);
1486*ec125fbbSEdward Tomasz Napierala 
1487*ec125fbbSEdward Tomasz Napierala 	error = rctl_write_outbuf(sb, uap->outbufp, uap->outbuflen);
1488*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release(filter);
1489*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allprison_lock);
1490*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allproc_lock);
1491*ec125fbbSEdward Tomasz Napierala 	free(buf, M_RCTL);
1492*ec125fbbSEdward Tomasz Napierala 	return (error);
1493*ec125fbbSEdward Tomasz Napierala }
1494*ec125fbbSEdward Tomasz Napierala 
1495*ec125fbbSEdward Tomasz Napierala int
1496*ec125fbbSEdward Tomasz Napierala rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
1497*ec125fbbSEdward Tomasz Napierala {
1498*ec125fbbSEdward Tomasz Napierala 	int error;
1499*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
1500*ec125fbbSEdward Tomasz Napierala 	char *inputstr;
1501*ec125fbbSEdward Tomasz Napierala 
1502*ec125fbbSEdward Tomasz Napierala 	error = priv_check(td, PRIV_RCTL_ADD_RULE);
1503*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1504*ec125fbbSEdward Tomasz Napierala 		return (error);
1505*ec125fbbSEdward Tomasz Napierala 
1506*ec125fbbSEdward Tomasz Napierala 	error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
1507*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1508*ec125fbbSEdward Tomasz Napierala 		return (error);
1509*ec125fbbSEdward Tomasz Napierala 
1510*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allproc_lock);
1511*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allprison_lock);
1512*ec125fbbSEdward Tomasz Napierala 	error = rctl_string_to_rule(inputstr, &rule);
1513*ec125fbbSEdward Tomasz Napierala 	free(inputstr, M_RCTL);
1514*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1515*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1516*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1517*ec125fbbSEdward Tomasz Napierala 		return (error);
1518*ec125fbbSEdward Tomasz Napierala 	}
1519*ec125fbbSEdward Tomasz Napierala 	/*
1520*ec125fbbSEdward Tomasz Napierala 	 * The 'per' part of a rule is optional.
1521*ec125fbbSEdward Tomasz Napierala 	 */
1522*ec125fbbSEdward Tomasz Napierala 	if (rule->rr_per == RCTL_SUBJECT_TYPE_UNDEFINED &&
1523*ec125fbbSEdward Tomasz Napierala 	    rule->rr_subject_type != RCTL_SUBJECT_TYPE_UNDEFINED)
1524*ec125fbbSEdward Tomasz Napierala 		rule->rr_per = rule->rr_subject_type;
1525*ec125fbbSEdward Tomasz Napierala 
1526*ec125fbbSEdward Tomasz Napierala 	if (!rctl_rule_fully_specified(rule)) {
1527*ec125fbbSEdward Tomasz Napierala 		error = EINVAL;
1528*ec125fbbSEdward Tomasz Napierala 		goto out;
1529*ec125fbbSEdward Tomasz Napierala 	}
1530*ec125fbbSEdward Tomasz Napierala 
1531*ec125fbbSEdward Tomasz Napierala 	error = rctl_rule_add(rule);
1532*ec125fbbSEdward Tomasz Napierala 
1533*ec125fbbSEdward Tomasz Napierala out:
1534*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release(rule);
1535*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allprison_lock);
1536*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allproc_lock);
1537*ec125fbbSEdward Tomasz Napierala 	return (error);
1538*ec125fbbSEdward Tomasz Napierala }
1539*ec125fbbSEdward Tomasz Napierala 
1540*ec125fbbSEdward Tomasz Napierala int
1541*ec125fbbSEdward Tomasz Napierala rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
1542*ec125fbbSEdward Tomasz Napierala {
1543*ec125fbbSEdward Tomasz Napierala 	int error;
1544*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *filter;
1545*ec125fbbSEdward Tomasz Napierala 	char *inputstr;
1546*ec125fbbSEdward Tomasz Napierala 
1547*ec125fbbSEdward Tomasz Napierala 	error = priv_check(td, PRIV_RCTL_REMOVE_RULE);
1548*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1549*ec125fbbSEdward Tomasz Napierala 		return (error);
1550*ec125fbbSEdward Tomasz Napierala 
1551*ec125fbbSEdward Tomasz Napierala 	error = rctl_read_inbuf(&inputstr, uap->inbufp, uap->inbuflen);
1552*ec125fbbSEdward Tomasz Napierala 	if (error != 0)
1553*ec125fbbSEdward Tomasz Napierala 		return (error);
1554*ec125fbbSEdward Tomasz Napierala 
1555*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allproc_lock);
1556*ec125fbbSEdward Tomasz Napierala 	sx_slock(&allprison_lock);
1557*ec125fbbSEdward Tomasz Napierala 	error = rctl_string_to_rule(inputstr, &filter);
1558*ec125fbbSEdward Tomasz Napierala 	free(inputstr, M_RCTL);
1559*ec125fbbSEdward Tomasz Napierala 	if (error != 0) {
1560*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allprison_lock);
1561*ec125fbbSEdward Tomasz Napierala 		sx_sunlock(&allproc_lock);
1562*ec125fbbSEdward Tomasz Napierala 		return (error);
1563*ec125fbbSEdward Tomasz Napierala 	}
1564*ec125fbbSEdward Tomasz Napierala 
1565*ec125fbbSEdward Tomasz Napierala 	error = rctl_rule_remove(filter);
1566*ec125fbbSEdward Tomasz Napierala 	rctl_rule_release(filter);
1567*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allprison_lock);
1568*ec125fbbSEdward Tomasz Napierala 	sx_sunlock(&allproc_lock);
1569*ec125fbbSEdward Tomasz Napierala 
1570*ec125fbbSEdward Tomasz Napierala 	return (error);
1571*ec125fbbSEdward Tomasz Napierala }
1572*ec125fbbSEdward Tomasz Napierala 
1573*ec125fbbSEdward Tomasz Napierala /*
1574*ec125fbbSEdward Tomasz Napierala  * Update RCTL rule list after credential change.
1575*ec125fbbSEdward Tomasz Napierala  */
1576*ec125fbbSEdward Tomasz Napierala void
1577*ec125fbbSEdward Tomasz Napierala rctl_proc_ucred_changed(struct proc *p, struct ucred *newcred)
1578*ec125fbbSEdward Tomasz Napierala {
1579*ec125fbbSEdward Tomasz Napierala 	int rulecnt, i;
1580*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link, *newlink;
1581*ec125fbbSEdward Tomasz Napierala 	struct uidinfo *newuip;
1582*ec125fbbSEdward Tomasz Napierala 	struct loginclass *newlc;
1583*ec125fbbSEdward Tomasz Napierala 	struct prison *newpr;
1584*ec125fbbSEdward Tomasz Napierala 	LIST_HEAD(, rctl_rule_link) newrules;
1585*ec125fbbSEdward Tomasz Napierala 
1586*ec125fbbSEdward Tomasz Napierala 	newuip = newcred->cr_ruidinfo;
1587*ec125fbbSEdward Tomasz Napierala 	newlc = newcred->cr_loginclass;
1588*ec125fbbSEdward Tomasz Napierala 	newpr = newcred->cr_prison;
1589*ec125fbbSEdward Tomasz Napierala 
1590*ec125fbbSEdward Tomasz Napierala 	LIST_INIT(&newrules);
1591*ec125fbbSEdward Tomasz Napierala 
1592*ec125fbbSEdward Tomasz Napierala again:
1593*ec125fbbSEdward Tomasz Napierala 	/*
1594*ec125fbbSEdward Tomasz Napierala 	 * First, count the rules that apply to the process with new
1595*ec125fbbSEdward Tomasz Napierala 	 * credentials.
1596*ec125fbbSEdward Tomasz Napierala 	 */
1597*ec125fbbSEdward Tomasz Napierala 	rulecnt = 0;
1598*ec125fbbSEdward Tomasz Napierala 	rw_rlock(&rctl_lock);
1599*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
1600*ec125fbbSEdward Tomasz Napierala 		if (link->rrl_rule->rr_subject_type ==
1601*ec125fbbSEdward Tomasz Napierala 		    RCTL_SUBJECT_TYPE_PROCESS)
1602*ec125fbbSEdward Tomasz Napierala 			rulecnt++;
1603*ec125fbbSEdward Tomasz Napierala 	}
1604*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next)
1605*ec125fbbSEdward Tomasz Napierala 		rulecnt++;
1606*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next)
1607*ec125fbbSEdward Tomasz Napierala 		rulecnt++;
1608*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newpr->pr_racct->r_rule_links, rrl_next)
1609*ec125fbbSEdward Tomasz Napierala 		rulecnt++;
1610*ec125fbbSEdward Tomasz Napierala 	rw_runlock(&rctl_lock);
1611*ec125fbbSEdward Tomasz Napierala 
1612*ec125fbbSEdward Tomasz Napierala 	/*
1613*ec125fbbSEdward Tomasz Napierala 	 * Create temporary list.  We've dropped the rctl_lock in order
1614*ec125fbbSEdward Tomasz Napierala 	 * to use M_WAITOK.
1615*ec125fbbSEdward Tomasz Napierala 	 */
1616*ec125fbbSEdward Tomasz Napierala 	for (i = 0; i < rulecnt; i++) {
1617*ec125fbbSEdward Tomasz Napierala 		newlink = uma_zalloc(rctl_rule_link_zone, M_WAITOK);
1618*ec125fbbSEdward Tomasz Napierala 		newlink->rrl_rule = NULL;
1619*ec125fbbSEdward Tomasz Napierala 		LIST_INSERT_HEAD(&newrules, newlink, rrl_next);
1620*ec125fbbSEdward Tomasz Napierala 	}
1621*ec125fbbSEdward Tomasz Napierala 
1622*ec125fbbSEdward Tomasz Napierala 	newlink = LIST_FIRST(&newrules);
1623*ec125fbbSEdward Tomasz Napierala 
1624*ec125fbbSEdward Tomasz Napierala 	/*
1625*ec125fbbSEdward Tomasz Napierala 	 * Assign rules to the newly allocated list entries.
1626*ec125fbbSEdward Tomasz Napierala 	 */
1627*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
1628*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &p->p_racct->r_rule_links, rrl_next) {
1629*ec125fbbSEdward Tomasz Napierala 		if (link->rrl_rule->rr_subject_type ==
1630*ec125fbbSEdward Tomasz Napierala 		    RCTL_SUBJECT_TYPE_PROCESS) {
1631*ec125fbbSEdward Tomasz Napierala 			if (newlink == NULL)
1632*ec125fbbSEdward Tomasz Napierala 				goto goaround;
1633*ec125fbbSEdward Tomasz Napierala 			rctl_rule_acquire(link->rrl_rule);
1634*ec125fbbSEdward Tomasz Napierala 			newlink->rrl_rule = link->rrl_rule;
1635*ec125fbbSEdward Tomasz Napierala 			newlink = LIST_NEXT(newlink, rrl_next);
1636*ec125fbbSEdward Tomasz Napierala 			rulecnt--;
1637*ec125fbbSEdward Tomasz Napierala 		}
1638*ec125fbbSEdward Tomasz Napierala 	}
1639*ec125fbbSEdward Tomasz Napierala 
1640*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newuip->ui_racct->r_rule_links, rrl_next) {
1641*ec125fbbSEdward Tomasz Napierala 		if (newlink == NULL)
1642*ec125fbbSEdward Tomasz Napierala 			goto goaround;
1643*ec125fbbSEdward Tomasz Napierala 		rctl_rule_acquire(link->rrl_rule);
1644*ec125fbbSEdward Tomasz Napierala 		newlink->rrl_rule = link->rrl_rule;
1645*ec125fbbSEdward Tomasz Napierala 		newlink = LIST_NEXT(newlink, rrl_next);
1646*ec125fbbSEdward Tomasz Napierala 		rulecnt--;
1647*ec125fbbSEdward Tomasz Napierala 	}
1648*ec125fbbSEdward Tomasz Napierala 
1649*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newlc->lc_racct->r_rule_links, rrl_next) {
1650*ec125fbbSEdward Tomasz Napierala 		if (newlink == NULL)
1651*ec125fbbSEdward Tomasz Napierala 			goto goaround;
1652*ec125fbbSEdward Tomasz Napierala 		rctl_rule_acquire(link->rrl_rule);
1653*ec125fbbSEdward Tomasz Napierala 		newlink->rrl_rule = link->rrl_rule;
1654*ec125fbbSEdward Tomasz Napierala 		newlink = LIST_NEXT(newlink, rrl_next);
1655*ec125fbbSEdward Tomasz Napierala 		rulecnt--;
1656*ec125fbbSEdward Tomasz Napierala 	}
1657*ec125fbbSEdward Tomasz Napierala 
1658*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &newpr->pr_racct->r_rule_links, rrl_next) {
1659*ec125fbbSEdward Tomasz Napierala 		if (newlink == NULL)
1660*ec125fbbSEdward Tomasz Napierala 			goto goaround;
1661*ec125fbbSEdward Tomasz Napierala 		rctl_rule_acquire(link->rrl_rule);
1662*ec125fbbSEdward Tomasz Napierala 		newlink->rrl_rule = link->rrl_rule;
1663*ec125fbbSEdward Tomasz Napierala 		newlink = LIST_NEXT(newlink, rrl_next);
1664*ec125fbbSEdward Tomasz Napierala 		rulecnt--;
1665*ec125fbbSEdward Tomasz Napierala 	}
1666*ec125fbbSEdward Tomasz Napierala 
1667*ec125fbbSEdward Tomasz Napierala 	if (rulecnt == 0) {
1668*ec125fbbSEdward Tomasz Napierala 		/*
1669*ec125fbbSEdward Tomasz Napierala 		 * Free the old rule list.
1670*ec125fbbSEdward Tomasz Napierala 		 */
1671*ec125fbbSEdward Tomasz Napierala 		while (!LIST_EMPTY(&p->p_racct->r_rule_links)) {
1672*ec125fbbSEdward Tomasz Napierala 			link = LIST_FIRST(&p->p_racct->r_rule_links);
1673*ec125fbbSEdward Tomasz Napierala 			LIST_REMOVE(link, rrl_next);
1674*ec125fbbSEdward Tomasz Napierala 			rctl_rule_release(link->rrl_rule);
1675*ec125fbbSEdward Tomasz Napierala 			uma_zfree(rctl_rule_link_zone, link);
1676*ec125fbbSEdward Tomasz Napierala 		}
1677*ec125fbbSEdward Tomasz Napierala 
1678*ec125fbbSEdward Tomasz Napierala 		/*
1679*ec125fbbSEdward Tomasz Napierala 		 * Replace lists and we're done.
1680*ec125fbbSEdward Tomasz Napierala 		 *
1681*ec125fbbSEdward Tomasz Napierala 		 * XXX: Is there any way to switch list heads instead
1682*ec125fbbSEdward Tomasz Napierala 		 *      of iterating here?
1683*ec125fbbSEdward Tomasz Napierala 		 */
1684*ec125fbbSEdward Tomasz Napierala 		while (!LIST_EMPTY(&newrules)) {
1685*ec125fbbSEdward Tomasz Napierala 			newlink = LIST_FIRST(&newrules);
1686*ec125fbbSEdward Tomasz Napierala 			LIST_REMOVE(newlink, rrl_next);
1687*ec125fbbSEdward Tomasz Napierala 			LIST_INSERT_HEAD(&p->p_racct->r_rule_links,
1688*ec125fbbSEdward Tomasz Napierala 			    newlink, rrl_next);
1689*ec125fbbSEdward Tomasz Napierala 		}
1690*ec125fbbSEdward Tomasz Napierala 
1691*ec125fbbSEdward Tomasz Napierala 		rw_wunlock(&rctl_lock);
1692*ec125fbbSEdward Tomasz Napierala 
1693*ec125fbbSEdward Tomasz Napierala 		return;
1694*ec125fbbSEdward Tomasz Napierala 	}
1695*ec125fbbSEdward Tomasz Napierala 
1696*ec125fbbSEdward Tomasz Napierala goaround:
1697*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1698*ec125fbbSEdward Tomasz Napierala 
1699*ec125fbbSEdward Tomasz Napierala 	/*
1700*ec125fbbSEdward Tomasz Napierala 	 * Rule list changed while we were not holding the rctl_lock.
1701*ec125fbbSEdward Tomasz Napierala 	 * Free the new list and try again.
1702*ec125fbbSEdward Tomasz Napierala 	 */
1703*ec125fbbSEdward Tomasz Napierala 	while (!LIST_EMPTY(&newrules)) {
1704*ec125fbbSEdward Tomasz Napierala 		newlink = LIST_FIRST(&newrules);
1705*ec125fbbSEdward Tomasz Napierala 		LIST_REMOVE(newlink, rrl_next);
1706*ec125fbbSEdward Tomasz Napierala 		if (newlink->rrl_rule != NULL)
1707*ec125fbbSEdward Tomasz Napierala 			rctl_rule_release(newlink->rrl_rule);
1708*ec125fbbSEdward Tomasz Napierala 		uma_zfree(rctl_rule_link_zone, newlink);
1709*ec125fbbSEdward Tomasz Napierala 	}
1710*ec125fbbSEdward Tomasz Napierala 
1711*ec125fbbSEdward Tomasz Napierala 	goto again;
1712*ec125fbbSEdward Tomasz Napierala }
1713*ec125fbbSEdward Tomasz Napierala 
1714*ec125fbbSEdward Tomasz Napierala /*
1715*ec125fbbSEdward Tomasz Napierala  * Assign RCTL rules to the newly created process.
1716*ec125fbbSEdward Tomasz Napierala  */
1717*ec125fbbSEdward Tomasz Napierala int
1718*ec125fbbSEdward Tomasz Napierala rctl_proc_fork(struct proc *parent, struct proc *child)
1719*ec125fbbSEdward Tomasz Napierala {
1720*ec125fbbSEdward Tomasz Napierala 	int error;
1721*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
1722*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule *rule;
1723*ec125fbbSEdward Tomasz Napierala 
1724*ec125fbbSEdward Tomasz Napierala 	LIST_INIT(&child->p_racct->r_rule_links);
1725*ec125fbbSEdward Tomasz Napierala 
1726*ec125fbbSEdward Tomasz Napierala 	/*
1727*ec125fbbSEdward Tomasz Napierala 	 * No limits for kernel processes.
1728*ec125fbbSEdward Tomasz Napierala 	 */
1729*ec125fbbSEdward Tomasz Napierala 	if (child->p_flag & P_SYSTEM)
1730*ec125fbbSEdward Tomasz Napierala 		return (0);
1731*ec125fbbSEdward Tomasz Napierala 
1732*ec125fbbSEdward Tomasz Napierala 	/*
1733*ec125fbbSEdward Tomasz Napierala 	 * Nothing to inherit from P_SYSTEM parents.
1734*ec125fbbSEdward Tomasz Napierala 	 */
1735*ec125fbbSEdward Tomasz Napierala 	if (parent->p_racct == NULL) {
1736*ec125fbbSEdward Tomasz Napierala 		KASSERT(parent->p_flag & P_SYSTEM,
1737*ec125fbbSEdward Tomasz Napierala 		    ("non-system process without racct; p = %p", parent));
1738*ec125fbbSEdward Tomasz Napierala 		return (0);
1739*ec125fbbSEdward Tomasz Napierala 	}
1740*ec125fbbSEdward Tomasz Napierala 
1741*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
1742*ec125fbbSEdward Tomasz Napierala 
1743*ec125fbbSEdward Tomasz Napierala 	/*
1744*ec125fbbSEdward Tomasz Napierala 	 * Go through limits applicable to the parent and assign them
1745*ec125fbbSEdward Tomasz Napierala 	 * to the child.  Rules with 'process' subject have to be duplicated
1746*ec125fbbSEdward Tomasz Napierala 	 * in order to make their rr_subject point to the new process.
1747*ec125fbbSEdward Tomasz Napierala 	 */
1748*ec125fbbSEdward Tomasz Napierala 	LIST_FOREACH(link, &parent->p_racct->r_rule_links, rrl_next) {
1749*ec125fbbSEdward Tomasz Napierala 		if (link->rrl_rule->rr_subject_type ==
1750*ec125fbbSEdward Tomasz Napierala 		    RCTL_SUBJECT_TYPE_PROCESS) {
1751*ec125fbbSEdward Tomasz Napierala 			rule = rctl_rule_duplicate(link->rrl_rule, M_NOWAIT);
1752*ec125fbbSEdward Tomasz Napierala 			if (rule == NULL)
1753*ec125fbbSEdward Tomasz Napierala 				goto fail;
1754*ec125fbbSEdward Tomasz Napierala 			KASSERT(rule->rr_subject.rs_proc == parent,
1755*ec125fbbSEdward Tomasz Napierala 			    ("rule->rr_subject.rs_proc != parent"));
1756*ec125fbbSEdward Tomasz Napierala 			rule->rr_subject.rs_proc = child;
1757*ec125fbbSEdward Tomasz Napierala 			error = rctl_racct_add_rule_locked(child->p_racct,
1758*ec125fbbSEdward Tomasz Napierala 			    rule);
1759*ec125fbbSEdward Tomasz Napierala 			rctl_rule_release(rule);
1760*ec125fbbSEdward Tomasz Napierala 			if (error != 0)
1761*ec125fbbSEdward Tomasz Napierala 				goto fail;
1762*ec125fbbSEdward Tomasz Napierala 		} else {
1763*ec125fbbSEdward Tomasz Napierala 			error = rctl_racct_add_rule_locked(child->p_racct,
1764*ec125fbbSEdward Tomasz Napierala 			    link->rrl_rule);
1765*ec125fbbSEdward Tomasz Napierala 			if (error != 0)
1766*ec125fbbSEdward Tomasz Napierala 				goto fail;
1767*ec125fbbSEdward Tomasz Napierala 		}
1768*ec125fbbSEdward Tomasz Napierala 	}
1769*ec125fbbSEdward Tomasz Napierala 
1770*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1771*ec125fbbSEdward Tomasz Napierala 	return (0);
1772*ec125fbbSEdward Tomasz Napierala 
1773*ec125fbbSEdward Tomasz Napierala fail:
1774*ec125fbbSEdward Tomasz Napierala 	while (!LIST_EMPTY(&child->p_racct->r_rule_links)) {
1775*ec125fbbSEdward Tomasz Napierala 		link = LIST_FIRST(&child->p_racct->r_rule_links);
1776*ec125fbbSEdward Tomasz Napierala 		LIST_REMOVE(link, rrl_next);
1777*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(link->rrl_rule);
1778*ec125fbbSEdward Tomasz Napierala 		uma_zfree(rctl_rule_link_zone, link);
1779*ec125fbbSEdward Tomasz Napierala 	}
1780*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1781*ec125fbbSEdward Tomasz Napierala 	return (EAGAIN);
1782*ec125fbbSEdward Tomasz Napierala }
1783*ec125fbbSEdward Tomasz Napierala 
1784*ec125fbbSEdward Tomasz Napierala /*
1785*ec125fbbSEdward Tomasz Napierala  * Release rules attached to the racct.
1786*ec125fbbSEdward Tomasz Napierala  */
1787*ec125fbbSEdward Tomasz Napierala void
1788*ec125fbbSEdward Tomasz Napierala rctl_racct_release(struct racct *racct)
1789*ec125fbbSEdward Tomasz Napierala {
1790*ec125fbbSEdward Tomasz Napierala 	struct rctl_rule_link *link;
1791*ec125fbbSEdward Tomasz Napierala 
1792*ec125fbbSEdward Tomasz Napierala 	rw_wlock(&rctl_lock);
1793*ec125fbbSEdward Tomasz Napierala 	while (!LIST_EMPTY(&racct->r_rule_links)) {
1794*ec125fbbSEdward Tomasz Napierala 		link = LIST_FIRST(&racct->r_rule_links);
1795*ec125fbbSEdward Tomasz Napierala 		LIST_REMOVE(link, rrl_next);
1796*ec125fbbSEdward Tomasz Napierala 		rctl_rule_release(link->rrl_rule);
1797*ec125fbbSEdward Tomasz Napierala 		uma_zfree(rctl_rule_link_zone, link);
1798*ec125fbbSEdward Tomasz Napierala 	}
1799*ec125fbbSEdward Tomasz Napierala 	rw_wunlock(&rctl_lock);
1800*ec125fbbSEdward Tomasz Napierala }
1801*ec125fbbSEdward Tomasz Napierala 
1802*ec125fbbSEdward Tomasz Napierala static void
1803*ec125fbbSEdward Tomasz Napierala rctl_init(void)
1804*ec125fbbSEdward Tomasz Napierala {
1805*ec125fbbSEdward Tomasz Napierala 
1806*ec125fbbSEdward Tomasz Napierala 	rctl_rule_link_zone = uma_zcreate("rctl_rule_link",
1807*ec125fbbSEdward Tomasz Napierala 	    sizeof(struct rctl_rule_link), NULL, NULL, NULL, NULL,
1808*ec125fbbSEdward Tomasz Napierala 	    UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
1809*ec125fbbSEdward Tomasz Napierala 	rctl_rule_zone = uma_zcreate("rctl_rule", sizeof(struct rctl_rule),
1810*ec125fbbSEdward Tomasz Napierala 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
1811*ec125fbbSEdward Tomasz Napierala }
1812*ec125fbbSEdward Tomasz Napierala 
1813*ec125fbbSEdward Tomasz Napierala #else /* !RCTL */
1814*ec125fbbSEdward Tomasz Napierala 
1815*ec125fbbSEdward Tomasz Napierala int
1816*ec125fbbSEdward Tomasz Napierala rctl_get_racct(struct thread *td, struct rctl_get_racct_args *uap)
1817*ec125fbbSEdward Tomasz Napierala {
1818*ec125fbbSEdward Tomasz Napierala 
1819*ec125fbbSEdward Tomasz Napierala 	return (ENOSYS);
1820*ec125fbbSEdward Tomasz Napierala }
1821*ec125fbbSEdward Tomasz Napierala 
1822*ec125fbbSEdward Tomasz Napierala int
1823*ec125fbbSEdward Tomasz Napierala rctl_get_rules(struct thread *td, struct rctl_get_rules_args *uap)
1824*ec125fbbSEdward Tomasz Napierala {
1825*ec125fbbSEdward Tomasz Napierala 
1826*ec125fbbSEdward Tomasz Napierala 	return (ENOSYS);
1827*ec125fbbSEdward Tomasz Napierala }
1828*ec125fbbSEdward Tomasz Napierala 
1829*ec125fbbSEdward Tomasz Napierala int
1830*ec125fbbSEdward Tomasz Napierala rctl_get_limits(struct thread *td, struct rctl_get_limits_args *uap)
1831*ec125fbbSEdward Tomasz Napierala {
1832*ec125fbbSEdward Tomasz Napierala 
1833*ec125fbbSEdward Tomasz Napierala 	return (ENOSYS);
1834*ec125fbbSEdward Tomasz Napierala }
1835*ec125fbbSEdward Tomasz Napierala 
1836*ec125fbbSEdward Tomasz Napierala int
1837*ec125fbbSEdward Tomasz Napierala rctl_add_rule(struct thread *td, struct rctl_add_rule_args *uap)
1838*ec125fbbSEdward Tomasz Napierala {
1839*ec125fbbSEdward Tomasz Napierala 
1840*ec125fbbSEdward Tomasz Napierala 	return (ENOSYS);
1841*ec125fbbSEdward Tomasz Napierala }
1842*ec125fbbSEdward Tomasz Napierala 
1843*ec125fbbSEdward Tomasz Napierala int
1844*ec125fbbSEdward Tomasz Napierala rctl_remove_rule(struct thread *td, struct rctl_remove_rule_args *uap)
1845*ec125fbbSEdward Tomasz Napierala {
1846*ec125fbbSEdward Tomasz Napierala 
1847*ec125fbbSEdward Tomasz Napierala 	return (ENOSYS);
1848*ec125fbbSEdward Tomasz Napierala }
1849*ec125fbbSEdward Tomasz Napierala 
1850*ec125fbbSEdward Tomasz Napierala #endif /* !RCTL */
1851