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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 26 /* 27 * System calls for creating and inquiring about tasks and projects 28 */ 29 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/errno.h> 33 #include <sys/thread.h> 34 #include <sys/proc.h> 35 #include <sys/task.h> 36 #include <sys/systm.h> 37 #include <sys/project.h> 38 #include <sys/cpuvar.h> 39 #include <sys/policy.h> 40 #include <sys/zone.h> 41 #include <sys/rctl.h> 42 43 /* 44 * Limit projlist to 256k projects. 45 */ 46 #define MAX_PROJLIST_BUFSIZE 1048576 47 48 typedef struct projlist_walk { 49 projid_t *pw_buf; 50 size_t pw_bufsz; 51 } projlist_walk_t; 52 53 /* 54 * taskid_t tasksys_settaskid(projid_t projid, uint_t flags); 55 * 56 * Overview 57 * Place the calling process in a new task if sufficiently privileged. If the 58 * present task is finalized, the process may not create a new task. 59 * 60 * Return values 61 * 0 on success, errno on failure. 62 */ 63 static long 64 tasksys_settaskid(projid_t projid, uint_t flags) 65 { 66 proc_t *p = ttoproc(curthread); 67 kproject_t *oldpj; 68 kproject_t *kpj; 69 task_t *tk, *oldtk; 70 rctl_entity_p_t e; 71 zone_t *zone; 72 int rctlfail = 0; 73 74 if (secpolicy_tasksys(CRED()) != 0) 75 return (set_errno(EPERM)); 76 77 if (projid < 0 || projid > MAXPROJID) 78 return (set_errno(EINVAL)); 79 80 if (flags & ~TASK_FINAL) 81 return (set_errno(EINVAL)); 82 83 mutex_enter(&pidlock); 84 if (p->p_task->tk_flags & TASK_FINAL) { 85 mutex_exit(&pidlock); 86 return (set_errno(EACCES)); 87 } 88 mutex_exit(&pidlock); 89 90 /* 91 * Try to stop all other lwps in the process while we're changing 92 * our project. This way, curthread doesn't need to grab its own 93 * thread_lock to find its project ID (see curprojid()). If this 94 * is the /proc agent lwp, we know that the other lwps are already 95 * held. If we failed to hold all lwps, bail out and return EINTR. 96 */ 97 if (curthread != p->p_agenttp && !holdlwps(SHOLDFORK1)) 98 return (set_errno(EINTR)); 99 /* 100 * Put a hold on our new project and make sure that nobody is 101 * trying to bind it to a pool while we're joining. 102 */ 103 kpj = project_hold_by_id(projid, p->p_zone, PROJECT_HOLD_INSERT); 104 e.rcep_p.proj = kpj; 105 e.rcep_t = RCENTITY_PROJECT; 106 107 mutex_enter(&p->p_lock); 108 oldpj = p->p_task->tk_proj; 109 zone = p->p_zone; 110 111 mutex_enter(&zone->zone_nlwps_lock); 112 mutex_enter(&zone->zone_mem_lock); 113 114 if (kpj->kpj_nlwps + p->p_lwpcnt > kpj->kpj_nlwps_ctl) 115 if (rctl_test_entity(rc_project_nlwps, kpj->kpj_rctls, p, &e, 116 p->p_lwpcnt, 0) & RCT_DENY) 117 rctlfail = 1; 118 119 if (kpj->kpj_ntasks + 1 > kpj->kpj_ntasks_ctl) 120 if (rctl_test_entity(rc_project_ntasks, kpj->kpj_rctls, p, &e, 121 1, 0) & RCT_DENY) 122 rctlfail = 1; 123 124 if (kpj != proj0p && kpj->kpj_nprocs + 1 > kpj->kpj_nprocs_ctl) 125 if (rctl_test_entity(rc_project_nprocs, kpj->kpj_rctls, p, &e, 126 1, 0) & RCT_DENY) 127 rctlfail = 1; 128 129 if (kpj->kpj_data.kpd_locked_mem + p->p_locked_mem > 130 kpj->kpj_data.kpd_locked_mem_ctl) 131 if (rctl_test_entity(rc_project_locked_mem, kpj->kpj_rctls, p, 132 &e, p->p_locked_mem, 0) & RCT_DENY) 133 rctlfail = 1; 134 135 mutex_enter(&(kpj->kpj_data.kpd_crypto_lock)); 136 if (kpj->kpj_data.kpd_crypto_mem + p->p_crypto_mem > 137 kpj->kpj_data.kpd_crypto_mem_ctl) 138 if (rctl_test_entity(rc_project_crypto_mem, kpj->kpj_rctls, p, 139 &e, p->p_crypto_mem, 0) & RCT_DENY) 140 rctlfail = 1; 141 142 if (rctlfail) { 143 mutex_exit(&(kpj->kpj_data.kpd_crypto_lock)); 144 mutex_exit(&zone->zone_mem_lock); 145 mutex_exit(&zone->zone_nlwps_lock); 146 if (curthread != p->p_agenttp) 147 continuelwps(p); 148 mutex_exit(&p->p_lock); 149 return (set_errno(EAGAIN)); 150 } 151 kpj->kpj_data.kpd_crypto_mem += p->p_crypto_mem; 152 mutex_exit(&(kpj->kpj_data.kpd_crypto_lock)); 153 kpj->kpj_data.kpd_locked_mem += p->p_locked_mem; 154 kpj->kpj_nlwps += p->p_lwpcnt; 155 kpj->kpj_ntasks++; 156 kpj->kpj_nprocs++; 157 158 oldpj->kpj_data.kpd_locked_mem -= p->p_locked_mem; 159 mutex_enter(&(oldpj->kpj_data.kpd_crypto_lock)); 160 oldpj->kpj_data.kpd_crypto_mem -= p->p_crypto_mem; 161 mutex_exit(&(oldpj->kpj_data.kpd_crypto_lock)); 162 oldpj->kpj_nlwps -= p->p_lwpcnt; 163 oldpj->kpj_nprocs--; 164 165 mutex_exit(&zone->zone_mem_lock); 166 mutex_exit(&zone->zone_nlwps_lock); 167 mutex_exit(&p->p_lock); 168 169 mutex_enter(&kpj->kpj_poolbind); 170 tk = task_create(projid, curproc->p_zone); 171 mutex_enter(&cpu_lock); 172 /* 173 * Returns with p_lock held. 174 */ 175 oldtk = task_join(tk, flags); 176 if (curthread != p->p_agenttp) 177 continuelwps(p); 178 mutex_exit(&p->p_lock); 179 mutex_exit(&cpu_lock); 180 mutex_exit(&kpj->kpj_poolbind); 181 task_rele(oldtk); 182 project_rele(kpj); 183 return (tk->tk_tkid); 184 } 185 186 /* 187 * taskid_t tasksys_gettaskid(void); 188 * 189 * Overview 190 * Return the current task ID for this process. 191 * 192 * Return value 193 * The ID for the task to which the current process belongs. 194 */ 195 static long 196 tasksys_gettaskid() 197 { 198 long ret; 199 proc_t *p = ttoproc(curthread); 200 201 mutex_enter(&pidlock); 202 ret = p->p_task->tk_tkid; 203 mutex_exit(&pidlock); 204 return (ret); 205 } 206 207 /* 208 * projid_t tasksys_getprojid(void); 209 * 210 * Overview 211 * Return the current project ID for this process. 212 * 213 * Return value 214 * The ID for the project to which the current process belongs. 215 */ 216 static long 217 tasksys_getprojid() 218 { 219 long ret; 220 proc_t *p = ttoproc(curthread); 221 222 mutex_enter(&pidlock); 223 ret = p->p_task->tk_proj->kpj_id; 224 mutex_exit(&pidlock); 225 return (ret); 226 } 227 228 static int 229 tasksys_projlist_cb(kproject_t *kp, void *buf) 230 { 231 projlist_walk_t *pw = (projlist_walk_t *)buf; 232 233 if (pw && pw->pw_bufsz >= sizeof (projid_t)) { 234 *pw->pw_buf = kp->kpj_id; 235 pw->pw_buf++; 236 pw->pw_bufsz -= sizeof (projid_t); 237 } 238 239 return (0); 240 } 241 242 /* 243 * long tasksys_projlist(void *buf, size_t bufsz) 244 * 245 * Overview 246 * Return a buffer containing the project IDs of all currently active projects 247 * in the current zone. 248 * 249 * Return values 250 * The minimum size of a buffer sufficiently large to contain all of the 251 * active project IDs, or -1 if an error occurs during copyout. 252 */ 253 static long 254 tasksys_projlist(void *buf, size_t bufsz) 255 { 256 long ret = 0; 257 projlist_walk_t pw; 258 void *kbuf; 259 260 if (buf == NULL || bufsz == 0) 261 return (project_walk_all(getzoneid(), tasksys_projlist_cb, 262 NULL)); 263 264 if (bufsz > MAX_PROJLIST_BUFSIZE) 265 return (set_errno(ENOMEM)); 266 267 kbuf = pw.pw_buf = kmem_zalloc(bufsz, KM_SLEEP); 268 pw.pw_bufsz = bufsz; 269 270 ret = project_walk_all(getzoneid(), tasksys_projlist_cb, &pw); 271 272 if (copyout(kbuf, buf, bufsz) == -1) 273 ret = set_errno(EFAULT); 274 275 kmem_free(kbuf, bufsz); 276 return (ret); 277 } 278 279 long 280 tasksys(int code, projid_t projid, uint_t flags, void *projidbuf, size_t pbufsz) 281 { 282 switch (code) { 283 case 0: 284 return (tasksys_settaskid(projid, flags)); 285 case 1: 286 return (tasksys_gettaskid()); 287 case 2: 288 return (tasksys_getprojid()); 289 case 3: 290 return (tasksys_projlist(projidbuf, pbufsz)); 291 default: 292 return (set_errno(EINVAL)); 293 } 294 } 295