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