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 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/types.h>
  29 #include <sys/cmn_err.h>
  30 #include <sys/sysmacros.h>
  31 #include <sys/proc.h>
  32 #include <sys/rctl.h>
  33 #include <sys/rctl_impl.h>
  34 #include <sys/port_kernel.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 
  69 /*
  70  * process.max-cpu-time / RLIMIT_CPU
  71  */
  72 /*ARGSUSED*/
  73 static int
  74 proc_cpu_time_test(struct rctl *rctl, struct proc *p, rctl_entity_p_t *e,
  75     rctl_val_t *rval, rctl_qty_t inc, uint_t flags)
  76 {
  77         return (inc >= rval->rcv_value);
  78 }
  79 
  80 static rctl_ops_t proc_cpu_time_ops = {
  81         rcop_no_action,
  82         rcop_no_usage,
  83         rcop_no_set,
  84         proc_cpu_time_test
  85 };
  86 
  87 /*
  88  * process.max-file-size / RLIMIT_FSIZE
  89  */
  90 static int
  91 proc_filesize_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
  92     rctl_qty_t nv)
  93 {
  94         if (p->p_model == DATAMODEL_NATIVE)
  95                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
  96         else
  97                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
  98 
  99         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 100         e->rcep_p.proc->p_fsz_ctl = nv;
 101 
 102         return (0);
 103 }
 104 
 105 static rctl_ops_t proc_filesize_ops = {
 106         rcop_no_action,
 107         rcop_no_usage,
 108         proc_filesize_set,
 109         rcop_no_test
 110 };
 111 
 112 /*
 113  * process.max-data / RLIMIT_DATA
 114  */
 115 
 116 /*
 117  * process.max-stack-size / RLIMIT_STACK
 118  */
 119 static int
 120 proc_stack_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
 121     rctl_qty_t nv)
 122 {
 123         klwp_t *lwp = ttolwp(curthread);
 124 
 125         if (p->p_model == DATAMODEL_NATIVE)
 126                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 127         else
 128                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 129 
 130         /*
 131          * In the process of changing the rlimit, this function actually
 132          * gets called a number of times. We only want to save the current
 133          * rlimit the first time we come through here. In post_syscall(),
 134          * we copyin() the lwp's ustack, and compare it to the rlimit we
 135          * save here; if the two match, we adjust the ustack to reflect
 136          * the new stack bounds.
 137          *
 138          * We check to make sure that we're changing the rlimit of our
 139          * own process rather than on behalf of some other process. The
 140          * notion of changing this resource limit on behalf of another
 141          * process is problematic at best, and changing the amount of stack
 142          * space a process is allowed to consume is a rather antiquated
 143          * notion that has limited applicability in our multithreaded
 144          * process model.
 145          */
 146         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 147         if (lwp != NULL && lwp->lwp_procp == e->rcep_p.proc &&
 148             lwp->lwp_ustack && lwp->lwp_old_stk_ctl == 0) {
 149                 lwp->lwp_old_stk_ctl = (size_t)e->rcep_p.proc->p_stk_ctl;
 150                 curthread->t_post_sys = 1;
 151         }
 152 
 153         e->rcep_p.proc->p_stk_ctl = nv;
 154 
 155         return (0);
 156 }
 157 
 158 static rctl_ops_t proc_stack_ops = {
 159         rcop_no_action,
 160         rcop_no_usage,
 161         proc_stack_set,
 162         rcop_no_test
 163 };
 164 
 165 /*
 166  * process.max-file-descriptors / RLIMIT_NOFILE
 167  */
 168 static int
 169 proc_nofile_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
 170 {
 171         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 172         if (p->p_model == DATAMODEL_NATIVE)
 173                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 174         else
 175                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 176 
 177         e->rcep_p.proc->p_fno_ctl = nv;
 178 
 179         return (0);
 180 }
 181 
 182 static rctl_ops_t proc_nofile_ops = {
 183         rcop_no_action,
 184         rcop_no_usage,
 185         proc_nofile_set,
 186         rcop_absolute_test
 187 };
 188 
 189 /*
 190  * process.max-address-space / RLIMIT_VMEM
 191  */
 192 static int
 193 proc_vmem_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e, rctl_qty_t nv)
 194 {
 195         ASSERT(e->rcep_t == RCENTITY_PROCESS);
 196         if (p->p_model == DATAMODEL_ILP32)
 197                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_ilp32);
 198         else
 199                 nv = MIN(nv, rctl->rc_dict_entry->rcd_max_native);
 200 
 201         e->rcep_p.proc->p_vmem_ctl = nv;
 202 
 203         return (0);
 204 }
 205 
 206 static rctl_ops_t proc_vmem_ops = {
 207         rcop_no_action,
 208         rcop_no_usage,
 209         proc_vmem_set,
 210         rcop_no_test
 211 };
 212 
 213 /*
 214  * void rctlproc_default_init()
 215  *
 216  * Overview
 217  *   Establish default basic and privileged control values on the init process.
 218  *   These correspond to the soft and hard limits, respectively.
 219  */
 220 void
 221 rctlproc_default_init(struct proc *initp, rctl_alloc_gp_t *gp)
 222 {
 223         struct rlimit64 rlp64;
 224 
 225         /*
 226          * RLIMIT_CPU: deny never, sigtoproc(pp, NULL, SIGXCPU).
 227          */
 228         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 229         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_CPU], initp, &rlp64, gp,
 230             RCTL_LOCAL_SIGNAL, SIGXCPU, kcred);
 231 
 232         /*
 233          * RLIMIT_FSIZE: deny always, sigtoproc(pp, NULL, SIGXFSZ).
 234          */
 235         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 236         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_FSIZE], initp, &rlp64, gp,
 237             RCTL_LOCAL_SIGNAL | RCTL_LOCAL_DENY, SIGXFSZ, kcred);
 238 
 239         /*
 240          * RLIMIT_DATA: deny always, no default action.
 241          */
 242         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 243         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_DATA], initp, &rlp64, gp,
 244             RCTL_LOCAL_DENY, 0, kcred);
 245 
 246         /*
 247          * RLIMIT_STACK: deny always, no default action.
 248          */
 249 #ifdef __sparc
 250         rlp64.rlim_cur = DFLSSIZ;
 251         rlp64.rlim_max = LONG_MAX;
 252 #else
 253         rlp64.rlim_cur = DFLSSIZ;
 254         rlp64.rlim_max = MAXSSIZ;
 255 #endif
 256         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_STACK], initp, &rlp64, gp,
 257             RCTL_LOCAL_DENY, 0, kcred);
 258 
 259         /*
 260          * RLIMIT_CORE: deny always, no default action.
 261          */
 262         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 263         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_CORE], initp, &rlp64, gp,
 264             RCTL_LOCAL_DENY, 0, kcred);
 265 
 266         /*
 267          * RLIMIT_NOFILE: deny always, no action.
 268          */
 269         rlp64.rlim_cur = rlim_fd_cur;
 270         rlp64.rlim_max = rlim_fd_max;
 271         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_NOFILE], initp, &rlp64,
 272             gp, RCTL_LOCAL_DENY, 0, kcred);
 273 
 274         /*
 275          * RLIMIT_VMEM
 276          */
 277         rlp64.rlim_cur = rlp64.rlim_max = RLIM64_INFINITY;
 278         (void) rctl_rlimit_set(rctlproc_legacy[RLIMIT_VMEM], initp, &rlp64, gp,
 279             RCTL_LOCAL_DENY, 0, kcred);
 280 }
 281 
 282 /*
 283  * void rctlproc_init()
 284  *
 285  * Overview
 286  *   Register the various resource controls associated with process entities.
 287  *   The historical rlim_infinity_map and rlim_infinity32_map are now encoded
 288  *   here as the native and ILP32 infinite values for each resource control.
 289  */
 290 void
 291 rctlproc_init()
 292 {
 293         rctl_set_t *set;
 294         rctl_alloc_gp_t *gp;
 295         rctl_entity_p_t e;
 296 
 297         rctlproc_legacy[RLIMIT_CPU] = rctl_register("process.max-cpu-time",
 298             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_NEVER |
 299             RCTL_GLOBAL_CPU_TIME | RCTL_GLOBAL_INFINITE | RCTL_GLOBAL_SECONDS,
 300             UINT64_MAX, UINT64_MAX, &proc_cpu_time_ops);
 301         rctlproc_legacy[RLIMIT_FSIZE] = rctl_register("process.max-file-size",
 302             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 303             RCTL_GLOBAL_FILE_SIZE | RCTL_GLOBAL_BYTES,
 304             MAXOFFSET_T, MAXOFFSET_T, &proc_filesize_ops);
 305         rctlproc_legacy[RLIMIT_DATA] = rctl_register("process.max-data-size",
 306             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 307             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 308             ULONG_MAX, UINT32_MAX, &rctl_default_ops);
 309 #ifdef _LP64
 310 #ifdef __sparc
 311         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 312             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 313             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 314             LONG_MAX, INT32_MAX, &proc_stack_ops);
 315 #else   /* __sparc */
 316         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 317             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 318             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 319             MAXSSIZ, USRSTACK32 - PAGESIZE, &proc_stack_ops);
 320 #endif  /* __sparc */
 321 #else   /* _LP64 */
 322         rctlproc_legacy[RLIMIT_STACK] = rctl_register("process.max-stack-size",
 323             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 324             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 325             USRSTACK - PAGESIZE, USRSTACK - PAGESIZE, &proc_stack_ops);
 326 #endif
 327         rctlproc_legacy[RLIMIT_CORE] = rctl_register("process.max-core-size",
 328             RCENTITY_PROCESS, RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 329             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 330             MIN(MAXOFFSET_T, ULONG_MAX), UINT32_MAX, &rctl_default_ops);
 331         rctlproc_legacy[RLIMIT_NOFILE] = rctl_register(
 332             "process.max-file-descriptor", RCENTITY_PROCESS,
 333             RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 334             RCTL_GLOBAL_COUNT, INT32_MAX, INT32_MAX, &proc_nofile_ops);
 335         rctlproc_legacy[RLIMIT_VMEM] =
 336             rctl_register("process.max-address-space", RCENTITY_PROCESS,
 337             RCTL_GLOBAL_LOWERABLE | RCTL_GLOBAL_DENY_ALWAYS |
 338             RCTL_GLOBAL_SIGNAL_NEVER | RCTL_GLOBAL_BYTES,
 339             ULONG_MAX, UINT32_MAX, &proc_vmem_ops);
 340 
 341         rc_process_semmsl = rctl_register("process.max-sem-nsems",
 342             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 343             SHRT_MAX, SHRT_MAX, &rctl_absolute_ops);
 344         rctl_add_legacy_limit("process.max-sem-nsems", "semsys",
 345             "seminfo_semmsl", 512, SHRT_MAX);
 346 
 347         rc_process_semopm = rctl_register("process.max-sem-ops",
 348             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 349             INT_MAX, INT_MAX, &rctl_absolute_ops);
 350         rctl_add_legacy_limit("process.max-sem-ops", "semsys",
 351             "seminfo_semopm", 512, INT_MAX);
 352 
 353         rc_process_msgmnb = rctl_register("process.max-msg-qbytes",
 354             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_BYTES,
 355             ULONG_MAX, ULONG_MAX, &rctl_absolute_ops);
 356         rctl_add_legacy_limit("process.max-msg-qbytes", "msgsys",
 357             "msginfo_msgmnb", 65536, ULONG_MAX);
 358 
 359         rc_process_msgtql = rctl_register("process.max-msg-messages",
 360             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 361             UINT_MAX, UINT_MAX, &rctl_absolute_ops);
 362         rctl_add_legacy_limit("process.max-msg-messages", "msgsys",
 363             "msginfo_msgtql", 8192, UINT_MAX);
 364 
 365         rc_process_portev = rctl_register("process.max-port-events",
 366             RCENTITY_PROCESS, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
 367             PORT_MAX_EVENTS, PORT_MAX_EVENTS, &rctl_absolute_ops);
 368         rctl_add_default_limit("process.max-port-events", PORT_DEFAULT_EVENTS,
 369             RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
 370 
 371         /*
 372          * Place minimal set of controls on "sched" process for inheritance by
 373          * processes created via newproc().
 374          */
 375         set = rctl_set_create();
 376         gp = rctl_set_init_prealloc(RCENTITY_PROCESS);
 377         mutex_enter(&curproc->p_lock);
 378         e.rcep_p.proc = curproc;
 379         e.rcep_t = RCENTITY_PROCESS;
 380         curproc->p_rctls = rctl_set_init(RCENTITY_PROCESS, curproc, &e,
 381             set, gp);
 382         mutex_exit(&curproc->p_lock);
 383         rctl_prealloc_destroy(gp);
 384 }