Print this page
10105 libproject needs smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libproject/common/setproject.c
+++ new/usr/src/lib/libproject/common/setproject.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 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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 (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright (c) 2012, Joyent, Inc. All rights reserved.
23 + * Copyright (c) 2018, Joyent, Inc.
24 24 */
25 25
26 26
27 27 #include <sys/task.h>
28 28 #include <sys/types.h>
29 29 #include <unistd.h>
30 30
31 31 #include <ctype.h>
32 32 #include <project.h>
33 33 #include <rctl.h>
34 34 #include <secdb.h>
35 35 #include <signal.h>
36 36 #include <stdlib.h>
37 37 #include <string.h>
38 38 #include <strings.h>
39 39 #include <nss_dbdefs.h>
40 40 #include <pwd.h>
41 41 #include <pool.h>
42 42 #include <libproc.h>
43 43 #include <priv.h>
44 44 #include <priv_utils.h>
45 45 #include <zone.h>
46 46 #include <sys/pool.h>
47 47 #include <sys/pool_impl.h>
48 48 #include <sys/rctl_impl.h>
49 49
50 50 static void
51 51 xstrtolower(char *s)
52 52 {
53 53 for (; *s != '\0'; s++)
54 54 *s = tolower(*s);
55 55 }
56 56
57 57 static void
58 58 remove_spaces(char *s)
59 59 {
60 60 char *current;
61 61 char *next;
62 62
63 63 current = next = s;
64 64
65 65 while (*next != '\0') {
66 66 while (isspace(*next))
67 67 next++;
68 68 *current++ = *next++;
69 69 }
70 70 *current = '\0';
71 71 }
72 72
73 73 int
74 74 build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
75 75 {
76 76 char *signam;
77 77 int sig = 0;
78 78 uint_t act = rctlblk_get_local_action(blk, &sig);
79 79
80 80 if (comp_num == 0) {
81 81 /*
82 82 * Setting privilege level for resource control block.
83 83 */
84 84 xstrtolower(component);
85 85
86 86 if (strcmp("basic", component) == 0) {
87 87 rctlblk_set_privilege(blk, RCPRIV_BASIC);
88 88 return (0);
89 89 }
90 90
91 91 if (strcmp("priv", component) == 0 ||
92 92 strcmp("privileged", component) == 0) {
93 93 rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
94 94 return (0);
95 95 }
96 96
97 97 return (-1);
98 98 }
99 99
100 100 if (comp_num == 1) {
101 101
102 102 /*
103 103 * Setting value for resource control block.
104 104 */
105 105 unsigned long long val;
106 106 char *t;
107 107
108 108 /* Negative numbers are not allowed */
109 109 if (strchr(component, '-') != NULL)
110 110 return (-1);
111 111
112 112 errno = 0;
113 113 val = strtoull(component, &t, 10);
114 114 if (errno != 0 || t == component || *t != '\0')
115 115 return (-1);
116 116
117 117 rctlblk_set_value(blk, (rctl_qty_t)val);
118 118 return (0);
119 119 }
120 120
121 121 /*
122 122 * Setting one or more actions on this resource control block.
123 123 */
124 124 if (comp_num >= 2) {
125 125 if (strcmp("none", component) == 0) {
126 126 rctlblk_set_local_action(blk, 0, 0);
127 127 return (0);
128 128 }
129 129
130 130 if (strcmp("deny", component) == 0) {
131 131 act |= RCTL_LOCAL_DENY;
132 132
133 133 rctlblk_set_local_action(blk, act, sig);
134 134
135 135 return (0);
136 136 }
137 137
138 138 /*
139 139 * The last, and trickiest, form of action is the signal
140 140 * specification.
141 141 */
142 142 if ((signam = strchr(component, '=')) == NULL)
143 143 return (-1);
144 144
145 145 *signam++ = '\0';
146 146
147 147 if (strcmp("sig", component) == 0 ||
148 148 strcmp("signal", component) == 0) {
149 149 if (strncmp("SIG", signam, 3) == 0)
150 150 signam += 3;
151 151
152 152 if (str2sig(signam, &sig) == -1)
153 153 return (-1);
154 154
155 155 act |= RCTL_LOCAL_SIGNAL;
156 156
157 157 rctlblk_set_local_action(blk, act, sig);
158 158
159 159 return (0);
160 160 }
161 161 }
162 162 return (-1);
163 163 }
164 164
165 165 /*
166 166 * States:
167 167 */
168 168 #define INPAREN 0x1
169 169
170 170 /*
171 171 * Errors:
172 172 */
173 173 #define SETFAILED (-1)
174 174 #define COMPLETE 1
175 175 #define NESTING 2
176 176 #define UNCLOSED 3
177 177 #define CLOSEBEFOREOPEN 4
178 178 #define BADSPEC 5
179 179
180 180 static void
181 181 reinit_blk(rctlblk_t *blk, int local_action)
182 182 {
183 183 rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
184 184 rctlblk_set_value(blk, 0);
185 185 rctlblk_set_local_flags(blk, 0);
186 186 rctlblk_set_local_action(blk, local_action, 0);
187 187 }
188 188
189 189 static int
190 190 rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
191 191 {
192 192 int error = 0;
193 193 uint_t component = 0;
194 194 int valuecount = 0;
195 195 uint_t state = 0;
196 196 char *component_head;
197 197 rctlblk_t *blk;
198 198 rctlblk_t *ablk;
199 199 int project_entity = 0;
200 200 int count = 0;
201 201 char *tmp;
202 202 int local_act;
203 203 rctlblk_t *rnext;
204 204 int teardown_basic = 0;
205 205 int teardown_priv = 0;
206 206
207 207 /* We cannot modify a zone resource control */
208 208 if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
209 209 return (SETFAILED);
210 210 }
211 211
212 212 remove_spaces(val);
213 213
214 214 if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
215 215 project_entity = 1;
216 216 } else if ((strncmp(ctl_name, "process.", strlen("process.")) != 0) &&
217 217 (strncmp(ctl_name, "task.", strlen("task.")) != 0)) {
218 218 return (SETFAILED);
219 219 }
220 220
221 221 /* Determine how many attributes we'll be setting */
222 222 for (tmp = val; *tmp != '\0'; tmp++) {
223 223 if (*tmp == '(')
224 224 count++;
225 225 }
226 226 /* Allocate sufficient memory for rctl blocks */
227 227 if ((count == 0) || ((ablk =
228 228 (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
229 229 return (SETFAILED);
230 230 }
231 231 blk = ablk;
232 232
233 233 /*
234 234 * In order to set the new rctl's local_action, we'll need the
235 235 * current value of global_flags. We obtain global_flags by
236 236 * performing a pr_getrctl().
237 237 *
238 238 * The ctl_name has been verified as valid, so we have no reason
239 239 * to suspect that pr_getrctl() will return an error.
240 240 */
241 241 (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
242 242
243 243
244 244 /*
245 245 * Set initial local action based on global deny properties.
246 246 */
247 247 rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
248 248 rctlblk_set_value(blk, 0);
249 249 rctlblk_set_local_flags(blk, 0);
250 250
251 251 if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
252 252 local_act = RCTL_LOCAL_DENY;
253 253 else
254 254 local_act = RCTL_LOCAL_NOACTION;
255 255
256 256 rctlblk_set_local_action(blk, local_act, 0);
257 257
258 258 for (; ; val++) {
259 259
260 260 switch (*val) {
261 261 case '(':
262 262 if (state & INPAREN) {
263 263 error = NESTING;
264 264 break;
265 265 }
266 266
267 267 state |= INPAREN;
268 268 component_head = (char *)val + 1;
269 269
270 270 break;
271 271 case ')':
272 272 if (state & INPAREN) {
273 273 *val = '\0';
274 274 if (component < 2) {
275 275 error = BADSPEC;
276 276 break;
277 277 }
278 278 if (build_rctlblk(blk, component,
279 279 component_head) == -1) {
280 280 error = BADSPEC;
281 281 break;
282 282 }
283 283 state &= ~INPAREN;
284 284 component = 0;
285 285 valuecount++;
286 286
287 287 if (project_entity &&
288 288 (rctlblk_get_privilege(blk) ==
289 289 RCPRIV_BASIC)) {
290 290 error = SETFAILED;
291 291 } else {
292 292 if (rctlblk_get_privilege(blk)
293 293 == RCPRIV_BASIC)
294 294 teardown_basic = 1;
295 295
296 296 if (rctlblk_get_privilege(blk)
297 297 == RCPRIV_PRIVILEGED)
298 298 teardown_priv = 1;
299 299
300 300 if (valuecount > count) {
301 301 free(ablk);
302 302 return (SETFAILED);
303 303 }
304 304
305 305 if (valuecount != count) {
306 306 blk = RCTLBLK_INC(ablk,
307 307 valuecount);
308 308 /* re-initialize blk */
309 309 reinit_blk(blk,
310 310 local_act);
311 311 }
312 312 }
313 313
314 314 } else {
315 315 error = CLOSEBEFOREOPEN;
316 316 }
317 317 break;
318 318 case ',':
319 319 if (state & INPAREN) {
320 320 *val = '\0';
321 321 if (build_rctlblk(blk, component,
322 322 component_head) == -1)
323 323 error = BADSPEC;
324 324
325 325 component++;
326 326 component_head = (char *)val + 1;
327 327
328 328 }
329 329 break;
330 330 case '\0':
331 331 if (valuecount == 0)
332 332 error = BADSPEC;
333 333 else if (state & INPAREN)
334 334 error = UNCLOSED;
335 335 else
336 336 error = COMPLETE;
337 337 break;
338 338 default:
339 339 if (!(state & INPAREN))
340 340 error = BADSPEC;
341 341 break;
342 342 }
343 343
344 344 if (error)
345 345 break;
346 346 }
347 347 /* ablk points to array of rctlblk_t */
348 348
349 349 if (valuecount == 0)
350 350 error = BADSPEC;
351 351
352 352 if (error != COMPLETE) {
353 353 free(ablk);
354 354 return (error);
355 355 }
356 356
357 357 /* teardown rctls if required */
358 358 if (!project_entity) {
359 359
360 360 if ((rnext = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
361 361 free(ablk);
362 362 return (SETFAILED);
363 363 }
364 364
365 365 restart:
366 366 if (pr_getrctl(Pr, ctl_name, NULL, rnext, RCTL_FIRST) == 0) {
367 367 while (1) {
368 368 if ((rctlblk_get_privilege(rnext) ==
369 369 RCPRIV_PRIVILEGED) &&
370 370 (teardown_priv == 1)) {
371 371 (void) pr_setrctl(Pr, ctl_name, NULL,
372 372 rnext, RCTL_DELETE);
373 373 goto restart;
374 374 }
375 375 if ((rctlblk_get_privilege(rnext) ==
376 376 RCPRIV_BASIC) && (teardown_basic == 1)) {
377 377 (void) pr_setrctl(Pr, ctl_name, NULL,
378 378 rnext, RCTL_DELETE);
379 379 goto restart;
380 380 }
381 381
382 382 if (pr_getrctl(Pr, ctl_name, rnext, rnext,
383 383 RCTL_NEXT) == -1)
384 384 break;
385 385 }
386 386 }
387 387
388 388 free(rnext);
389 389 }
390 390
391 391 /* set rctls */
392 392
393 393 blk = ablk;
394 394
395 395 if (project_entity) {
396 396 if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
397 397 error = SETFAILED;
398 398 } else {
399 399 valuecount = 0;
400 400 while (valuecount < count) {
401 401 if (pr_setrctl(Pr, ctl_name,
402 402 NULL, blk, RCTL_INSERT) == -1) {
403 403 error = SETFAILED;
404 404 break;
405 405 }
406 406 valuecount++;
407 407 blk = RCTLBLK_INC(ablk, valuecount);
408 408 }
409 409 }
410 410
411 411
412 412
413 413 free(ablk);
414 414
415 415 if (error != COMPLETE)
416 416 return (error);
417 417
418 418 return (0);
419 419 }
420 420
421 421 static int
422 422 rctlwalkfunc(const char *name, void *data)
423 423 {
424 424
425 425 if (strcmp(name, (char *)data) == 0)
426 426 return (-1);
427 427 else
428 428 return (0);
429 429
430 430 }
431 431
432 432 /*
433 433 * This routine determines if /dev/pool device is present on the system and
434 434 * pools are currently enabled. We want to do this directly from libproject
435 435 * without using libpool's pool_get_status() routine because pools could be
436 436 * completely removed from the system. Return 1 if pools are enabled, or
437 437 * 0 otherwise. When used inside local zones, always pretend that pools
438 438 * are disabled because binding is not allowed and we're already in the
439 439 * right pool.
440 440 */
441 441 static int
442 442 pools_enabled(void)
443 443 {
444 444 pool_status_t status;
445 445 int fd;
446 446
447 447 if (getzoneid() != GLOBAL_ZONEID)
448 448 return (0);
449 449 if ((fd = open("/dev/pool", O_RDONLY)) < 0)
450 450 return (0);
451 451 if (ioctl(fd, POOL_STATUSQ, &status) < 0) {
452 452 (void) close(fd);
453 453 return (0);
454 454 }
455 455 (void) close(fd);
456 456 return (status.ps_io_state);
457 457 }
458 458
459 459 /*
460 460 * A pool_name of NULL means to attempt to bind to the default pool.
461 461 * If the "force" flag is non-zero, the value of "system.bind-default" will be
462 462 * ignored, and the process will be bound to the default pool if one exists.
463 463 */
464 464 static int
465 465 bind_to_pool(const char *pool_name, pid_t pid, int force)
466 466 {
467 467 pool_value_t *pvals[] = { NULL, NULL };
468 468 pool_t **pools;
469 469 uint_t nelem;
470 470 uchar_t bval;
471 471 pool_conf_t *conf;
472 472 const char *nm;
473 473 int retval;
474 474
475 475 if ((conf = pool_conf_alloc()) == NULL)
476 476 return (-1);
477 477 if (pool_conf_open(conf, pool_dynamic_location(), PO_RDONLY) < 0) {
478 478 /*
479 479 * Pools configuration file is corrupted; allow logins.
480 480 */
481 481 pool_conf_free(conf);
482 482 return (0);
483 483 }
484 484 if (pool_name != NULL && pool_get_pool(conf, pool_name) != NULL) {
485 485 /*
486 486 * There was a project.pool entry, and the pool it refers to
487 487 * is a valid (active) pool.
488 488 */
489 489 (void) pool_conf_close(conf);
490 490 pool_conf_free(conf);
491 491 if (pool_set_binding(pool_name, P_PID, pid) != PO_SUCCESS) {
492 492 if (pool_error() != POE_SYSTEM)
493 493 errno = EINVAL;
↓ open down ↓ |
460 lines elided |
↑ open up ↑ |
494 494 return (-1);
495 495 }
496 496 return (0);
497 497 }
498 498
499 499 /*
500 500 * Bind to the pool with 'pool.default' = 'true' if
501 501 * 'system.bind-default' = 'true'.
502 502 */
503 503 if ((pvals[0] = pool_value_alloc()) == NULL) {
504 - pool_conf_close(conf);
504 + (void) pool_conf_close(conf);
505 505 pool_conf_free(conf);
506 506 return (-1);
507 507 }
508 508 if (!force && pool_get_property(conf, pool_conf_to_elem(conf),
509 509 "system.bind-default", pvals[0]) != POC_BOOL ||
510 510 pool_value_get_bool(pvals[0], &bval) != PO_SUCCESS ||
511 511 bval == PO_FALSE) {
512 512 pool_value_free(pvals[0]);
513 - pool_conf_close(conf);
513 + (void) pool_conf_close(conf);
514 514 pool_conf_free(conf);
515 515 errno = pool_name == NULL ? EACCES : ESRCH;
516 516 return (-1);
517 517 }
518 518 (void) pool_value_set_name(pvals[0], "pool.default");
519 519 pool_value_set_bool(pvals[0], PO_TRUE);
520 520 if ((pools = pool_query_pools(conf, &nelem, pvals)) == NULL) {
521 521 /*
522 522 * No default pools exist.
523 523 */
524 524 pool_value_free(pvals[0]);
525 - pool_conf_close(conf);
525 + (void) pool_conf_close(conf);
526 526 pool_conf_free(conf);
527 527 errno = pool_name == NULL ? EACCES : ESRCH;
528 528 return (-1);
529 529 }
530 530 if (nelem != 1 ||
531 531 pool_get_property(conf, pool_to_elem(conf, pools[0]), "pool.name",
532 532 pvals[0]) != POC_STRING) {
533 533 /*
534 534 * Configuration is invalid.
535 535 */
536 536 free(pools);
537 537 pool_value_free(pvals[0]);
538 538 (void) pool_conf_close(conf);
539 539 pool_conf_free(conf);
540 540 return (0);
541 541 }
542 542 free(pools);
543 543 (void) pool_conf_close(conf);
544 544 pool_conf_free(conf);
545 545 (void) pool_value_get_string(pvals[0], &nm);
546 546 if (pool_set_binding(nm, P_PID, pid) != PO_SUCCESS) {
547 547 if (pool_error() != POE_SYSTEM)
548 548 errno = EINVAL;
549 549 retval = -1;
550 550 } else {
551 551 retval = 0;
552 552 }
553 553 pool_value_free(pvals[0]);
554 554 return (retval);
555 555 }
556 556
557 557 /*
558 558 * Changes the assigned project, task and resource pool of a stopped target
559 559 * process.
560 560 *
561 561 * We may not have access to the project table if our target process is in
562 562 * getprojbyname()'s execution path. Similarly, we may not be able to get user
563 563 * information if the target process is in getpwnam()'s execution path. Thus we
564 564 * give the caller the option of skipping these checks by providing a pointer to
565 565 * a pre-validated project structure in proj (whose name matches project_name)
566 566 * and taking responsibility for ensuring that the target process' owner is a
567 567 * member of the target project.
568 568 *
569 569 * Callers of this function should always provide a pre-validated project
570 570 * structure in proj unless they can be sure that the target process will never
571 571 * be in setproject_proc()'s execution path.
572 572 */
573 573
574 574 projid_t
575 575 setproject_proc(const char *project_name, const char *user_name, int flags,
576 576 pid_t pid, struct ps_prochandle *Pr, struct project *proj)
577 577 {
578 578 char pwdbuf[NSS_BUFLEN_PASSWD];
579 579 char prbuf[PROJECT_BUFSZ];
580 580 projid_t projid;
581 581 struct passwd pwd;
582 582 int i;
583 583 int unknown = 0;
584 584 int ret = 0;
585 585 kva_t *kv_array;
586 586 struct project local_proj; /* space to store proj if not provided */
587 587 const char *pool_name = NULL;
588 588
589 589 if (project_name != NULL) {
590 590 /*
591 591 * Sanity checks.
592 592 */
593 593 if (strcmp(project_name, "") == 0 ||
594 594 user_name == NULL) {
595 595 errno = EINVAL;
596 596 return (SETPROJ_ERR_TASK);
597 597 }
598 598
599 599 /*
600 600 * If proj is NULL, acquire project information to ensure that
601 601 * project_name is a valid project, and confirm that user_name
602 602 * exists and is a member of the specified project.
603 603 */
604 604 if (proj == NULL) {
605 605 if ((proj = getprojbyname(project_name, &local_proj,
606 606 prbuf, PROJECT_BUFSZ)) == NULL) {
607 607 errno = ESRCH;
608 608 return (SETPROJ_ERR_TASK);
609 609 }
610 610
611 611 if (getpwnam_r(user_name, &pwd,
612 612 pwdbuf, NSS_BUFLEN_PASSWD) == NULL) {
613 613 errno = ESRCH;
614 614 return (SETPROJ_ERR_TASK);
615 615 }
616 616 /*
617 617 * Root can join any project.
618 618 */
619 619 if (pwd.pw_uid != (uid_t)0 &&
620 620 !inproj(user_name, project_name, prbuf,
621 621 PROJECT_BUFSZ)) {
622 622 errno = ESRCH;
623 623 return (SETPROJ_ERR_TASK);
624 624 }
625 625 }
626 626 projid = proj->pj_projid;
627 627 } else {
628 628 projid = getprojid();
629 629 }
630 630
631 631
632 632 if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
633 633 KV_DELIMITER)) != NULL) {
634 634 for (i = 0; i < kv_array->length; i++) {
635 635 if (strcmp(kv_array->data[i].key,
636 636 "project.pool") == 0) {
637 637 pool_name = kv_array->data[i].value;
638 638 }
639 639 if (strcmp(kv_array->data[i].key, "task.final") == 0) {
640 640 flags |= TASK_FINAL;
641 641 }
642 642 }
643 643 }
644 644
645 645 /*
646 646 * Bind process to a pool only if pools are configured
647 647 */
648 648 if (pools_enabled() == 1) {
649 649 char *old_pool_name;
650 650 /*
651 651 * Attempt to bind to pool before calling
652 652 * settaskid().
653 653 */
654 654 old_pool_name = pool_get_binding(pid);
655 655 if (bind_to_pool(pool_name, pid, 0) != 0) {
656 656 if (old_pool_name)
657 657 free(old_pool_name);
658 658 _kva_free(kv_array);
659 659 return (SETPROJ_ERR_POOL);
660 660 }
661 661 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
662 662 int saved_errno = errno;
663 663
664 664 /*
665 665 * Undo pool binding.
666 666 */
667 667 (void) bind_to_pool(old_pool_name, pid, 1);
668 668 if (old_pool_name)
669 669 free(old_pool_name);
670 670 _kva_free(kv_array);
671 671 /*
672 672 * Restore errno
673 673 */
674 674 errno = saved_errno;
675 675 return (SETPROJ_ERR_TASK);
676 676 }
677 677 if (old_pool_name)
678 678 free(old_pool_name);
679 679 } else {
680 680 /*
681 681 * Pools are not configured, so simply create new task.
682 682 */
683 683 if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
684 684 _kva_free(kv_array);
685 685 return (SETPROJ_ERR_TASK);
686 686 }
687 687 }
688 688
689 689 if (project_name == NULL) {
690 690 /*
691 691 * In the case that we are starting a new task in the
692 692 * current project, we are finished, since the current
693 693 * resource controls will still apply. (Implicit behaviour:
694 694 * a project must be entirely logged out before name
695 695 * service changes will take effect.)
696 696 */
697 697 _kva_free(kv_array);
698 698 return (projid);
699 699 }
700 700
701 701 if (kv_array == NULL)
702 702 return (0);
703 703
704 704 for (i = 0; i < kv_array->length; i++) {
705 705 /*
706 706 * Providing a special, i.e. a non-resource control, key? Then
707 707 * parse that key here and end with "continue;".
708 708 */
709 709
710 710 /*
711 711 * For generic bindings, the kernel performs the binding, as
712 712 * these are resource controls advertised by kernel subsystems.
713 713 */
714 714
715 715 /*
716 716 * Check for known attribute name.
717 717 */
718 718 errno = 0;
719 719 if (rctl_walk(rctlwalkfunc, (void *)kv_array->data[i].key)
720 720 == 0)
721 721 continue;
722 722 if (errno) {
723 723 _kva_free(kv_array);
724 724 return (SETPROJ_ERR_TASK);
725 725 }
726 726
727 727 ret = rctl_set(kv_array->data[i].key,
728 728 kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
729 729
730 730 if (ret && unknown == 0) {
731 731 /*
732 732 * We only report the first failure.
733 733 */
734 734 unknown = i + 1;
735 735 }
736 736
737 737 if (ret && ret != SETFAILED) {
738 738 /*
739 739 * We abort if we couldn't set a component, but if
740 740 * it's merely that the system didn't recognize it, we
741 741 * continue, as this could be a third party attribute.
742 742 */
743 743 break;
744 744 }
745 745 }
746 746 _kva_free(kv_array);
747 747
748 748 return (unknown);
749 749 }
750 750
751 751 projid_t
752 752 setproject(const char *project_name, const char *user_name, int flags)
753 753 {
754 754 return (setproject_proc(project_name, user_name, flags, P_MYID, NULL,
755 755 NULL));
756 756 }
757 757
758 758
759 759 priv_set_t *
760 760 setproject_initpriv(void)
761 761 {
762 762 static priv_t taskpriv = PRIV_PROC_TASKID;
763 763 static priv_t rctlpriv = PRIV_SYS_RESOURCE;
764 764 static priv_t poolpriv = PRIV_SYS_RES_CONFIG;
765 765 static priv_t schedpriv = PRIV_PROC_PRIOCNTL;
766 766 int res;
767 767
768 768 priv_set_t *nset;
769 769
770 770 if (getzoneid() == GLOBAL_ZONEID) {
771 771 res = __init_suid_priv(0, taskpriv, rctlpriv, poolpriv,
772 772 schedpriv, (char *)NULL);
773 773 } else {
774 774 res = __init_suid_priv(0, taskpriv, rctlpriv, (char *)NULL);
775 775 }
776 776
777 777 if (res != 0)
778 778 return (NULL);
779 779
780 780 nset = priv_allocset();
781 781 if (nset != NULL) {
782 782 priv_emptyset(nset);
783 783 (void) priv_addset(nset, taskpriv);
784 784 (void) priv_addset(nset, rctlpriv);
785 785 /*
786 786 * Only need these if we need to change pools, which can
787 787 * only happen if the target is in the global zone. Rather
788 788 * than checking the target's zone just check our own
789 789 * (since if we're in a non-global zone we won't be able
790 790 * to control processes in other zones).
791 791 */
792 792 if (getzoneid() == GLOBAL_ZONEID) {
793 793 (void) priv_addset(nset, poolpriv);
794 794 (void) priv_addset(nset, schedpriv);
795 795 }
796 796 }
797 797 return (nset);
798 798 }
↓ open down ↓ |
263 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX