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(©->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