Mercurial > illumos > illumos-gate
changeset 3684:a0773f73b68d
PSARC 2006/554 setproject(3PROJECT) defining, and enhancing behaviour
6194864 simultaneous setproject()'s on the same project can fail to set rctl
6449567 setproject(3PROJECT) deletes resource controls set through prctl(1M)
6450539 projmod(1M) does not provide a mechanism to refresh "in-core" enforced resource controls
6491754 project.max-contracts should not allow basic privileges
6491804 task.final project property is not honoured if pools are not enabled
line wrap: on
line diff
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm Tue Feb 20 10:39:20 2007 -0800 @@ -1,13 +1,12 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -38,7 +37,7 @@ XSLoader::load(__PACKAGE__, $VERSION); our (@EXPORT_OK, %EXPORT_TAGS); -my @constants = qw(TASK_NORMAL TASK_FINAL); +my @constants = qw(TASK_NORMAL TASK_FINAL TASK_PROJ_PURGE); my @syscalls = qw(settaskid gettaskid); @EXPORT_OK = (@constants, @syscalls); %EXPORT_TAGS = (CONSTANTS => \@constants, SYSCALLS => \@syscalls,
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Task.xs contains XS wrappers for the task maniplulation functions. @@ -58,6 +57,7 @@ stash = gv_stashpv("Sun::Solaris::Task", TRUE); newCONSTSUB(stash, "TASK_NORMAL", newSViv(TASK_NORMAL)); newCONSTSUB(stash, "TASK_FINAL", newSViv(TASK_FINAL)); + newCONSTSUB(stash, "TASK_PROJ_PURGE", newSViv(TASK_PROJ_PURGE)); } taskid_t
--- a/usr/src/cmd/projadd/projmod.pl Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/projadd/projmod.pl Tue Feb 20 10:39:20 2007 -0800 @@ -3,9 +3,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -38,6 +37,7 @@ use POSIX qw(locale_h); use Sun::Solaris::Utils qw(textdomain gettext); use Sun::Solaris::Project qw(:ALL :PRIVATE); +use Sun::Solaris::Task qw(:ALL); # # Print a usage message and exit. @@ -51,7 +51,7 @@ printf(STDERR gettext( "Usage: %s [-n] [-f filename]\n"), $prog); printf(STDERR gettext( - " %s [-n] [-f filename] [-p projid [-o]] [-c comment]\n". + " %s [-n] [-A|-f filename] [-p projid [-o]] [-c comment]\n". " %s [-a|-s|-r] [-U user[,user...]] [-G group[,group...]]\n". " %s [-K name[=value[,value...]]] [-l new_projectname] ". "project\n"), $prog, $space, $space, $space); @@ -360,7 +360,7 @@ $flags = {}; my $modify = 0; -my $projfile = &PROJF_PATH; +my $projfile; my $opt_n; my $opt_c; my $opt_o; @@ -372,6 +372,7 @@ my $opt_U; my $opt_G; my @opt_K; +my $opt_A; GetOptions("f=s" => \$projfile, "n" => \$opt_n, @@ -384,11 +385,12 @@ "a" => \$opt_a, "U=s" => \$opt_U, "G=s" => \$opt_G, - "K=s" => \@opt_K) || usage(); + "K=s" => \@opt_K, + "A" => \$opt_A) || usage(); usage(gettext('Invalid command-line arguments')) if (@ARGV > 1); -if ($opt_c || $opt_G || $opt_l || $opt_p || $opt_U || @opt_K) { +if ($opt_c || $opt_G || $opt_l || $opt_p || $opt_U || @opt_K || $opt_A) { $modify = 1; if (! defined($ARGV[0])) { usage(gettext('No project name specified')); @@ -399,6 +401,14 @@ usage(gettext('missing -c, -G, -l, -p, -U, or -K')); } +if (defined($opt_A) && defined($projfile)) { + usage(gettext('-A and -f are mutually exclusive')); +} + +if (! defined($projfile)) { + $projfile = &PROJF_PATH; +} + if ($modify && $projfile eq '-') { usage(gettext('Cannot modify standard input')); } @@ -654,8 +664,69 @@ } -exit(0); +if (defined($opt_A)) { + my $error; + + if (($error = setproject($pname, "root", TASK_FINAL|TASK_PROJ_PURGE)) != 0) { + if ($error == SETPROJ_ERR_TASK) { + if ($!{EAGAIN}) { + error([5, gettext("resource control limit has ". + "been reached\n")]); + } elsif ($!{ESRCH}) { + error([5, gettext("user \"%s\" is not a member ". + "of project \"%s\"\n"), "root", $pname]); + } elsif ($!{EACCES}) { + error([5, gettext("the invoking task is final\n" + )]); + } else { + error([5, gettext("could not join project \"%s". + "\"\n"), $pname]); + } + } elsif ($error == SETPROJ_ERR_POOL) { + if ($!{EACCES}) { + error([5, gettext("no resource pool accepting ". + "default bindings exists for project \"%s". + "\"\n"), $pname]); + } elsif ($!{ESRCH}) { + error([5, gettext("specified resource pool ". + "does not exist for project \"%s\"\n"), + $pname]); + } else { + error([5, gettext("could not bind to default ". + "resource pool for project \"%s\"\n"), + $pname]); + } + } else { + # + # $error represents the position - within the semi-colon + # delimited $attribute - that generated the error + # + if ($error <= 0) { + error([5, gettext("setproject failed for ". + "project \"%s\"\n"), $pname]); + } else { + my ($name, $projid, $comment, $users_ref, + $groups_ref, $attr) = getprojbyname($pname); + my $attribute = ($attr =~ + /(\S+?)=\S+?(?:;|\z)/g)[$error - 1]; + if (!$attribute) { + error([5, gettext("warning, resource ". + "control assignment failed for ". + "project \"%s\" attribute %d\n"), + $pname, $error]); + } else { + error([5, gettext("warning, %s ". + "resource control assignment ". + "failed for project \"%s\"\n"), + $attribute, $pname]); + } + } + } + } +} + +exit(0);
--- a/usr/src/cmd/truss/codes.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/truss/codes.c Tue Feb 20 10:39:20 2007 -0800 @@ -1129,6 +1129,7 @@ case 1: str = "SETRCTL"; break; case 2: str = "RCTLSYS_LST"; break; case 3: str = "RCTLSYS_CTL"; break; + case 4: str = "RCTLSYS_SETPROJ"; break; default: str = "UNKNOWN"; break; } return (str);
--- a/usr/src/cmd/truss/expound.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/truss/expound.c Tue Feb 20 10:39:20 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -93,6 +93,7 @@ #include <tsol/label.h> #include <sys/nvpair.h> #include <libnvpair.h> +#include <sys/rctl_impl.h> #include "ramdata.h" #include "systable.h" @@ -4687,6 +4688,8 @@ static void show_rctls(private_t *pri) { + int entry; + switch (pri->sys_args[0]) { case 0: /* getrctl */ case 1: /* setrctl */ @@ -4705,6 +4708,16 @@ show_rctlblk(pri, pri->sys_args[3]); } break; + case 4: /* setprojrctl */ + for (entry = 0; entry < pri->sys_args[4]; entry++) { + (void) printf("%s\tNew rctlblk[%d]: 0x%lx\n", + pri->pname, entry, + (long)RCTLBLK_INC(pri->sys_args[3], entry)); + if (RCTLBLK_INC(pri->sys_args[3], entry) != NULL) { + show_rctlblk(pri, + (long)RCTLBLK_INC(pri->sys_args[3], entry)); + } + } } }
--- a/usr/src/cmd/truss/print.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/truss/print.c Tue Feb 20 10:39:20 2007 -0800 @@ -80,6 +80,7 @@ #include <sys/rctl.h> #include <sys/rctl_impl.h> #include <sys/fork.h> +#include <sys/task.h> #include "ramdata.h" #include "print.h" #include "proto.h" @@ -2542,6 +2543,20 @@ } /* + * Print setprojrctl flags + */ +void +prt_spf(private_t *pri, int raw, long val) +{ + long action = val & TASK_PROJ_MASK; + + if (!raw && (action == TASK_PROJ_PURGE)) + outstring(pri, "TASK_PROJ_PURGE"); + else + prt_hex(pri, 0, val); +} + +/* * Print forkx() flags */ void @@ -2664,5 +2679,6 @@ prt_rsf, /* RSF -- print setrctl() flags */ prt_rcf, /* RCF -- print rctlsys_ctl() flags */ prt_fxf, /* FXF -- print forkx() flags */ + prt_spf, /* SPF -- print rctlsys_projset() flags */ prt_dec, /* HID -- hidden argument, make this the last one */ };
--- a/usr/src/cmd/truss/print.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/truss/print.h Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -133,7 +133,8 @@ #define RSF 91 /* print rctlsys_set flags */ #define RCF 92 /* print rctlsys_ctl flags */ #define FXF 93 /* print forkx flags */ -#define HID 94 /* hidden argument, don't print */ +#define SPF 94 /* print rctlsys_projset flags */ +#define HID 95 /* hidden argument, don't print */ /* make sure HID is always the last member */ /*
--- a/usr/src/cmd/truss/systable.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/cmd/truss/systable.c Tue Feb 20 10:39:20 2007 -0800 @@ -578,6 +578,7 @@ {"setrctl", 6, DEC, NOV, HID, STG, HEX, HEX, HID, RSF}, /* 1 */ {"rctlsys_lst", 6, DEC, NOV, HID, HID, HEX, HID, HEX, HID}, /* 2 */ {"rctlsys_ctl", 6, DEC, NOV, HID, STG, HEX, HID, HID, RCF}, /* 3 */ +{"setprojrctl", 6, DEC, NOV, HID, STG, HID, HEX, HEX, SPF}, /* 4 */ }; #define NRCTLCODE (sizeof (rctltable) / sizeof (struct systable))
--- a/usr/src/lib/common/inc/c_synonyms.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/common/inc/c_synonyms.h Tue Feb 20 10:39:20 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -800,6 +800,7 @@ #define setppriv _setppriv #define setpwent _setpwent #define setrctl _setrctl +#define setprojrctl _setprojrctl #define setregid _setregid #define setreuid _setreuid #define setrlimit _setrlimit
--- a/usr/src/lib/libc/inc/synonyms.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libc/inc/synonyms.h Tue Feb 20 10:39:20 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -917,6 +917,7 @@ #define setpgid _setpgid #define setpgrp _setpgrp #define setppriv _setppriv +#define setprojrctl _setprojrctl #define setpwent _setpwent #define setrctl _setrctl #define setregid _setregid
--- a/usr/src/lib/libc/port/llib-lc Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libc/port/llib-lc Tue Feb 20 10:39:20 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1348,6 +1348,7 @@ int setrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk, int flags); /* (private functions) */ +int setprojrctl(const char *name, rctlblk_t *new_rblk, size_t size, int flags); int rctlctl(const char *, rctlblk_t *, int); size_t rctllist(char *, size_t);
--- a/usr/src/lib/libc/port/mapfile-vers Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libc/port/mapfile-vers Tue Feb 20 10:39:20 2007 -0800 @@ -1989,6 +1989,8 @@ _setgrent; _setlogmask; _setpwent; + setprojrctl; + _setprojrctl; _setregid; _setreuid; setsigacthandler;
--- a/usr/src/lib/libc/port/sys/rctlsys.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libc/port/sys/rctlsys.c Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,6 +29,7 @@ #pragma weak getrctl = _getrctl #pragma weak rctllist = _rctllist #pragma weak rctlctl = _rctlctl +#pragma weak setprojrctl = _setprojrctl #include "synonyms.h" #include <sys/types.h> @@ -71,3 +71,10 @@ { return (syscall(SYS_rctlsys, 3, name, rblk, NULL, 0, flags)); } + +int +setprojrctl(const char *name, rctlblk_t *new_rblk, size_t size, int flags) +{ + return (syscall(SYS_rctlsys, + 4, name, NULL, new_rblk, size, flags)); +}
--- a/usr/src/lib/libproc/common/libproc.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libproc/common/libproc.h Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -325,6 +325,8 @@ int, struct rlimit *); extern int pr_setrlimit(struct ps_prochandle *, int, const struct rlimit *); +extern int pr_setprojrctl(struct ps_prochandle *, const char *, + rctlblk_t *, size_t, int); #if defined(_LARGEFILE64_SOURCE) extern int pr_getrlimit64(struct ps_prochandle *, int, struct rlimit64 *);
--- a/usr/src/lib/libproc/common/llib-lproc Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libproc/common/llib-lproc Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -23,7 +22,7 @@ /* PROTOLIB1 */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -248,6 +247,8 @@ rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag); int pr_setrctl(struct ps_prochandle *Pr, const char *rname, rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag); +int pr_setprojrctl(struct ps_prochandle *Pr, const char *rname, + rctlblk_t *new_blk, size_t size, int rflag); /* pr_getrlimit.c */ int pr_getrlimit(struct ps_prochandle *Pr,
--- a/usr/src/lib/libproc/common/mapfile-vers Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libproc/common/mapfile-vers Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -208,6 +208,7 @@ pr_pset_bind; pr_rename; pr_setitimer; + pr_setprojrctl; pr_setrctl; pr_setrlimit; pr_setrlimit64;
--- a/usr/src/lib/libproc/common/pr_getrctl.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libproc/common/pr_getrctl.c Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,8 +19,8 @@ * CDDL HEADER END */ /* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -33,6 +32,7 @@ #include <errno.h> #include <strings.h> #include "libproc.h" +#include <sys/rctl_impl.h> /* * getrctl() system call -- executed by subject process @@ -197,3 +197,78 @@ } return (rval.sys_rval1); } + +/* + * setprojrctl() system call -- executed by subject process + */ +int +pr_setprojrctl(struct ps_prochandle *Pr, const char *rname, + rctlblk_t *new_blk, size_t size, int rflag) +{ + sysret_t rval; + argdes_t argd[6]; + argdes_t *adp; + int error; + + if (Pr == NULL) /* no subject process */ + return (setprojrctl(rname, new_blk, size, rflag)); + + adp = &argd[0]; + adp->arg_value = 4; /* switch for setprojrctls in rctlsys */ + adp->arg_object = NULL; + adp->arg_type = AT_BYVAL; + adp->arg_inout = AI_INPUT; + adp->arg_size = 0; + + adp++; + adp->arg_value = 0; + adp->arg_object = (void *)rname; + adp->arg_type = AT_BYREF; + adp->arg_inout = AI_INPUT; + adp->arg_size = strlen(rname) + 1; + + adp++; + adp->arg_value = 0; /* old_blk is not used by setprojrctls() */ + adp->arg_object = NULL; + adp->arg_type = AT_BYVAL; + adp->arg_inout = AI_INPUT; + adp->arg_size = 0; + + + adp++; + if (new_blk == NULL) { + adp->arg_value = 0; + adp->arg_object = NULL; + adp->arg_type = AT_BYVAL; + adp->arg_inout = AI_INPUT; + adp->arg_size = 0; + } else { + adp->arg_value = 0; + adp->arg_object = new_blk; + adp->arg_type = AT_BYREF; + adp->arg_inout = AI_INPUT; + adp->arg_size = rctlblk_size() * size; + } + + adp++; + adp->arg_value = size; /* obufsz is used by setrctls() */ + adp->arg_object = NULL; + adp->arg_type = AT_BYVAL; + adp->arg_inout = AI_INPUT; + adp->arg_size = 0; + + adp++; + adp->arg_value = rflag; + adp->arg_object = NULL; + adp->arg_type = AT_BYVAL; + adp->arg_inout = AI_INPUT; + adp->arg_size = 0; + + error = Psyscall(Pr, &rval, SYS_rctlsys, 6, &argd[0]); + + if (error) { + errno = (error > 0) ? error : ENOSYS; + return (-1); + } + return (rval.sys_rval1); +}
--- a/usr/src/lib/libproject/common/setproject.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/lib/libproject/common/setproject.c Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,6 +36,7 @@ #include <signal.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <nss_dbdefs.h> #include <pwd.h> #include <pool.h> @@ -45,6 +46,7 @@ #include <zone.h> #include <sys/pool.h> #include <sys/pool_impl.h> +#include <sys/rctl_impl.h> static void xstrtolower(char *s) @@ -177,7 +179,7 @@ #define BADSPEC 5 static int -rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) +rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags) { int error = 0; uint_t component = 0; @@ -185,18 +187,68 @@ uint_t state = 0; char *component_head; rctlblk_t *blk; + rctlblk_t *ablk; + int project_entity = 0; + int count = 0; + char *tmp; + int local_action; - remove_spaces(val); - if ((blk = malloc(rctlblk_size())) == NULL) { + /* We cannot modify a zone resource control */ + if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) { return (SETFAILED); } + remove_spaces(val); + /* - * Tear down everything with this ctl name. + * As we are operating in a new task, both process and task + * rctls are referenced by this process alone. Tear down + * matching process and task rctls only. + * + * blk will be the RCPRIV_SYSTEM for this resource control, + * populated by the last pr_setrctl(). */ - while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 && - rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) { - (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE); + if ((strncmp(ctl_name, "process.", strlen("process.")) == 0) || + (strncmp(ctl_name, "task.", strlen("task.")) == 0)) { + + if ((blk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) { + return (SETFAILED); + } + + + while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 && + rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) { + (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE); + } + + } else if (strncmp(ctl_name, "project.", strlen("project.")) == 0) { + project_entity = 1; + + /* Determine how many attributes we'll be setting */ + for (tmp = val; *tmp != '\0'; tmp++) { + if (*tmp == '(') + count++; + } + + /* Allocate sufficient memory for rctl blocks */ + if ((count == 0) || ((ablk = + (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) { + return (SETFAILED); + } + blk = ablk; + + /* + * In order to set the new rctl's local_action, we'll need the + * current value of global_flags. We obtain global_flags by + * performing a pr_getrctl(). + * + * The ctl_name has been verified as valid, so we have no reason + * to suspect that pr_getrctl() will return an error. + */ + (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST); + + } else { + return (SETFAILED); } /* @@ -205,11 +257,13 @@ rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED); rctlblk_set_value(blk, 0); rctlblk_set_local_flags(blk, 0); + if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS) - rctlblk_set_local_action(blk, RCTL_LOCAL_DENY, 0); + local_action = RCTL_LOCAL_DENY; else - rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0); + local_action = RCTL_LOCAL_NOACTION; + rctlblk_set_local_action(blk, local_action, 0); for (; ; val++) { switch (*val) { @@ -238,22 +292,35 @@ state &= ~INPAREN; component = 0; valuecount++; - if (pr_setrctl(Pr, ctl_name, NULL, blk, - RCTL_INSERT) == -1) + + if (project_entity && + (rctlblk_get_privilege(blk) == + RCPRIV_BASIC)) { error = SETFAILED; + } else if (project_entity) { + if (valuecount > count) + return (SETFAILED); + + if (valuecount != count) + blk = RCTLBLK_INC(ablk, + valuecount); + } else { + if (pr_setrctl(Pr, ctl_name, + NULL, blk, RCTL_INSERT) == + -1) + error = SETFAILED; + } /* re-initialize block */ - rctlblk_set_privilege(blk, - RCPRIV_PRIVILEGED); - rctlblk_set_value(blk, 0); - rctlblk_set_local_flags(blk, 0); - if (rctlblk_get_global_flags(blk) & - RCTL_GLOBAL_DENY_ALWAYS) + if (!project_entity || + (valuecount != count)) { + rctlblk_set_privilege(blk, + RCPRIV_PRIVILEGED); + rctlblk_set_value(blk, 0); + rctlblk_set_local_flags(blk, 0); rctlblk_set_local_action(blk, - RCTL_LOCAL_DENY, 0); - else - rctlblk_set_local_action(blk, - RCTL_LOCAL_NOACTION, 0); + local_action, 0); + } } else { error = CLOSEBEFOREOPEN; } @@ -288,6 +355,12 @@ break; } + if (project_entity) { + blk = ablk; + if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1) + error = SETFAILED; + } + free(blk); if (valuecount == 0) @@ -465,6 +538,7 @@ int ret = 0; kva_t *kv_array; struct project local_proj; /* space to store proj if not provided */ + const char *pool_name = NULL; if (project_name != NULL) { /* @@ -508,45 +582,37 @@ projid = getprojid(); } + + if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, + KV_DELIMITER)) != NULL) { + for (i = 0; i < kv_array->length; i++) { + if (strcmp(kv_array->data[i].key, + "project.pool") == 0) { + pool_name = kv_array->data[i].value; + } + if (strcmp(kv_array->data[i].key, "task.final") == 0) { + flags |= TASK_FINAL; + } + } + } + /* - * Only bind to a pool if pools are configured. + * Bind process to a pool only if pools are configured */ if (pools_enabled() == 1) { - const char *pool_name = NULL; char *old_pool_name; - int taskflags = flags; /* * Attempt to bind to pool before calling * settaskid(). */ - if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, - KV_DELIMITER)) != NULL) { - for (i = 0; i < kv_array->length; i++) { - if (strcmp(kv_array->data[i].key, - "project.pool") == 0) { - pool_name = kv_array->data[i].value; - break; - } - if (strcmp(kv_array->data[i].key, - "task.final") == 0) { - taskflags |= TASK_FINAL; - } - } - } - old_pool_name = pool_get_binding(pid); - - /* - * If parent is not bound to the default pool, then we want - * to preserve same binding as parent. - */ - if (pool_name != NULL && bind_to_pool(pool_name, pid, 0) != 0) { + if (bind_to_pool(pool_name, pid, 0) != 0) { if (old_pool_name) free(old_pool_name); _kva_free(kv_array); return (SETPROJ_ERR_POOL); } - if (pr_settaskid(Pr, projid, taskflags) == -1) { + if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) { int saved_errno = errno; /* @@ -568,9 +634,10 @@ /* * Pools are not configured, so simply create new task. */ - if (pr_settaskid(Pr, projid, flags) == -1) + if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) { + _kva_free(kv_array); return (SETPROJ_ERR_TASK); - kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, KV_DELIMITER); + } } if (project_name == NULL) { @@ -612,7 +679,7 @@ } ret = rctl_set(kv_array->data[i].key, - kv_array->data[i].value, Pr); + kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK); if (ret && unknown == 0) { /*
--- a/usr/src/uts/common/os/project.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/os/project.c Tue Feb 20 10:39:20 2007 -0800 @@ -905,8 +905,8 @@ * Per project limit on contracts. */ rc_project_contract = rctl_register("project.max-contracts", - RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT, - INT_MAX, INT_MAX, &project_contract_ops); + RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC | + RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, &project_contract_ops); rctl_add_default_limit("project.max-contracts", 10000, RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
--- a/usr/src/uts/common/os/rctl.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/os/rctl.c Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -150,6 +150,41 @@ * * The locking subsequence of interest is: p_lock, rctl_dict_lock, * rctl_lists_lock, entity->rcs_lock. + * + * The projects(4) database and project entity resource controls + * A special case is made for RCENTITY_PROJECT values set through the + * setproject(3PROJECT) interface. setproject() makes use of a private + * interface, setprojrctl(), which passes through an array of resource control + * blocks that need to be set while holding the entity->rcs_lock. This + * ensures that the act of modifying a project's resource controls is + * "atomic" within the kernel. + * + * Within the rctl sub-system, we provide two interfaces that are only used by + * the setprojrctl() code path - rctl_local_insert_all() and + * rctl_local_replace_all(). rctl_local_insert_all() will ensure that the + * resource values specified in *new_values are applied. + * rctl_local_replace_all() will purge the current rctl->rc_projdb and + * rctl->rc_values entries, and apply the *new_values. + * + * These functions modify not only the linked list of active resource controls + * (rctl->rc_values), but also a "cached" linked list (rctl->rc_projdb) of + * values set through these interfaces. To clarify: + * + * rctl->rc_values - a linked list of rctl_val_t. These are the active + * resource values associated with this rctl, and may have been set by + * setrctl() - via prctl(1M), or by setprojrctl() - via + * setproject(3PROJECT). + * + * rctl->rc_projdb - a linked list of rctl_val_t. These reflect the + * resource values set by the setprojrctl() code path. rc_projdb is not + * referenced by any other component of the rctl sub-system. + * + * As various locks are held when calling these functions, we ensure that all + * the possible memory allocations are performed prior to calling the + * function. *alloc_values is a linked list of uninitialized rctl_val_t, + * which may be used to duplicate a new resource control value (passed in as + * one of the members of the *new_values linked list), in order to populate + * rctl->rc_values. */ id_t max_rctl_hndl = 32768; @@ -1081,6 +1116,7 @@ rctl->rc_dict_entry = rde; rctl->rc_id = rde->rcd_id; + rctl->rc_projdb = NULL; rctl->rc_values = rctl_val_list_dup(rde->rcd_default_value, ragp, NULL, p); @@ -1688,6 +1724,259 @@ return (rctl_local_op(hndl, NULL, val, rctl_local_insert_cb, p)); } +/* + * rctl_local_insert_all_cb() + * + * Overview + * Called for RCENTITY_PROJECT rctls only, via rctlsys_projset(). + * + * Inserts new values from the project database (new_values). alloc_values + * should be a linked list of pre-allocated rctl_val_t, which are used to + * populate (rc_projdb). + * + * Should the *new_values linked list match the contents of the rctl's + * rp_projdb then we do nothing. + * + * Return Values + * 0 is always returned. + */ +/*ARGSUSED*/ +static int +rctl_local_insert_all_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, + rctl_t *rctl, rctl_val_t *new_values, rctl_val_t *alloc_values) +{ + rctl_val_t *val; + rctl_val_t *tmp_val; + rctl_val_t *next; + int modified = 0; + + /* + * If this the first time we've set this project rctl, then we delete + * all the privilege values. These privilege values have been set by + * rctl_add_default_limit(). + * + * We save some cycles here by not calling rctl_val_list_delete(). + */ + if (rctl->rc_projdb == NULL) { + val = rctl->rc_values; + + while (val != NULL) { + if (val->rcv_privilege == RCPRIV_PRIVILEGED) { + if (val->rcv_prev != NULL) + val->rcv_prev->rcv_next = val->rcv_next; + else + rctl->rc_values = val->rcv_next; + + if (val->rcv_next != NULL) + val->rcv_next->rcv_prev = val->rcv_prev; + + tmp_val = val; + val = val->rcv_next; + kmem_cache_free(rctl_val_cache, tmp_val); + } else { + val = val->rcv_next; + } + } + modified = 1; + } + + /* + * Delete active values previously set through the project database. + */ + val = rctl->rc_projdb; + + while (val != NULL) { + + /* Is the old value found in the new values? */ + if (rctl_val_list_find(&new_values, val) == NULL) { + + /* + * Delete from the active values if it originated from + * the project database. + */ + if (((tmp_val = rctl_val_list_find(&rctl->rc_values, + val)) != NULL) && + (tmp_val->rcv_flagaction & RCTL_LOCAL_PROJDB)) { + (void) rctl_val_list_delete(&rctl->rc_values, + tmp_val); + } + + tmp_val = val->rcv_next; + (void) rctl_val_list_delete(&rctl->rc_projdb, val); + val = tmp_val; + modified = 1; + + } else + val = val->rcv_next; + } + + /* + * Insert new values from the project database. + */ + while (new_values != NULL) { + next = new_values->rcv_next; + + /* + * Insert this new value into the rc_projdb, and duplicate this + * entry to the active list. + */ + if (rctl_val_list_insert(&rctl->rc_projdb, new_values) == 0) { + + tmp_val = alloc_values->rcv_next; + bcopy(new_values, alloc_values, sizeof (rctl_val_t)); + alloc_values->rcv_next = tmp_val; + + if (rctl_val_list_insert(&rctl->rc_values, + alloc_values) == 0) { + /* inserted move alloc_values on */ + alloc_values = tmp_val; + modified = 1; + } + } else { + /* + * Unlike setrctl() we don't want to return an error on + * a duplicate entry; we are concerned solely with + * ensuring that all the values specified are set. + */ + kmem_cache_free(rctl_val_cache, new_values); + } + new_values = next; + } + + /* Teardown any unused rctl_val_t */ + while (alloc_values != NULL) { + tmp_val = alloc_values; + alloc_values = alloc_values->rcv_next; + kmem_cache_free(rctl_val_cache, tmp_val); + } + + /* Reset the cursor if rctl values have been modified */ + if (modified) { + rctl->rc_cursor = rctl->rc_values; + rctl_val_list_reset(rctl->rc_cursor); + RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p, + rctl->rc_cursor->rcv_value)); + } + + return (0); +} + +int +rctl_local_insert_all(rctl_hndl_t hndl, rctl_val_t *new_values, + rctl_val_t *alloc_values, struct proc *p) +{ + return (rctl_local_op(hndl, new_values, alloc_values, + rctl_local_insert_all_cb, p)); +} + +/* + * rctl_local_replace_all_cb() + * + * Overview + * Called for RCENTITY_PROJECT rctls only, via rctlsys_projset(). + * + * Clears the active rctl values (rc_values), and stored values from the + * previous insertions from the project database (rc_projdb). + * + * Inserts new values from the project database (new_values). alloc_values + * should be a linked list of pre-allocated rctl_val_t, which are used to + * populate (rc_projdb). + * + * Return Values + * 0 is always returned. + */ +/*ARGSUSED*/ +static int +rctl_local_replace_all_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, + rctl_t *rctl, rctl_val_t *new_values, rctl_val_t *alloc_values) +{ + rctl_val_t *val; + rctl_val_t *next; + rctl_val_t *tmp_val; + + /* Delete all the privilege vaules */ + val = rctl->rc_values; + + while (val != NULL) { + if (val->rcv_privilege == RCPRIV_PRIVILEGED) { + if (val->rcv_prev != NULL) + val->rcv_prev->rcv_next = val->rcv_next; + else + rctl->rc_values = val->rcv_next; + + if (val->rcv_next != NULL) + val->rcv_next->rcv_prev = val->rcv_prev; + + tmp_val = val; + val = val->rcv_next; + kmem_cache_free(rctl_val_cache, tmp_val); + } else { + val = val->rcv_next; + } + } + + /* Delete the contents of rc_projdb */ + val = rctl->rc_projdb; + while (val != NULL) { + + tmp_val = val; + val = val->rcv_next; + kmem_cache_free(rctl_val_cache, tmp_val); + } + rctl->rc_projdb = NULL; + + /* + * Insert new values from the project database. + */ + while (new_values != NULL) { + next = new_values->rcv_next; + + if (rctl_val_list_insert(&rctl->rc_projdb, new_values) == 0) { + tmp_val = alloc_values->rcv_next; + bcopy(new_values, alloc_values, sizeof (rctl_val_t)); + alloc_values->rcv_next = tmp_val; + + if (rctl_val_list_insert(&rctl->rc_values, + alloc_values) == 0) { + /* inserted, so move alloc_values on */ + alloc_values = tmp_val; + } + } else { + /* + * Unlike setrctl() we don't want to return an error on + * a duplicate entry; we are concerned solely with + * ensuring that all the values specified are set. + */ + kmem_cache_free(rctl_val_cache, new_values); + } + + new_values = next; + } + + /* Teardown any unused rctl_val_t */ + while (alloc_values != NULL) { + tmp_val = alloc_values; + alloc_values = alloc_values->rcv_next; + kmem_cache_free(rctl_val_cache, tmp_val); + } + + /* Always reset the cursor */ + rctl->rc_cursor = rctl->rc_values; + rctl_val_list_reset(rctl->rc_cursor); + RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p, + rctl->rc_cursor->rcv_value)); + + return (0); +} + +int +rctl_local_replace_all(rctl_hndl_t hndl, rctl_val_t *new_values, + rctl_val_t *alloc_values, struct proc *p) +{ + return (rctl_local_op(hndl, new_values, alloc_values, + rctl_local_replace_all_cb, p)); +} + static int rctl_local_replace_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e, rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval)
--- a/usr/src/uts/common/sys/rctl.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/sys/rctl.h Tue Feb 20 10:39:20 2007 -0800 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,9 +44,10 @@ #define RCTL_LOCAL_DENY 0x00000002 #define RCTL_LOCAL_MAXIMAL 0x80000000 +#define RCTL_LOCAL_PROJDB 0x40000000 #define RCTL_LOCAL_ACTION_MASK 0xffff0000 -#define RCTL_LOCAL_MASK 0x80000003 +#define RCTL_LOCAL_MASK 0xc0000003 /* * Available global actions and flags. @@ -216,6 +217,7 @@ rctl_val_t *rc_cursor; /* currently enforced value */ struct rctl_dict_entry *rc_dict_entry; /* global control properties */ rctl_hndl_t rc_id; /* control handle (hash key) */ + rctl_val_t *rc_projdb; /* project database rctls */ } rctl_t; /* @@ -309,6 +311,10 @@ int rctl_local_delete(rctl_hndl_t, rctl_val_t *, struct proc *p); int rctl_local_insert(rctl_hndl_t, rctl_val_t *, struct proc *p); +int rctl_local_insert_all(rctl_hndl_t, rctl_val_t *, rctl_val_t *, + struct proc *p); +int rctl_local_replace_all(rctl_hndl_t, rctl_val_t *, rctl_val_t *, + struct proc *p); int rctl_local_get(rctl_hndl_t, rctl_val_t *, rctl_val_t *, struct proc *p); int rctl_local_replace(rctl_hndl_t, rctl_val_t *, rctl_val_t *, struct proc *p);
--- a/usr/src/uts/common/sys/rctl_impl.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/sys/rctl_impl.h Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,6 +43,7 @@ extern int rctlctl(const char *, rctlblk_t *, int); extern size_t rctllist(char *, size_t); +extern int setprojrctl(const char *, rctlblk_t *, size_t, int); #endif /* _KERNEL */ @@ -62,6 +62,10 @@ extern uint_t rlim_fd_cur; extern uint_t rlim_fd_max; +/* Given an array of rctlblk_t calculate the address of the n'th element */ +#define RCTLBLK_INC(blk, n) (rctlblk_t *)(((char *)blk) \ + + (n * rctlblk_size())) + #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/task.h Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/sys/task.h Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +38,10 @@ #define TASK_NORMAL 0x0 /* task may create tasks via settaskid() */ #define TASK_FINAL 0x1 /* task finalized, settaskid() will fail */ +#define TASK_MASK 0x1 /* task flags mask */ + +#define TASK_PROJ_PURGE 0x100000 /* purge project.* rctl entities */ +#define TASK_PROJ_MASK 0x100000 #ifdef _KERNEL
--- a/usr/src/uts/common/syscall/rctlsys.c Tue Feb 20 09:46:06 2007 -0800 +++ b/usr/src/uts/common/syscall/rctlsys.c Tue Feb 20 10:39:20 2007 -0800 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -843,6 +842,155 @@ return (0); } +/* + * The arbitrary maximum number of rctl_opaque_t that we can pass to + * rctl_projset(). + */ +#define RCTL_PROJSET_MAXSIZE 1024 + +static long +rctlsys_projset(char *name, rctl_opaque_t *rblk, size_t size, int flags) +{ + rctl_dict_entry_t *krde; + rctl_opaque_t *krblk; + char *kname; + size_t klen; + rctl_hndl_t hndl; + rctl_val_t *new_values = NULL; + rctl_val_t *alloc_values = NULL; + rctl_val_t *new_val; + rctl_val_t *alloc_val; + int error = 0; + int count; + + kname = kmem_alloc(MAXPATHLEN, KM_SLEEP); + + if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) { + kmem_free(kname, MAXPATHLEN); + return (set_errno(EFAULT)); + } + + if (secpolicy_rctlsys(CRED(), B_TRUE) != 0) { + kmem_free(kname, MAXPATHLEN); + return (set_errno(EPERM)); + } + + if (size > RCTL_PROJSET_MAXSIZE) { + kmem_free(kname, MAXPATHLEN); + return (set_errno(EINVAL)); + } + + if ((hndl = rctl_hndl_lookup(kname)) == -1) { + kmem_free(kname, MAXPATHLEN); + return (set_errno(EINVAL)); + } + + krde = rctl_dict_lookup_hndl(hndl); + + /* If not a project entity then exit */ + if ((krde->rcd_entity != RCENTITY_PROJECT) || (size <= 0)) { + kmem_free(kname, MAXPATHLEN); + return (set_errno(EINVAL)); + } + + /* Allocate an array large enough for all resource control blocks */ + krblk = kmem_zalloc(sizeof (rctl_opaque_t) * size, KM_SLEEP); + + if (copyin(rblk, krblk, sizeof (rctl_opaque_t) * size) == 0) { + + for (count = 0; (count < size) && (error == 0); count++) { + new_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); + alloc_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP); + + rctlsys_rblk_xfrm(&krblk[count], NULL, new_val, + RBX_FROM_BLK | RBX_VAL); + + /* + * Project entity resource control values should always + * be privileged + */ + if (new_val->rcv_privilege != RCPRIV_PRIVILEGED) { + kmem_cache_free(rctl_val_cache, new_val); + kmem_cache_free(rctl_val_cache, alloc_val); + + error = EPERM; + } else if (rctl_invalid_value(krde, new_val) == 0) { + + /* + * This is a project entity; we do not set + * rcv_action_recipient or rcv_action_recip_pid + */ + new_val->rcv_action_recipient = NULL; + new_val->rcv_action_recip_pid = -1; + new_val->rcv_flagaction |= RCTL_LOCAL_PROJDB; + new_val->rcv_firing_time = 0; + + new_val->rcv_prev = NULL; + new_val->rcv_next = new_values; + new_values = new_val; + + /* + * alloc_val is left largely uninitialized, it + * is a pre-allocated rctl_val_t which is used + * later in rctl_local_replace_all() / + * rctl_local_insert_all(). + */ + alloc_val->rcv_prev = NULL; + alloc_val->rcv_next = alloc_values; + alloc_values = alloc_val; + } else { + kmem_cache_free(rctl_val_cache, new_val); + kmem_cache_free(rctl_val_cache, alloc_val); + + error = EINVAL; + } + } + + kmem_free(krblk, sizeof (rctl_opaque_t) * size); + } else { + error = EFAULT; + } + + kmem_free(kname, MAXPATHLEN); + + if (error) { + /* + * We will have the same number of items in the alloc_values + * linked list, as we have in new_values. However, we remain + * cautious, and teardown the linked lists individually. + */ + while (new_values != NULL) { + new_val = new_values; + new_values = new_values->rcv_next; + kmem_cache_free(rctl_val_cache, new_val); + } + + while (alloc_values != NULL) { + alloc_val = alloc_values; + alloc_values = alloc_values->rcv_next; + kmem_cache_free(rctl_val_cache, alloc_val); + } + + return (set_errno(error)); + } + + /* + * We take the p_lock here to maintain consistency with other functions + * - rctlsys_get() and rctlsys_set() + */ + mutex_enter(&curproc->p_lock); + if (flags & TASK_PROJ_PURGE) { + (void) rctl_local_replace_all(hndl, new_values, alloc_values, + curproc); + } else { + (void) rctl_local_insert_all(hndl, new_values, alloc_values, + curproc); + } + mutex_exit(&curproc->p_lock); + + return (0); +} + long rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags) { @@ -864,6 +1012,11 @@ * Private code for rctladm(1M): "rctlctl". */ return (rctlsys_ctl(name, obuf, flags)); + case 4: + /* + * Private code for setproject(3PROJECT). + */ + return (rctlsys_projset(name, nbuf, obufsz, flags)); default: return (set_errno(EINVAL));