1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/cmn_err.h>
  28 #include <sys/sysmacros.h>
  29 #include <sys/proc.h>
  30 #include <sys/rctl.h>
  31 #include <sys/rctl_impl.h>
  32 #include <sys/port_kernel.h>
  33 #include <sys/signal.h>
  34 #include <sys/var.h>
  35 
  36 #include <sys/vmparam.h>
  37 #include <sys/machparam.h>
  38 
  39 /*
  40  * Process-based resource controls
  41  *   The structure of the kernel leaves us no particular place where the process
  42  *   abstraction can be declared--it is intertwined with the growth of the Unix
  43  *   kernel.  Accordingly, we place all of the resource control logic associated
  44  *   with processes, both existing and future, in this file.
  45  */
  46 
  47 rctl_hndl_t rctlproc_legacy[RLIM_NLIMITS];
  48 uint_t rctlproc_flags[RLIM_NLIMITS] = {
  49         RCTL_LOCAL_SIGNAL,                      /* RLIMIT_CPU   */
  50         RCTL_LOCAL_DENY | RCTL_LOCAL_SIGNAL,    /* RLIMIT_FSIZE */
  51         RCTL_LOCAL_DENY,                                /* RLIMIT_DATA  */
  52         RCTL_LOCAL_DENY,                                /* RLIMIT_STACK */
  53         RCTL_LOCAL_DENY,                                /* RLIMIT_CORE  */
  54         RCTL_LOCAL_DENY,                                /* RLIMIT_NOFILE */
  55         RCTL_LOCAL_DENY                         /* RLIMIT_VMEM  */
  56 };
  57 int rctlproc_signals[RLIM_NLIMITS] = {
  58         SIGXCPU,                                /* RLIMIT_CPU   */
  59         SIGXFSZ,                                /* RLIMIT_FSIZE */
  60         0, 0, 0, 0, 0                           /* remainder do not signal */
  61 };
  62 
  63 rctl_hndl_t rc_process_msgmnb;
  64 rctl_hndl_t rc_process_msgtql;
  65 rctl_hndl_t rc_process_semmsl;
  66 rctl_hndl_t rc_process_semopm;
  67 rctl_hndl_t rc_process_portev;
  68 rctl_hndl_t rc_process_sigqueue;
  69 
  70 /*
  71  * process.max-cpu-time / RLIMIT_CPU
  72  */
  73 /*ARGSUSED*/
  74 static int
  75 proc_cpu_time_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
  76     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
  77 {
  78         return (inc >= rval->rcv_value);
  79 }
  80 
  81 static rctl_ops_t proc_cpu_time_ops = {
  82         rcop_no_action,
  83         rcop_no_usage,
  84         rcop_no_set,
  85         proc_cpu_time_test
  86 };
  87 
  88 /*
  89  * process.max-file-size / RLIMIT_FSIZE
  90  */
  91 static int
  92 proc_filesize_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
  93     rctl_qty_t nv)
  94 {
  95         if (p->p_model == DATAMODEL_NATIVE)
  96                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
  97         else
  98                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
  99 
 100         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 101         e->rcep_p.proc->p_fsz_ctl = nv;
 102 
 103         return (0);
 104 }
 105 
 106 static rctl_ops_t proc_filesize_ops = {
 107         rcop_no_action,
 108         rcop_no_usage,
 109         proc_filesize_set,
 110         rcop_no_test
 111 };
 112 
 113 /*
 114  * process.max-data / RLIMIT_DATA
 115  */
 116 
 117 /*
 118  * process.max-stack-size / RLIMIT_STACK
 119  */
 120 static int
 121 proc_stack_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
 122     rctl_qty_t nv)
 123 {
 124         klwp_t *lwp = ttolwp(curthread);
 125 
 126         if (p->p_model == DATAMODEL_NATIVE)
 127                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 128         else
 129                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 130 
 131         /*
 132          * In the process of changing the rlimit, this function actually
 133          * gets called a number of times. We only want to save the current
 134          * rlimit the first time we come through here. In post_syscall(),
 135          * we copyin() the lwp's ustack, and compare it to the rlimit we
 136          * save here; if the two match, we adjust the ustack to reflect
 137          * the new stack bounds.
 138          *
 139          * We check to make sure that we're changing the rlimit of our
 140          * own process rather than on behalf of some other process. The
 141          * notion of changing this resource limit on behalf of another
 142          * process is problematic at best, and changing the amount of stack
 143          * space a process is allowed to consume is a rather antiquated
 144          * notion that has limited applicability in our multithreaded
 145          * process model.
 146          */
 147         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 148         if (lwp != NULL && lwp->lwp_procp == e->rcep_p.proc &&
 149             lwp->lwp_ustack && lwp->lwp_old_stk_ctl == 0) {
 150                 lwp->lwp_old_stk_ctl = (size_t)e->rcep_p.proc->p_stk_ctl;
 151                 curthread->t_post_sys = 1;
 152         }
 153 
 154         e->rcep_p.proc->p_stk_ctl = nv;
 155 
 156         return (0);
 157 }
 158 
 159 static rctl_ops_t proc_stack_ops = {
 160         rcop_no_action,
 161         rcop_no_usage,
 162         proc_stack_set,
 163         rcop_no_test
 164 };
 165 
 166 /*
 167  * process.max-file-descriptors / RLIMIT_NOFILE
 168  */
 169 static int
 170 proc_nofile_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
 171 {
 172         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 173         if (p->p_model == DATAMODEL_NATIVE)
 174                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 175         else
 176                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 177 
 178         e->rcep_p.proc->p_fno_ctl = nv;
 179 
 180         return (0);
 181 }
 182 
 183 static rctl_ops_t proc_nofile_ops = {
 184         rcop_no_action,
 185         rcop_no_usage,
 186         proc_nofile_set,
 187         rcop_absolute_test
 188 };
 189 
 190 /*
 191  * process.max-address-space / RLIMIT_VMEM
 192  */
 193 static int
 194 proc_vmem_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
 195 {
 196         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 197         if (p->p_model == DATAMODEL_ILP32)
 198                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 199         else
 200                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 201 
 202         e->rcep_p.proc->p_vmem_ctl = nv;
 203 
 204         return (0);
 205 }
 206 
 207 static rctl_ops_t proc_vmem_ops = {
 208         rcop_no_action,
 209         rcop_no_usage,
 210         proc_vmem_set,
 211         rcop_no_test
 212 };
 213 
 214 /*
 215  * void rctlproc_default_init()
 216  *
 217  * Overview
 218  *   Establish default basic and privileged control values on the init process.
 219  *   These correspond to the soft and hard limits, respectively.
 220  */
 221 void
 222 rctlproc_default_init(struct proc *initp, rctl_alloc_gp_t *gp)
 223 {
 224         struct rlimit64 rlp64;
 225 
 226         /*
 227          * RLIMIT_CPU: deny never, sigtoproc(pp, NULL, SIGXCPU).
 228          */
 229         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 230         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_CPU], initp, &rlp64, gp,
 231             RCTL_LOCAL_SIGNAL, SIGXCPU, kcred);
 232 
 233         /*
 234          * RLIMIT_FSIZE: deny always, sigtoproc(pp, NULL, SIGXFSZ).
 235          */
 236         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 237         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_FSIZE], initp, &rlp64, gp,
 238             RCTL_LOCAL_SIGNAL | RCTL_LOCAL_DENY, SIGXFSZ, kcred);
 239 
 240         /*
 241          * RLIMIT_DATA: deny always, no default action.
 242          */
 243         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 244         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_DATA], initp, &rlp64, gp,
 245             RCTL_LOCAL_DENY, 0, kcred);
 246 
 247         /*
 248          * RLIMIT_STACK: deny always, no default action.
 249          */
 250 #ifdef __sparc
 251         rlp64.rlim_cur = DFLSSIZ;
 252         rlp64.rlim_max = LONG_MAX;
 253 #else
 254         rlp64.rlim_cur = DFLSSIZ;
 255         rlp64.rlim_max = MAXSSIZ;
 256 #endif
 257         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_STACK], initp, &rlp64, gp,
 258             RCTL_LOCAL_DENY, 0, kcred);
 259 
 260         /*
 261          * RLIMIT_CORE: deny always, no default action.
 262          */
 263         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 264         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_CORE], initp, &rlp64, gp,
 265             RCTL_LOCAL_DENY, 0, kcred);
 266 
 267         /*
 268          * RLIMIT_NOFILE: deny always, no action.
 269          */
 270         rlp64.rlim_cur = rlim_fd_cur;
 271         rlp64.rlim_max = rlim_fd_max;
 272         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], initp, &rlp64,
 273             gp, RCTL_LOCAL_DENY, 0, kcred);
 274 
 275         /*
 276          * RLIMIT_VMEM
 277          */
 278         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 279         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_VMEM], initp, &rlp64, gp,
 280             RCTL_LOCAL_DENY, 0, kcred);
 281 }
 282 
 283 /*
 284  * void rctlproc_init()
 285  *
 286  * Overview
 287  *   Register the various resource controls associated with process entities.
 288  *   The historical rlim_infinity_map and rlim_infinity32_map are now encoded
 289  *   here as the native and ILP32 infinite values for each resource control.
 290  */
 291 void
 292 rctlproc_init(void)
 293 {
 294         rctl_set_t *set;
 295         rctl_alloc_gp_t *gp;
 296         rctl_entity_p_t e;
 297 
 298         rctlproc_legacy[RLIMIT_CPU] = rctl_register("process.max-cpu-time",
 299             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_NEVER |
 300             RCTL_GLOBAL_CPU_TIME | RCTL_GLOBAL_INFINITE | RCTL_GLOBAL_SECONDS,
 301             UINT64_MAX, UINT64_MAX, &proc_cpu_time_ops);
 302         rctlproc_legacy[RLIMIT_FSIZE] = rctl_register("process.max-file-size",
 303             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 304             RCTL_GLOBAL_FILE_SIZE | RCTL_GLOBAL_BYTES,
 305             MAXOFFSET_T, MAXOFFSET_T, &proc_filesize_ops);
 306         rctlproc_legacy[RLIMIT_DATA] = rctl_register("process.max-data-size",
 307             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 308             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 309             ULONG_MAX, UINT32_MAX, &rctl_default_ops);
 310 #ifdef _LP64
 311 #ifdef __sparc
 312         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 313             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 314             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 315             LONG_MAX, INT32_MAX, &proc_stack_ops);
 316 #else   /* __sparc */
 317         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 318             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 319             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 320             MAXSSIZ, USRSTACK32 - PAGESIZE, &proc_stack_ops);
 321 #endif  /* __sparc */
 322 #else   /* _LP64 */
 323         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 324             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 325             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 326             USRSTACK - PAGESIZE, USRSTACK - PAGESIZE, &proc_stack_ops);
 327 #endif
 328         rctlproc_legacy[RLIMIT_CORE] = rctl_register("process.max-core-size",
 329             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 330             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 331             MIN(MAXOFFSET_T, ULONG_MAX), UINT32_MAX, &rctl_default_ops);
 332         rctlproc_legacy[RLIMIT_NOFILE] = rctl_register(
 333             "process.max-file-descriptor", RCENTITY_PROCESS,
 334             RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 335             RCTL_GLOBAL_COUNT, INT32_MAX, INT32_MAX, &proc_nofile_ops);
 336         rctlproc_legacy[RLIMIT_VMEM] =
 337             rctl_register("process.max-address-space", RCENTITY_PROCESS,
 338             RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 339             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 340             ULONG_MAX, UINT32_MAX, &proc_vmem_ops);
 341 
 342         rc_process_semmsl = rctl_register("process.max-sem-nsems",
 343             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 344             SHRT_MAX, SHRT_MAX, &rctl_absolute_ops);
 345         rctl_add_legacy_limit("process.max-sem-nsems", "semsys",
 346             "seminfo_semmsl", 512, SHRT_MAX);
 347 
 348         rc_process_semopm = rctl_register("process.max-sem-ops",
 349             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 350             INT_MAX, INT_MAX, &rctl_absolute_ops);
 351         rctl_add_legacy_limit("process.max-sem-ops", "semsys",
 352             "seminfo_semopm", 512, INT_MAX);
 353 
 354         rc_process_msgmnb = rctl_register("process.max-msg-qbytes",
 355             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_BYTES,
 356             ULONG_MAX, ULONG_MAX, &rctl_absolute_ops);
 357         rctl_add_legacy_limit("process.max-msg-qbytes", "msgsys",
 358             "msginfo_msgmnb", 65536, ULONG_MAX);
 359 
 360         rc_process_msgtql = rctl_register("process.max-msg-messages",
 361             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 362             UINT_MAX, UINT_MAX, &rctl_absolute_ops);
 363         rctl_add_legacy_limit("process.max-msg-messages", "msgsys",
 364             "msginfo_msgtql", 8192, UINT_MAX);
 365 
 366         rc_process_portev = rctl_register("process.max-port-events",
 367             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 368             PORT_MAX_EVENTS, PORT_MAX_EVENTS, &rctl_absolute_ops);
 369         rctl_add_default_limit("process.max-port-events", PORT_DEFAULT_EVENTS,
 370             RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
 371 
 372         rc_process_sigqueue = rctl_register("process.max-sigqueue-size",
 373             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 374             RCTL_GLOBAL_COUNT, v.v_maxup, v.v_maxup,
 375             &rctl_absolute_ops);
 376         rctl_add_default_limit("process.max-sigqueue-size",
 377             _SIGQUEUE_SIZE_BASIC, RCPRIV_BASIC, RCTL_LOCAL_DENY);
 378         rctl_add_default_limit("process.max-sigqueue-size",
 379             _SIGQUEUE_SIZE_PRIVILEGED, RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
 380 
 381         /*
 382          * Place minimal set of controls on "sched" process for inheritance by
 383          * processes created via newproc().
 384          */
 385         set = rctl_set_create();
 386         gp = rctl_set_init_prealloc(RCENTITY_PROCESS);
 387         mutex_enter(&curproc->p_lock);
 388         e.rcep_p.proc = curproc;
 389         e.rcep_t = RCENTITY_PROCESS;
 390         curproc->p_rctls = rctl_set_init(RCENTITY_PROCESS, curproc, &e,
 391             set, gp);
 392         mutex_exit(&curproc->p_lock);
 393         rctl_prealloc_destroy(gp);
 394 }