diff options
author | rd117015 <none@none> | 2007-02-20 10:39:20 -0800 |
---|---|---|
committer | rd117015 <none@none> | 2007-02-20 10:39:20 -0800 |
commit | 532877c46d04a2d0b254f9b5797720078adcea07 (patch) | |
tree | 6a099b60988ee5b9c2a654492f35be5dce1ffee8 /usr/src | |
parent | 0a9f9c2a7d4d961e3ed3221accb2c04919531d23 (diff) | |
download | illumos-joyent-532877c46d04a2d0b254f9b5797720078adcea07.tar.gz |
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
Diffstat (limited to 'usr/src')
24 files changed, 823 insertions, 108 deletions
diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm index bb7c72700a..9dbdf26274 100644 --- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm +++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm @@ -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 @@ use XSLoader; 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, diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs index b18968440d..8cdbb9e403 100644 --- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs +++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs @@ -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 @@ BOOT: 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 diff --git a/usr/src/cmd/projadd/projmod.pl b/usr/src/cmd/projadd/projmod.pl index e522747629..2d3f07e1a2 100644 --- a/usr/src/cmd/projadd/projmod.pl +++ b/usr/src/cmd/projadd/projmod.pl @@ -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 Getopt::Long qw(:config no_ignore_case bundling); 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 @@ sub usage 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 @@ my ($pname, $flags); $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_s; my $opt_U; my $opt_G; my @opt_K; +my $opt_A; GetOptions("f=s" => \$projfile, "n" => \$opt_n, @@ -384,11 +385,12 @@ GetOptions("f=s" => \$projfile, "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 @@ if (!$modify && defined($ARGV[0])) { 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 @@ if ($modify) { } -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); diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c index b3867d52ee..1e734fd926 100644 --- a/usr/src/cmd/truss/codes.c +++ b/usr/src/cmd/truss/codes.c @@ -1129,6 +1129,7 @@ rctlsyscode(int code) 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); diff --git a/usr/src/cmd/truss/expound.c b/usr/src/cmd/truss/expound.c index e5213b88d5..e158f96343 100644 --- a/usr/src/cmd/truss/expound.c +++ b/usr/src/cmd/truss/expound.c @@ -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 @@ show_rctlblk(private_t *pri, long _rctlblk) 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_rctls(private_t *pri) 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)); + } + } } } diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c index 09dec70e82..8bdc4134e0 100644 --- a/usr/src/cmd/truss/print.c +++ b/usr/src/cmd/truss/print.c @@ -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 @@ prt_rcf(private_t *pri, int raw, long val) } /* + * 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 @@ void (* const Print[])() = { 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 */ }; diff --git a/usr/src/cmd/truss/print.h b/usr/src/cmd/truss/print.h index 9a4482139e..9d4239cce8 100644 --- a/usr/src/cmd/truss/print.h +++ b/usr/src/cmd/truss/print.h @@ -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 @@ extern "C" { #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 */ /* diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c index e9b8c6a6e5..61ff8cb7dc 100644 --- a/usr/src/cmd/truss/systable.c +++ b/usr/src/cmd/truss/systable.c @@ -578,6 +578,7 @@ const struct systable rctltable[] = { {"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)) diff --git a/usr/src/lib/common/inc/c_synonyms.h b/usr/src/lib/common/inc/c_synonyms.h index 581f55150f..d652cc06c2 100644 --- a/usr/src/lib/common/inc/c_synonyms.h +++ b/usr/src/lib/common/inc/c_synonyms.h @@ -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 @@ extern "C" { #define setppriv _setppriv #define setpwent _setpwent #define setrctl _setrctl +#define setprojrctl _setprojrctl #define setregid _setregid #define setreuid _setreuid #define setrlimit _setrlimit diff --git a/usr/src/lib/libc/inc/synonyms.h b/usr/src/lib/libc/inc/synonyms.h index faa9d33034..209d7f6063 100644 --- a/usr/src/lib/libc/inc/synonyms.h +++ b/usr/src/lib/libc/inc/synonyms.h @@ -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 @@ extern "C" { #define setpgid _setpgid #define setpgrp _setpgrp #define setppriv _setppriv +#define setprojrctl _setprojrctl #define setpwent _setpwent #define setrctl _setrctl #define setregid _setregid diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc index 169b444f6a..cff6f24c5d 100644 --- a/usr/src/lib/libc/port/llib-lc +++ b/usr/src/lib/libc/port/llib-lc @@ -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 getrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk, 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); diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index 560ac9d878..1f3fdc9d6a 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -1989,6 +1989,8 @@ SUNWprivate_1.1 { _setgrent; _setlogmask; _setpwent; + setprojrctl; + _setprojrctl; _setregid; _setreuid; setsigacthandler; diff --git a/usr/src/lib/libc/port/sys/rctlsys.c b/usr/src/lib/libc/port/sys/rctlsys.c index e47511ac2a..9e395d3048 100644 --- a/usr/src/lib/libc/port/sys/rctlsys.c +++ b/usr/src/lib/libc/port/sys/rctlsys.c @@ -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 @@ rctlctl(const char *name, rctlblk_t *rblk, int flags) { 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)); +} diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h index 07e58fa05c..d12fda05e3 100644 --- a/usr/src/lib/libproc/common/libproc.h +++ b/usr/src/lib/libproc/common/libproc.h @@ -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 @@ extern int pr_getrlimit(struct ps_prochandle *, 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 *); diff --git a/usr/src/lib/libproc/common/llib-lproc b/usr/src/lib/libproc/common/llib-lproc index 015de9ca0e..b9eff09617 100644 --- a/usr/src/lib/libproc/common/llib-lproc +++ b/usr/src/lib/libproc/common/llib-lproc @@ -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 @@ int pr_getrctl(struct ps_prochandle *Pr, const char *rname, 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, diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers index ef256570ce..758f43d99f 100644 --- a/usr/src/lib/libproc/common/mapfile-vers +++ b/usr/src/lib/libproc/common/mapfile-vers @@ -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 @@ SUNWprivate_1.1 { pr_pset_bind; pr_rename; pr_setitimer; + pr_setprojrctl; pr_setrctl; pr_setrlimit; pr_setrlimit64; diff --git a/usr/src/lib/libproc/common/pr_getrctl.c b/usr/src/lib/libproc/common/pr_getrctl.c index d54fc228a6..9cbf7dfa0c 100644 --- a/usr/src/lib/libproc/common/pr_getrctl.c +++ b/usr/src/lib/libproc/common/pr_getrctl.c @@ -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 @@ pr_setrctl(struct ps_prochandle *Pr, const char *rname, } 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); +} diff --git a/usr/src/lib/libproject/common/setproject.c b/usr/src/lib/libproject/common/setproject.c index d22878a36f..e15c719c5c 100644 --- a/usr/src/lib/libproject/common/setproject.c +++ b/usr/src/lib/libproject/common/setproject.c @@ -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 @@ build_rctlblk(rctlblk_t *blk, int comp_num, char *component) #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 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) uint_t state = 0; char *component_head; rctlblk_t *blk; - - remove_spaces(val); - if ((blk = malloc(rctlblk_size())) == NULL) { + rctlblk_t *ablk; + int project_entity = 0; + int count = 0; + char *tmp; + int local_action; + + /* 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 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) 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 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) 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) - rctlblk_set_local_action(blk, - RCTL_LOCAL_DENY, 0); - else + 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_NOACTION, 0); + local_action, 0); + } } else { error = CLOSEBEFOREOPEN; } @@ -288,6 +355,12 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr) 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 @@ setproject_proc(const char *project_name, const char *user_name, int flags, 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 @@ setproject_proc(const char *project_name, const char *user_name, int flags, 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 @@ setproject_proc(const char *project_name, const char *user_name, int flags, /* * 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 @@ setproject_proc(const char *project_name, const char *user_name, int flags, } 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) { /* diff --git a/usr/src/uts/common/os/project.c b/usr/src/uts/common/os/project.c index c17ba2b414..3c17a0dc38 100644 --- a/usr/src/uts/common/os/project.c +++ b/usr/src/uts/common/os/project.c @@ -905,8 +905,8 @@ project_init(void) * 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); diff --git a/usr/src/uts/common/os/rctl.c b/usr/src/uts/common/os/rctl.c index 026d6b13ed..3aa6e7b6cc 100644 --- a/usr/src/uts/common/os/rctl.c +++ b/usr/src/uts/common/os/rctl.c @@ -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_set_init(rctl_entity_t entity, struct proc *p, rctl_entity_p_t *e, 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 @@ rctl_local_insert(rctl_hndl_t hndl, rctl_val_t *val, struct proc *p) 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) diff --git a/usr/src/uts/common/sys/rctl.h b/usr/src/uts/common/sys/rctl.h index a8480c2768..2061398fba 100644 --- a/usr/src/uts/common/sys/rctl.h +++ b/usr/src/uts/common/sys/rctl.h @@ -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 @@ extern "C" { #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 @@ typedef struct rctl { 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_global_set(const char *name, rctl_dict_entry_t *); 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); diff --git a/usr/src/uts/common/sys/rctl_impl.h b/usr/src/uts/common/sys/rctl_impl.h index c3d7d118ce..c37f9879e7 100644 --- a/usr/src/uts/common/sys/rctl_impl.h +++ b/usr/src/uts/common/sys/rctl_impl.h @@ -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 "C" { 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 @@ typedef struct rctl_opaque { 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 diff --git a/usr/src/uts/common/sys/task.h b/usr/src/uts/common/sys/task.h index f009b5e5a7..87cc94cbd0 100644 --- a/usr/src/uts/common/sys/task.h +++ b/usr/src/uts/common/sys/task.h @@ -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 @@ extern "C" { #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 diff --git a/usr/src/uts/common/syscall/rctlsys.c b/usr/src/uts/common/syscall/rctlsys.c index 03617b5d44..b82f4b0566 100644 --- a/usr/src/uts/common/syscall/rctlsys.c +++ b/usr/src/uts/common/syscall/rctlsys.c @@ -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 @@ rctlsys_ctl(char *name, rctl_opaque_t *rblk, int flags) 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 @@ rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags) * 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)); |