Print this page
6141 use kmem_zalloc instead of kmem_alloc + bzero/memset
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/syscall/rctlsys.c
+++ new/usr/src/uts/common/syscall/rctlsys.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27
28 28 #include <sys/cmn_err.h>
29 29 #include <sys/cred.h>
30 30 #include <sys/errno.h>
31 31 #include <sys/rctl.h>
32 32 #include <sys/rctl_impl.h>
33 33 #include <sys/strlog.h>
34 34 #include <sys/syslog.h>
35 35 #include <sys/sysmacros.h>
36 36 #include <sys/systm.h>
37 37 #include <sys/policy.h>
38 38 #include <sys/proc.h>
39 39 #include <sys/task.h>
40 40
41 41 /*
42 42 * setrctl(2), getrctl(2), and private rctlsys(2*) system calls
43 43 *
44 44 * Resource control block (rctlblk_ptr_t, rctl_opaque_t)
45 45 * The resource control system call interfaces present the resource control
46 46 * values and flags via the resource control block abstraction, made manifest
47 47 * via an opaque data type with strict type definitions. Keeping the formal
48 48 * definitions in the rcontrol block allows us to be clever in the kernel,
49 49 * combining attributes where appropriate in the current implementation while
50 50 * preserving binary compatibility in the face of implementation changes.
51 51 */
52 52
53 53 #define RBX_TO_BLK 0x1
54 54 #define RBX_FROM_BLK 0x2
55 55 #define RBX_VAL 0x4
56 56 #define RBX_CTL 0x8
57 57
58 58 static void
59 59 rctlsys_rblk_xfrm(rctl_opaque_t *blk, rctl_dict_entry_t *rde,
60 60 rctl_val_t *val, int flags)
61 61 {
62 62 if (flags & RBX_FROM_BLK) {
63 63 if (flags & RBX_VAL) {
64 64 /*
65 65 * Firing time cannot be set.
66 66 */
67 67 val->rcv_privilege = blk->rcq_privilege;
68 68 val->rcv_value = blk->rcq_value;
69 69 val->rcv_flagaction = blk->rcq_local_flagaction;
70 70 val->rcv_action_signal = blk->rcq_local_signal;
71 71 val->rcv_action_recip_pid =
72 72 blk->rcq_local_recipient_pid;
73 73 }
74 74 if (flags & RBX_CTL) {
75 75 rde->rcd_flagaction = blk->rcq_global_flagaction;
76 76 rde->rcd_syslog_level = blk->rcq_global_syslog_level;
77 77
78 78 /*
79 79 * Because the strlog() interface supports fewer options
80 80 * than are made available via the syslog() interface to
81 81 * userland, we map the syslog level down to a smaller
82 82 * set of distinct logging behaviours.
83 83 */
84 84 rde->rcd_strlog_flags = 0;
85 85 switch (blk->rcq_global_syslog_level) {
86 86 case LOG_EMERG:
87 87 case LOG_ALERT:
88 88 case LOG_CRIT:
89 89 rde->rcd_strlog_flags |= SL_CONSOLE;
90 90 /*FALLTHROUGH*/
91 91 case LOG_ERR:
92 92 rde->rcd_strlog_flags |= SL_ERROR;
93 93 /*FALLTHROUGH*/
94 94 case LOG_WARNING:
95 95 rde->rcd_strlog_flags |= SL_WARN;
96 96 break;
97 97 case LOG_NOTICE:
98 98 rde->rcd_strlog_flags |= SL_CONSOLE;
99 99 /*FALLTHROUGH*/
100 100 case LOG_INFO: /* informational */
101 101 case LOG_DEBUG: /* debug-level messages */
102 102 default:
103 103 rde->rcd_strlog_flags |= SL_NOTE;
104 104 break;
105 105 }
106 106 }
107 107 } else {
108 108 bzero(blk, sizeof (rctl_opaque_t));
109 109 if (flags & RBX_VAL) {
110 110 blk->rcq_privilege = val->rcv_privilege;
111 111 blk->rcq_value = val->rcv_value;
112 112 blk->rcq_enforced_value = rctl_model_value(rde,
113 113 curproc, val->rcv_value);
114 114 blk->rcq_local_flagaction = val->rcv_flagaction;
115 115 blk->rcq_local_signal = val->rcv_action_signal;
116 116 blk->rcq_firing_time = val->rcv_firing_time;
117 117 blk->rcq_local_recipient_pid =
118 118 val->rcv_action_recip_pid;
119 119 }
120 120 if (flags & RBX_CTL) {
121 121 blk->rcq_global_flagaction = rde->rcd_flagaction;
122 122 blk->rcq_global_syslog_level = rde->rcd_syslog_level;
123 123 }
124 124 }
125 125 }
126 126
127 127 /*
128 128 * int rctl_invalid_value(rctl_dict_entry_t *, rctl_val_t *)
129 129 *
130 130 * Overview
131 131 * Perform basic validation of proposed new resource control value against the
132 132 * global properties set on the control. Any system call operation presented
133 133 * with an invalid resource control value should return -1 and set errno to
134 134 * EINVAL.
135 135 *
136 136 * Return values
137 137 * 0 if valid, 1 if invalid.
138 138 *
139 139 * Caller's context
140 140 * No restriction on context.
141 141 */
142 142 int
143 143 rctl_invalid_value(rctl_dict_entry_t *rde, rctl_val_t *rval)
144 144 {
145 145 rctl_val_t *sys_rval;
146 146
147 147 if (rval->rcv_privilege != RCPRIV_BASIC &&
148 148 rval->rcv_privilege != RCPRIV_PRIVILEGED &&
149 149 rval->rcv_privilege != RCPRIV_SYSTEM)
150 150 return (1);
151 151
152 152 if (rval->rcv_flagaction & ~RCTL_LOCAL_MASK)
153 153 return (1);
154 154
155 155 if (rval->rcv_privilege == RCPRIV_BASIC &&
156 156 (rde->rcd_flagaction & RCTL_GLOBAL_NOBASIC) != 0)
157 157 return (1);
158 158
159 159 if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) == 0 &&
160 160 (rde->rcd_flagaction & RCTL_GLOBAL_DENY_ALWAYS) != 0)
161 161 return (1);
162 162
163 163 if ((rval->rcv_flagaction & RCTL_LOCAL_DENY) &&
164 164 (rde->rcd_flagaction & RCTL_GLOBAL_DENY_NEVER))
165 165 return (1);
166 166
167 167 if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) &&
168 168 (rde->rcd_flagaction & RCTL_GLOBAL_SIGNAL_NEVER))
169 169 return (1);
170 170
171 171 if ((rval->rcv_flagaction & RCTL_LOCAL_SIGNAL) &&
172 172 rval->rcv_action_signal == 0)
173 173 return (1);
174 174
175 175 if (rval->rcv_action_signal == SIGXCPU &&
176 176 (rde->rcd_flagaction & RCTL_GLOBAL_CPU_TIME) == 0)
177 177 return (1);
178 178 else if (rval->rcv_action_signal == SIGXFSZ &&
179 179 (rde->rcd_flagaction & RCTL_GLOBAL_FILE_SIZE) == 0)
180 180 return (1);
181 181 else if (rval->rcv_action_signal != SIGHUP &&
182 182 rval->rcv_action_signal != SIGABRT &&
183 183 rval->rcv_action_signal != SIGKILL &&
184 184 rval->rcv_action_signal != SIGTERM &&
185 185 rval->rcv_action_signal != SIGSTOP &&
186 186 rval->rcv_action_signal != SIGXCPU &&
187 187 rval->rcv_action_signal != SIGXFSZ &&
188 188 rval->rcv_action_signal != SIGXRES &&
189 189 rval->rcv_action_signal != 0) /* That is, no signal is ok. */
190 190 return (1);
191 191
192 192 sys_rval = rde->rcd_default_value;
193 193 while (sys_rval->rcv_privilege != RCPRIV_SYSTEM)
194 194 sys_rval = sys_rval->rcv_next;
195 195
196 196 if (rval->rcv_value > sys_rval->rcv_value)
197 197 return (1);
198 198
199 199 return (0);
200 200 }
201 201
202 202 /*
203 203 * static long rctlsys_get(char *name, rctl_opaque_t *old_rblk,
204 204 * rctl_opaque_t *new_rblk, int flags)
205 205 *
206 206 * Overview
207 207 * rctlsys_get() is the implementation of the core logic of getrctl(2), the
208 208 * public system call for fetching resource control values. Three mutually
209 209 * exclusive flag values are supported: RCTL_USAGE, RCTL_FIRST and RCTL_NEXT.
210 210 * When RCTL_USAGE is presented, the current usage for the resource control
211 211 * is returned in new_blk if the resource control provides an implementation
212 212 * of the usage operation. When RCTL_FIRST is presented, the value of
213 213 * old_rblk is ignored, and the first value in the resource control value
214 214 * sequence for the named control is transformed and placed in the user
215 215 * memory location at new_rblk. In the RCTL_NEXT case, the value of old_rblk
216 216 * is examined, and the next value in the sequence is transformed and placed
217 217 * at new_rblk.
218 218 */
219 219 static long
220 220 rctlsys_get(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk,
221 221 int flags)
222 222 {
223 223 rctl_val_t *nval;
224 224 rctl_opaque_t *nblk;
225 225 rctl_hndl_t hndl;
226 226 char *kname;
227 227 size_t klen;
228 228 rctl_dict_entry_t *krde;
229 229 int ret;
230 230 int action = flags & (~RCTLSYS_ACTION_MASK);
231 231
232 232 if (flags & (~RCTLSYS_MASK))
233 233 return (set_errno(EINVAL));
234 234
235 235 if (action != RCTL_FIRST && action != RCTL_NEXT &&
236 236 action != RCTL_USAGE)
237 237 return (set_errno(EINVAL));
238 238
239 239 if (new_rblk == NULL || name == NULL)
240 240 return (set_errno(EFAULT));
241 241
242 242 kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
243 243 krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
244 244
245 245 if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
246 246 kmem_free(kname, MAXPATHLEN);
247 247 kmem_free(krde, sizeof (rctl_dict_entry_t));
248 248 return (set_errno(EFAULT));
249 249 }
250 250
251 251 if ((hndl = rctl_hndl_lookup(kname)) == -1) {
252 252 kmem_free(kname, MAXPATHLEN);
253 253 kmem_free(krde, sizeof (rctl_dict_entry_t));
254 254 return (set_errno(EINVAL));
255 255 }
256 256
257 257 if (rctl_global_get(kname, krde) == -1) {
258 258 kmem_free(kname, MAXPATHLEN);
259 259 kmem_free(krde, sizeof (rctl_dict_entry_t));
260 260 return (set_errno(ESRCH));
261 261 }
262 262
263 263 kmem_free(kname, MAXPATHLEN);
264 264
265 265 if (action != RCTL_USAGE)
266 266 nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
267 267
268 268 if (action == RCTL_USAGE) {
269 269 rctl_set_t *rset;
270 270 rctl_t *rctl;
271 271 rctl_qty_t usage;
272 272
273 273 mutex_enter(&curproc->p_lock);
274 274 if ((rset = rctl_entity_obtain_rset(krde, curproc)) == NULL) {
275 275 mutex_exit(&curproc->p_lock);
276 276 kmem_free(krde, sizeof (rctl_dict_entry_t));
277 277 return (set_errno(ESRCH));
278 278 }
279 279 mutex_enter(&rset->rcs_lock);
280 280 if (rctl_set_find(rset, hndl, &rctl) == -1) {
281 281 mutex_exit(&rset->rcs_lock);
282 282 mutex_exit(&curproc->p_lock);
283 283 kmem_free(krde, sizeof (rctl_dict_entry_t));
284 284 return (set_errno(ESRCH));
285 285 }
↓ open down ↓ |
285 lines elided |
↑ open up ↑ |
286 286 if (RCTLOP_NO_USAGE(rctl)) {
287 287 mutex_exit(&rset->rcs_lock);
288 288 mutex_exit(&curproc->p_lock);
289 289 kmem_free(krde, sizeof (rctl_dict_entry_t));
290 290 return (set_errno(ENOTSUP));
291 291 }
292 292 usage = RCTLOP_GET_USAGE(rctl, curproc);
293 293 mutex_exit(&rset->rcs_lock);
294 294 mutex_exit(&curproc->p_lock);
295 295
296 - nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
297 - bzero(nblk, sizeof (rctl_opaque_t));
296 + nblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP);
298 297 nblk->rcq_value = usage;
299 298
300 299 ret = copyout(nblk, new_rblk, sizeof (rctl_opaque_t));
301 300 kmem_free(nblk, sizeof (rctl_opaque_t));
302 301 kmem_free(krde, sizeof (rctl_dict_entry_t));
303 302 return (ret == 0 ? 0 : set_errno(EFAULT));
304 303 } else if (action == RCTL_FIRST) {
305 304
306 305 mutex_enter(&curproc->p_lock);
307 306 if (ret = rctl_local_get(hndl, NULL, nval, curproc)) {
308 307 mutex_exit(&curproc->p_lock);
309 308 kmem_cache_free(rctl_val_cache, nval);
310 309 kmem_free(krde, sizeof (rctl_dict_entry_t));
311 310 return (set_errno(ret));
312 311 }
313 312 mutex_exit(&curproc->p_lock);
314 313 } else {
315 314 /*
316 315 * RCTL_NEXT
317 316 */
318 317 rctl_val_t *oval;
319 318 rctl_opaque_t *oblk;
320 319
321 320 oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
322 321
323 322 if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) {
324 323 kmem_cache_free(rctl_val_cache, nval);
325 324 kmem_free(oblk, sizeof (rctl_opaque_t));
326 325 kmem_free(krde, sizeof (rctl_dict_entry_t));
327 326 return (set_errno(EFAULT));
328 327 }
329 328
330 329 oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
331 330
332 331 rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL);
333 332 mutex_enter(&curproc->p_lock);
334 333 ret = rctl_local_get(hndl, oval, nval, curproc);
335 334 mutex_exit(&curproc->p_lock);
336 335
337 336 kmem_cache_free(rctl_val_cache, oval);
338 337 kmem_free(oblk, sizeof (rctl_opaque_t));
339 338
340 339 if (ret != 0) {
341 340 kmem_cache_free(rctl_val_cache, nval);
342 341 kmem_free(krde, sizeof (rctl_dict_entry_t));
343 342 return (set_errno(ret));
344 343 }
345 344 }
346 345
347 346 nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
348 347
349 348 rctlsys_rblk_xfrm(nblk, krde, nval, RBX_TO_BLK | RBX_VAL | RBX_CTL);
350 349
351 350 kmem_free(krde, sizeof (rctl_dict_entry_t));
352 351 kmem_cache_free(rctl_val_cache, nval);
353 352
354 353 if (copyout(nblk, new_rblk, sizeof (rctl_opaque_t)) == -1) {
355 354 kmem_free(nblk, sizeof (rctl_opaque_t));
356 355 return (set_errno(EFAULT));
357 356 }
358 357
359 358 kmem_free(nblk, sizeof (rctl_opaque_t));
360 359
361 360 return (0);
362 361 }
363 362
364 363 /*
365 364 * static long rctlsys_set(char *name, rctl_opaque_t *old_rblk,
366 365 * rctl_opaque_t *new_rblk, int flags)
367 366 *
368 367 * Overview
369 368 * rctlsys_set() is the implementation of the core login of setrctl(2), which
370 369 * allows the establishment of resource control values. Flags may take on any
371 370 * of three exclusive values: RCTL_INSERT, RCTL_DELETE, and RCTL_REPLACE.
372 371 * RCTL_INSERT ignores old_rblk and inserts the value in the appropriate
373 372 * position in the ordered sequence of resource control values. RCTL_DELETE
374 373 * ignores old_rblk and deletes the first resource control value matching
375 374 * (value, priority) in the given resource block. If no matching value is
376 375 * found, -1 is returned and errno is set to ENOENT. Finally, in the case of
377 376 * RCTL_REPLACE, old_rblk is used to match (value, priority); the matching
378 377 * resource control value in the sequence is replaced with the contents of
379 378 * new_rblk. Again, if no match is found, -1 is returned and errno is set to
380 379 * ENOENT.
381 380 *
382 381 * rctlsys_set() causes a cursor test, which can reactivate resource controls
383 382 * that have previously fired.
384 383 */
385 384 static long
386 385 rctlsys_set(char *name, rctl_opaque_t *old_rblk, rctl_opaque_t *new_rblk,
387 386 int flags)
388 387 {
389 388 rctl_val_t *nval;
390 389 rctl_dict_entry_t *rde;
391 390 rctl_opaque_t *nblk;
392 391 rctl_hndl_t hndl;
393 392 char *kname;
394 393 size_t klen;
395 394 long ret = 0;
396 395 proc_t *pp = NULL;
397 396 pid_t pid;
398 397 int action = flags & (~RCTLSYS_ACTION_MASK);
399 398 rctl_val_t *oval;
400 399 rctl_val_t *rval1;
401 400 rctl_val_t *rval2;
402 401 rctl_val_t *tval;
403 402 rctl_opaque_t *oblk;
404 403
405 404 if (flags & (~RCTLSYS_MASK))
406 405 return (set_errno(EINVAL));
407 406
408 407 if (action != RCTL_INSERT &&
409 408 action != RCTL_DELETE &&
410 409 action != RCTL_REPLACE)
411 410 return (set_errno(EINVAL));
412 411
413 412 if (new_rblk == NULL || name == NULL)
414 413 return (set_errno(EFAULT));
415 414
416 415 kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
417 416 if (copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
418 417 kmem_free(kname, MAXPATHLEN);
419 418 return (set_errno(EFAULT));
420 419 }
421 420
422 421 if ((hndl = rctl_hndl_lookup(kname)) == -1) {
423 422 kmem_free(kname, MAXPATHLEN);
424 423 return (set_errno(EINVAL));
425 424 }
426 425
427 426 kmem_free(kname, MAXPATHLEN);
428 427
429 428 rde = rctl_dict_lookup_hndl(hndl);
430 429
431 430 nblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
432 431
433 432 if (copyin(new_rblk, nblk, sizeof (rctl_opaque_t)) == -1) {
434 433 kmem_free(nblk, sizeof (rctl_opaque_t));
435 434 return (set_errno(EFAULT));
436 435 }
437 436
438 437 nval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
439 438
440 439 rctlsys_rblk_xfrm(nblk, NULL, nval, RBX_FROM_BLK | RBX_VAL);
441 440
442 441 if (rctl_invalid_value(rde, nval)) {
443 442 kmem_free(nblk, sizeof (rctl_opaque_t));
444 443 kmem_cache_free(rctl_val_cache, nval);
445 444 return (set_errno(EINVAL));
446 445 }
447 446
448 447 /* allocate what we might need before potentially grabbing p_lock */
449 448 oblk = kmem_alloc(sizeof (rctl_opaque_t), KM_SLEEP);
450 449 oval = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
451 450 rval1 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
452 451 rval2 = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
453 452
454 453 if (nval->rcv_privilege == RCPRIV_BASIC) {
455 454 if (flags & RCTL_USE_RECIPIENT_PID) {
456 455 pid = nval->rcv_action_recip_pid;
457 456
458 457 /* case for manipulating rctl values on other procs */
459 458 if (pid != curproc->p_pid) {
460 459 /* cannot be other pid on process rctls */
461 460 if (rde->rcd_entity == RCENTITY_PROCESS) {
462 461 ret = set_errno(EINVAL);
463 462 goto rctlsys_out;
464 463 }
465 464 /*
466 465 * must have privilege to manipulate controls
467 466 * on other processes
468 467 */
469 468 if (secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
470 469 ret = set_errno(EACCES);
471 470 goto rctlsys_out;
472 471 }
473 472
474 473 pid = nval->rcv_action_recip_pid;
475 474 mutex_enter(&pidlock);
476 475 pp = prfind(pid);
477 476 if (!pp) {
478 477 mutex_exit(&pidlock);
479 478 ret = set_errno(ESRCH);
480 479 goto rctlsys_out;
481 480 }
482 481
483 482 /*
484 483 * idle or zombie procs have either not yet
485 484 * set up their rctls or have already done
486 485 * their rctl_set_tearoff's.
487 486 */
488 487 if (pp->p_stat == SZOMB ||
489 488 pp->p_stat == SIDL) {
490 489 mutex_exit(&pidlock);
491 490 ret = set_errno(ESRCH);
492 491 goto rctlsys_out;
493 492 }
494 493
495 494 /*
496 495 * hold this pp's p_lock to ensure that
497 496 * it does not do it's rctl_set_tearoff
498 497 * If we did not do this, we could
499 498 * potentially add rctls to the entity
500 499 * with a recipient that is a process
501 500 * that has exited.
502 501 */
503 502 mutex_enter(&pp->p_lock);
504 503 mutex_exit(&pidlock);
505 504
506 505 /*
507 506 * We know that curproc's task, project,
508 507 * and zone pointers will not change
509 508 * because functions that change them
510 509 * call holdlwps(SHOLDFORK1) first.
511 510 */
512 511
513 512 /*
514 513 * verify that the found pp is in the
515 514 * current task. If it is, then it
516 515 * is also within the current project
517 516 * and zone.
518 517 */
519 518 if (rde->rcd_entity == RCENTITY_TASK &&
520 519 pp->p_task != curproc->p_task) {
521 520 ret = set_errno(ESRCH);
522 521 goto rctlsys_out;
523 522 }
524 523
525 524 ASSERT(pp->p_task->tk_proj ==
526 525 curproc->p_task->tk_proj);
527 526 ASSERT(pp->p_zone == curproc->p_zone);
528 527
529 528
530 529 nval->rcv_action_recipient = pp;
531 530 nval->rcv_action_recip_pid = pid;
532 531
533 532 } else {
534 533 /* for manipulating rctl values on this proc */
535 534 mutex_enter(&curproc->p_lock);
536 535 pp = curproc;
537 536 nval->rcv_action_recipient = curproc;
538 537 nval->rcv_action_recip_pid = curproc->p_pid;
539 538 }
540 539
541 540 } else {
542 541 /* RCTL_USE_RECIPIENT_PID not set, use this proc */
543 542 mutex_enter(&curproc->p_lock);
544 543 pp = curproc;
545 544 nval->rcv_action_recipient = curproc;
546 545 nval->rcv_action_recip_pid = curproc->p_pid;
547 546 }
548 547
549 548 } else {
550 549 /* privileged controls have no recipient pid */
551 550 mutex_enter(&curproc->p_lock);
552 551 pp = curproc;
553 552 nval->rcv_action_recipient = NULL;
554 553 nval->rcv_action_recip_pid = -1;
555 554 }
556 555
557 556 nval->rcv_firing_time = 0;
558 557
559 558 if (action == RCTL_REPLACE) {
560 559
561 560 if (copyin(old_rblk, oblk, sizeof (rctl_opaque_t)) == -1) {
562 561 ret = set_errno(EFAULT);
563 562 goto rctlsys_out;
564 563 }
565 564
566 565 rctlsys_rblk_xfrm(oblk, NULL, oval, RBX_FROM_BLK | RBX_VAL);
567 566
568 567 if (rctl_invalid_value(rde, oval)) {
569 568 ret = set_errno(EINVAL);
570 569 goto rctlsys_out;
571 570 }
572 571
573 572 if (oval->rcv_privilege == RCPRIV_BASIC) {
574 573 if (!(flags & RCTL_USE_RECIPIENT_PID)) {
575 574 oval->rcv_action_recipient = curproc;
576 575 oval->rcv_action_recip_pid = curproc->p_pid;
577 576 }
578 577 } else {
579 578 oval->rcv_action_recipient = NULL;
580 579 oval->rcv_action_recip_pid = -1;
581 580 }
582 581
583 582 /*
584 583 * Find the real value we're attempting to replace on the
585 584 * sequence, rather than trusting the one delivered from
586 585 * userland.
587 586 */
588 587 if (ret = rctl_local_get(hndl, NULL, rval1, pp)) {
589 588 (void) set_errno(ret);
590 589 goto rctlsys_out;
591 590 }
592 591
593 592 do {
594 593 if (rval1->rcv_privilege == RCPRIV_SYSTEM ||
595 594 rctl_val_cmp(oval, rval1, 0) == 0)
596 595 break;
597 596
598 597 tval = rval1;
599 598 rval1 = rval2;
600 599 rval2 = tval;
601 600 } while (rctl_local_get(hndl, rval2, rval1, pp) == 0);
602 601
603 602 if (rval1->rcv_privilege == RCPRIV_SYSTEM) {
604 603 if (rctl_val_cmp(oval, rval1, 1) == 0)
605 604 ret = set_errno(EPERM);
606 605 else
607 606 ret = set_errno(ESRCH);
608 607
609 608 goto rctlsys_out;
610 609 }
611 610
612 611 bcopy(rval1, oval, sizeof (rctl_val_t));
613 612
614 613 /*
615 614 * System controls are immutable.
616 615 */
617 616 if (nval->rcv_privilege == RCPRIV_SYSTEM) {
618 617 ret = set_errno(EPERM);
619 618 goto rctlsys_out;
620 619 }
621 620
622 621 /*
623 622 * Only privileged processes in the global zone can modify
624 623 * privileged rctls of type RCENTITY_ZONE; replacing privileged
625 624 * controls with basic ones are not allowed either. Lowering a
626 625 * lowerable one might be OK for privileged processes in a
627 626 * non-global zone, but lowerable rctls probably don't make
628 627 * sense for zones (hence, not modifiable from within a zone).
629 628 */
630 629 if (rde->rcd_entity == RCENTITY_ZONE &&
631 630 (nval->rcv_privilege == RCPRIV_PRIVILEGED ||
632 631 oval->rcv_privilege == RCPRIV_PRIVILEGED) &&
633 632 secpolicy_rctlsys(CRED(), B_TRUE) != 0) {
634 633 ret = set_errno(EACCES);
635 634 goto rctlsys_out;
636 635 }
637 636
638 637 /*
639 638 * Must be privileged to replace a privileged control with
640 639 * a basic one.
641 640 */
642 641 if (oval->rcv_privilege == RCPRIV_PRIVILEGED &&
643 642 nval->rcv_privilege != RCPRIV_PRIVILEGED &&
644 643 secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
645 644 ret = set_errno(EACCES);
646 645 goto rctlsys_out;
647 646 }
648 647
649 648 /*
650 649 * Must have lowerable global property for non-privileged
651 650 * to lower the value of a privileged control; otherwise must
652 651 * have sufficient privileges to modify privileged controls
653 652 * at all.
654 653 */
655 654 if (oval->rcv_privilege == RCPRIV_PRIVILEGED &&
656 655 nval->rcv_privilege == RCPRIV_PRIVILEGED &&
657 656 ((((rde->rcd_flagaction & RCTL_GLOBAL_LOWERABLE) == 0) ||
658 657 oval->rcv_flagaction != nval->rcv_flagaction ||
659 658 oval->rcv_action_signal != nval->rcv_action_signal ||
660 659 oval->rcv_value < nval->rcv_value)) &&
661 660 secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
662 661 ret = set_errno(EACCES);
663 662 goto rctlsys_out;
664 663 }
665 664
666 665 if (ret = rctl_local_replace(hndl, oval, nval, pp)) {
667 666 (void) set_errno(ret);
668 667 goto rctlsys_out;
669 668 }
670 669
671 670 /* ensure that nval is not freed */
672 671 nval = NULL;
673 672
674 673 } else if (action == RCTL_INSERT) {
675 674 /*
676 675 * System controls are immutable.
677 676 */
678 677 if (nval->rcv_privilege == RCPRIV_SYSTEM) {
679 678 ret = set_errno(EPERM);
680 679 goto rctlsys_out;
681 680 }
682 681
683 682 /*
684 683 * Only privileged processes in the global zone may add
685 684 * privileged zone.* rctls. Only privileged processes
686 685 * may add other privileged rctls.
687 686 */
688 687 if (nval->rcv_privilege == RCPRIV_PRIVILEGED) {
689 688 if ((rde->rcd_entity == RCENTITY_ZONE &&
690 689 secpolicy_rctlsys(CRED(), B_TRUE) != 0) ||
691 690 (rde->rcd_entity != RCENTITY_ZONE &&
692 691 secpolicy_rctlsys(CRED(), B_FALSE) != 0)) {
693 692 ret = set_errno(EACCES);
694 693 goto rctlsys_out;
695 694 }
696 695 }
697 696
698 697 /*
699 698 * Only one basic control is allowed per rctl.
700 699 * If a basic control is being inserted, delete
701 700 * any other basic control.
702 701 */
703 702 if ((nval->rcv_privilege == RCPRIV_BASIC) &&
704 703 (rctl_local_get(hndl, NULL, rval1, pp) == 0)) {
705 704 do {
706 705 if (rval1->rcv_privilege == RCPRIV_BASIC &&
707 706 rval1->rcv_action_recipient == curproc) {
708 707 (void) rctl_local_delete(hndl, rval1,
709 708 pp);
710 709 if (rctl_local_get(hndl, NULL, rval1,
711 710 pp) != 0)
712 711 break;
713 712 }
714 713
715 714 tval = rval1;
716 715 rval1 = rval2;
717 716 rval2 = tval;
718 717 } while (rctl_local_get(hndl, rval2, rval1, pp)
719 718 == 0);
720 719 }
721 720
722 721
723 722 if (ret = rctl_local_insert(hndl, nval, pp)) {
724 723 (void) set_errno(ret);
725 724 goto rctlsys_out;
726 725 }
727 726
728 727 /* ensure that nval is not freed */
729 728 nval = NULL;
730 729
731 730 } else {
732 731 /*
733 732 * RCTL_DELETE
734 733 */
735 734 if (nval->rcv_privilege == RCPRIV_SYSTEM) {
736 735 ret = set_errno(EPERM);
737 736 goto rctlsys_out;
738 737 }
739 738
740 739 if (nval->rcv_privilege == RCPRIV_PRIVILEGED) {
741 740 if ((rde->rcd_entity == RCENTITY_ZONE &&
742 741 secpolicy_rctlsys(CRED(), B_TRUE) != 0) ||
743 742 (rde->rcd_entity != RCENTITY_ZONE &&
744 743 secpolicy_rctlsys(CRED(), B_FALSE) != 0)) {
745 744 ret = set_errno(EACCES);
746 745 goto rctlsys_out;
747 746 }
748 747 }
749 748
750 749 if (ret = rctl_local_delete(hndl, nval, pp)) {
751 750 (void) set_errno(ret);
752 751 goto rctlsys_out;
753 752 }
754 753 }
755 754
756 755 rctlsys_out:
757 756
758 757 if (pp)
759 758 mutex_exit(&pp->p_lock);
760 759
761 760 kmem_free(nblk, sizeof (rctl_opaque_t));
762 761 kmem_free(oblk, sizeof (rctl_opaque_t));
763 762
764 763 /* only free nval if we did not rctl_local_insert it */
765 764 if (nval)
766 765 kmem_cache_free(rctl_val_cache, nval);
767 766
768 767 kmem_cache_free(rctl_val_cache, oval);
769 768 kmem_cache_free(rctl_val_cache, rval1);
770 769 kmem_cache_free(rctl_val_cache, rval2);
771 770
772 771 return (ret);
773 772 }
774 773
775 774 static long
776 775 rctlsys_lst(char *ubuf, size_t ubufsz)
777 776 {
778 777 char *kbuf;
779 778 size_t kbufsz;
780 779
781 780 kbufsz = rctl_build_name_buf(&kbuf);
782 781
783 782 if (kbufsz <= ubufsz &&
784 783 copyout(kbuf, ubuf, kbufsz) != 0) {
785 784 kmem_free(kbuf, kbufsz);
786 785 return (set_errno(EFAULT));
787 786 }
788 787
789 788 kmem_free(kbuf, kbufsz);
790 789
791 790 return (kbufsz);
792 791 }
793 792
794 793 static long
795 794 rctlsys_ctl(char *name, rctl_opaque_t *rblk, int flags)
796 795 {
797 796 rctl_dict_entry_t *krde;
798 797 rctl_opaque_t *krblk;
799 798 char *kname;
800 799 size_t klen;
801 800
802 801 kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
803 802
804 803 if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
805 804 kmem_free(kname, MAXPATHLEN);
806 805 return (set_errno(EFAULT));
807 806 }
808 807
809 808 switch (flags) {
810 809 case RCTLCTL_GET:
811 810 krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
812 811 krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP);
813 812
814 813 if (rctl_global_get(kname, krde) == -1) {
815 814 kmem_free(krde, sizeof (rctl_dict_entry_t));
816 815 kmem_free(krblk, sizeof (rctl_opaque_t));
817 816 kmem_free(kname, MAXPATHLEN);
818 817 return (set_errno(ESRCH));
819 818 }
820 819
821 820 rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_TO_BLK | RBX_CTL);
822 821
823 822 if (copyout(krblk, rblk, sizeof (rctl_opaque_t)) != 0) {
824 823 kmem_free(krde, sizeof (rctl_dict_entry_t));
825 824 kmem_free(krblk, sizeof (rctl_opaque_t));
826 825 kmem_free(kname, MAXPATHLEN);
827 826 return (set_errno(EFAULT));
828 827 }
829 828
830 829 kmem_free(krde, sizeof (rctl_dict_entry_t));
831 830 kmem_free(krblk, sizeof (rctl_opaque_t));
832 831 kmem_free(kname, MAXPATHLEN);
833 832 break;
834 833 case RCTLCTL_SET:
835 834 if (secpolicy_rctlsys(CRED(), B_TRUE) != 0) {
836 835 kmem_free(kname, MAXPATHLEN);
837 836 return (set_errno(EPERM));
838 837 }
839 838
840 839 krde = kmem_alloc(sizeof (rctl_dict_entry_t), KM_SLEEP);
841 840 krblk = kmem_zalloc(sizeof (rctl_opaque_t), KM_SLEEP);
842 841
843 842 if (rctl_global_get(kname, krde) == -1) {
844 843 kmem_free(krde, sizeof (rctl_dict_entry_t));
845 844 kmem_free(krblk, sizeof (rctl_opaque_t));
846 845 kmem_free(kname, MAXPATHLEN);
847 846 return (set_errno(ESRCH));
848 847 }
849 848
850 849 if (copyin(rblk, krblk, sizeof (rctl_opaque_t)) != 0) {
851 850 kmem_free(krde, sizeof (rctl_dict_entry_t));
852 851 kmem_free(krblk, sizeof (rctl_opaque_t));
853 852 kmem_free(kname, MAXPATHLEN);
854 853 return (set_errno(EFAULT));
855 854 }
856 855
857 856 rctlsys_rblk_xfrm(krblk, krde, NULL, RBX_FROM_BLK | RBX_CTL);
858 857
859 858 if (rctl_global_set(kname, krde) == -1) {
860 859 kmem_free(krde, sizeof (rctl_dict_entry_t));
861 860 kmem_free(krblk, sizeof (rctl_opaque_t));
862 861 kmem_free(kname, MAXPATHLEN);
863 862 return (set_errno(ESRCH));
864 863 }
865 864
866 865 kmem_free(krde, sizeof (rctl_dict_entry_t));
867 866 kmem_free(krblk, sizeof (rctl_opaque_t));
868 867 kmem_free(kname, MAXPATHLEN);
869 868
870 869 break;
871 870 default:
872 871 kmem_free(kname, MAXPATHLEN);
873 872 return (set_errno(EINVAL));
874 873 }
875 874
876 875 return (0);
877 876 }
878 877
879 878 /*
880 879 * The arbitrary maximum number of rctl_opaque_t that we can pass to
881 880 * rctl_projset().
882 881 */
883 882 #define RCTL_PROJSET_MAXSIZE 1024
884 883
885 884 static long
886 885 rctlsys_projset(char *name, rctl_opaque_t *rblk, size_t size, int flags)
887 886 {
888 887 rctl_dict_entry_t *krde;
889 888 rctl_opaque_t *krblk;
890 889 char *kname;
891 890 size_t klen;
892 891 rctl_hndl_t hndl;
893 892 rctl_val_t *new_values = NULL;
894 893 rctl_val_t *alloc_values = NULL;
895 894 rctl_val_t *new_val;
896 895 rctl_val_t *alloc_val;
897 896 int error = 0;
898 897 int count;
899 898
900 899 kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
901 900
902 901 if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
903 902 kmem_free(kname, MAXPATHLEN);
904 903 return (set_errno(EFAULT));
905 904 }
906 905
907 906 if (size > RCTL_PROJSET_MAXSIZE) {
908 907 kmem_free(kname, MAXPATHLEN);
909 908 return (set_errno(EINVAL));
910 909 }
911 910
912 911 if ((hndl = rctl_hndl_lookup(kname)) == -1) {
913 912 kmem_free(kname, MAXPATHLEN);
914 913 return (set_errno(EINVAL));
915 914 }
916 915
917 916 krde = rctl_dict_lookup_hndl(hndl);
918 917
919 918 /* If not a project entity then exit */
920 919 if ((krde->rcd_entity != RCENTITY_PROJECT) || (size <= 0)) {
921 920 kmem_free(kname, MAXPATHLEN);
922 921 return (set_errno(EINVAL));
923 922 }
924 923
925 924 if (secpolicy_rctlsys(CRED(), B_FALSE) != 0) {
926 925 kmem_free(kname, MAXPATHLEN);
927 926 return (set_errno(EPERM));
928 927 }
929 928
930 929 /* Allocate an array large enough for all resource control blocks */
931 930 krblk = kmem_zalloc(sizeof (rctl_opaque_t) * size, KM_SLEEP);
932 931
933 932 if (copyin(rblk, krblk, sizeof (rctl_opaque_t) * size) == 0) {
934 933
935 934 for (count = 0; (count < size) && (error == 0); count++) {
936 935 new_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
937 936 alloc_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
938 937
939 938 rctlsys_rblk_xfrm(&krblk[count], NULL, new_val,
940 939 RBX_FROM_BLK | RBX_VAL);
941 940
942 941 /*
943 942 * Project entity resource control values should always
944 943 * be privileged
945 944 */
946 945 if (new_val->rcv_privilege != RCPRIV_PRIVILEGED) {
947 946 kmem_cache_free(rctl_val_cache, new_val);
948 947 kmem_cache_free(rctl_val_cache, alloc_val);
949 948
950 949 error = EPERM;
951 950 } else if (rctl_invalid_value(krde, new_val) == 0) {
952 951
953 952 /*
954 953 * This is a project entity; we do not set
955 954 * rcv_action_recipient or rcv_action_recip_pid
956 955 */
957 956 new_val->rcv_action_recipient = NULL;
958 957 new_val->rcv_action_recip_pid = -1;
959 958 new_val->rcv_flagaction |= RCTL_LOCAL_PROJDB;
960 959 new_val->rcv_firing_time = 0;
961 960
962 961 new_val->rcv_prev = NULL;
963 962 new_val->rcv_next = new_values;
964 963 new_values = new_val;
965 964
966 965 /*
967 966 * alloc_val is left largely uninitialized, it
968 967 * is a pre-allocated rctl_val_t which is used
969 968 * later in rctl_local_replace_all() /
970 969 * rctl_local_insert_all().
971 970 */
972 971 alloc_val->rcv_prev = NULL;
973 972 alloc_val->rcv_next = alloc_values;
974 973 alloc_values = alloc_val;
975 974 } else {
976 975 kmem_cache_free(rctl_val_cache, new_val);
977 976 kmem_cache_free(rctl_val_cache, alloc_val);
978 977
979 978 error = EINVAL;
980 979 }
981 980 }
982 981
983 982 } else {
984 983 error = EFAULT;
985 984 }
986 985
987 986 kmem_free(krblk, sizeof (rctl_opaque_t) * size);
988 987 kmem_free(kname, MAXPATHLEN);
989 988
990 989 if (error) {
991 990 /*
992 991 * We will have the same number of items in the alloc_values
993 992 * linked list, as we have in new_values. However, we remain
994 993 * cautious, and teardown the linked lists individually.
995 994 */
996 995 while (new_values != NULL) {
997 996 new_val = new_values;
998 997 new_values = new_values->rcv_next;
999 998 kmem_cache_free(rctl_val_cache, new_val);
1000 999 }
1001 1000
1002 1001 while (alloc_values != NULL) {
1003 1002 alloc_val = alloc_values;
1004 1003 alloc_values = alloc_values->rcv_next;
1005 1004 kmem_cache_free(rctl_val_cache, alloc_val);
1006 1005 }
1007 1006
1008 1007 return (set_errno(error));
1009 1008 }
1010 1009
1011 1010 /*
1012 1011 * We take the p_lock here to maintain consistency with other functions
1013 1012 * - rctlsys_get() and rctlsys_set()
1014 1013 */
1015 1014 mutex_enter(&curproc->p_lock);
1016 1015 if (flags & TASK_PROJ_PURGE) {
1017 1016 (void) rctl_local_replace_all(hndl, new_values, alloc_values,
1018 1017 curproc);
1019 1018 } else {
1020 1019 (void) rctl_local_insert_all(hndl, new_values, alloc_values,
1021 1020 curproc);
1022 1021 }
1023 1022 mutex_exit(&curproc->p_lock);
1024 1023
1025 1024 return (0);
1026 1025 }
1027 1026
1028 1027 long
1029 1028 rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags)
1030 1029 {
1031 1030 switch (code) {
1032 1031 case 0:
1033 1032 return (rctlsys_get(name, obuf, nbuf, flags));
1034 1033
1035 1034 case 1:
1036 1035 return (rctlsys_set(name, obuf, nbuf, flags));
1037 1036
1038 1037 case 2:
1039 1038 /*
1040 1039 * Private call for rctl_walk(3C).
1041 1040 */
1042 1041 return (rctlsys_lst(obuf, obufsz));
1043 1042
1044 1043 case 3:
1045 1044 /*
1046 1045 * Private code for rctladm(1M): "rctlctl".
1047 1046 */
1048 1047 return (rctlsys_ctl(name, obuf, flags));
1049 1048 case 4:
1050 1049 /*
1051 1050 * Private code for setproject(3PROJECT).
1052 1051 */
1053 1052 return (rctlsys_projset(name, nbuf, obufsz, flags));
1054 1053
1055 1054 default:
1056 1055 return (set_errno(EINVAL));
1057 1056 }
1058 1057 }
↓ open down ↓ |
751 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX