changeset 9799:641e52717cb5

PSARC 2007/072 PRIV_AWARE_RESET 6452447 Need the ability to limit each and every privilege on login
author Casper H.S. Dik <Casper.Dik@Sun.COM>
date Fri, 05 Jun 2009 09:55:17 +0200
parents c54abbfdeb61
children cdd8f85c3102
files usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/popen.c usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/privs.c usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm usr/src/cmd/ptools/ppriv/ppriv.c usr/src/cmd/truss/print.c usr/src/lib/pam_modules/unix_cred/unix_cred.c usr/src/uts/common/os/priv.c usr/src/uts/common/sys/priv.h usr/src/uts/common/syscall/ppriv.c usr/src/uts/common/syscall/uid.c
diffstat 10 files changed, 154 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/popen.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/popen.c	Fri Jun 05 09:55:17 2009 +0200
@@ -1,10 +1,8 @@
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /****************************************************************************    
   Copyright (c) 1999,2000 WU-FTPD Development Group.  
   All rights reserved.
@@ -198,11 +196,10 @@
 	/* begin CERT suggested fixes */
 	close(0);
 	i = geteuid();
-	delay_signaling();	/* we can't allow any signals while euid==0: kinch */
-	seteuid(0);
+	setid_priv_on(0);
 	setgid(getegid());
 	setuid(i);
-	enable_signaling();	/* we can allow signals once again: kinch */
+	setid_priv_off(i);
 	/* end CERT suggested fixes */
 	execv(gargv[0], gargv);
 	perror(gargv[0]);
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/privs.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/privs.c	Fri Jun 05 09:55:17 2009 +0200
@@ -1,10 +1,8 @@
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Least privilege support functions.
  */
@@ -24,17 +22,8 @@
 #include "proto.h"
 
 #ifdef SOLARIS_PRIVS
-/*
- * Before becoming privilege aware in init_privs(), no explicit privilege
- * manipulation using priv_on()/priv_off() is necessary as seteuid(0) sets
- * the effective privilege set to the limit set. Thus these are all
- * initialized to TRUE.
- */
-static boolean_t got_setid_priv = B_TRUE;
-static boolean_t got_privaddr_priv = B_TRUE;
-static boolean_t got_read_priv = B_TRUE;
-static boolean_t got_search_priv = B_TRUE;
-static boolean_t got_chown_priv = B_TRUE;
+/* When ununitialized, this indicates we still have all privs */
+static priv_set_t *uprivs;
 #endif /* SOLARIS_PRIVS */
 
 #ifdef SOLARIS_PRIVS
@@ -55,20 +44,20 @@
 }
 #endif /* PRIVS_DEBUG */
 
-static void priv_on(const char *priv, boolean_t already_have)
+static void priv_on(const char *priv)
 {
     /* no need to add the privilege if already have it */
-    if (already_have)
+    if (uprivs == NULL || priv_ismember(uprivs, priv))
 	return;
 
     if (priv_set(PRIV_ON, PRIV_EFFECTIVE, priv, NULL) == -1)
 	syslog(LOG_ERR, "priv_set: error adding privilege %s: %m", priv);
 }
 
-static void priv_off(const char *priv, boolean_t already_had)
+static void priv_off(const char *priv)
 {
     /* don't remove the privilege if already had it */
-    if (already_had)
+    if (uprivs == NULL || priv_ismember(uprivs, priv))
 	return;
 
     if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, priv, NULL) == -1)
@@ -85,52 +74,64 @@
 {
 #ifdef SOLARIS_PRIVS
     uid_t euid = geteuid();
-    priv_set_t *privset;
+    priv_set_t *pset1, *pset2;
 
     /*
-     * The FTP server runs with "basic" inheritable privileges, which are
-     * reset in pam_setcred() for non anonymous users. The seteuid() call in
-     * pass() sets the effective privileges to the inheritable privileges.
+     * The FTP server runs with the inheritable set and the limit set
+     * filled in through user_attr (or with default values of basic and all).
+     * The privileges available to the user at login, is an intersection
+     * of both those sets.  The only way to limit the root user is by
+     * changing the limit set, not by changing the I set.
      */
-    if ((privset = priv_allocset()) == NULL) {
-	syslog(LOG_ERR, "priv_allocset failed: %m");
+    if ((pset1 = priv_allocset()) == NULL ||
+	(uprivs = priv_allocset()) == NULL ||
+	(pset2 = priv_allocset()) == NULL) {
+	    syslog(LOG_ERR, "priv_allocset failed: %m");
+	    dologout(1);
+    }
+    if (getppriv(PRIV_LIMIT, pset1) == -1) {
+	syslog(LOG_ERR, "getppriv(limit) failed: %m");
 	dologout(1);
     }
-    if (getppriv(PRIV_EFFECTIVE, privset) == -1) {
-	syslog(LOG_ERR, "getppriv(effective) failed: %m");
+    if (getppriv(euid == 0 ? PRIV_PERMITTED : PRIV_INHERITABLE, pset2) == -1) {
+	syslog(LOG_ERR, "getppriv() failed: %m");
 	dologout(1);
     }
 
+    /* Compute the permitted set after login. */
+    priv_intersect(pset2, pset1);
+
     /*
-     * Set the permitted privilege set to the effective privileges plus
+     * Set the permitted privilege set to the allowable privileges plus
      * those required after init_privs() is called. Keep note of which
-     * effective privileges we already had so we don't turn them off.
+     * effective privileges we already had in uprivs so we don't turn
+     * them off.
      */
-    if (!priv_ismember(privset, PRIV_PROC_SETID)) {
-	got_setid_priv = B_FALSE;
-	(void) priv_addset(privset, PRIV_PROC_SETID);
-    }
-    if (!priv_ismember(privset, PRIV_NET_PRIVADDR)) {
-	got_privaddr_priv = B_FALSE;
-	(void) priv_addset(privset, PRIV_NET_PRIVADDR);
+    priv_emptyset(pset2);
+    (void) priv_addset(pset2, PRIV_PROC_SETID);
+    (void) priv_addset(pset2, PRIV_NET_PRIVADDR);
+    (void) priv_addset(pset2, PRIV_FILE_DAC_READ);
+    (void) priv_addset(pset2, PRIV_FILE_DAC_SEARCH);
+    (void) priv_addset(pset2, PRIV_FILE_CHOWN);
+
+    priv_copyset(pset2, uprivs);
+    priv_intersect(pset1, uprivs);
+
+    /* Now, set the effective privileges. */
+    if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pset1) == -1) {
+	syslog(LOG_ERR,
+	    "unable to set privileges for %s: setppriv(effective): %m",
+	    username);
+	dologout(1);
     }
-    if (!priv_ismember(privset, PRIV_FILE_DAC_READ)) {
-	got_read_priv = B_FALSE;
-	(void) priv_addset(privset, PRIV_FILE_DAC_READ);
-    }
-    if (!priv_ismember(privset, PRIV_FILE_DAC_SEARCH)) {
-	got_search_priv = B_FALSE;
-	(void) priv_addset(privset, PRIV_FILE_DAC_SEARCH);
-    }
-    if (!priv_ismember(privset, PRIV_FILE_CHOWN)) {
-	got_chown_priv = B_FALSE;
-	(void) priv_addset(privset, PRIV_FILE_CHOWN);
-    }
+
 #if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT)
     /* needed for audit_ftpd_logout() */
-    (void) priv_addset(privset, PRIV_PROC_AUDIT);
+    (void) priv_addset(pset1, PRIV_PROC_AUDIT);
 #endif
-    if (setppriv(PRIV_SET, PRIV_PERMITTED, privset) == -1) {
+    /* And set the permitted, adding ftpd's required privileges in the mix. */
+    priv_union(pset2, pset1);
+    if (setppriv(PRIV_SET, PRIV_PERMITTED, pset1) == -1) {
 	syslog(LOG_ERR,
 	    "unable to set privileges for %s: setppriv(permitted): %m",
 	    username);
@@ -140,8 +141,8 @@
      * setppriv() has made us privilege aware, so the effective privileges
      * are no longer modified by user ID changes.
      */
-
-    priv_freeset(privset);
+    priv_freeset(pset1);
+    priv_freeset(pset2);
 
     /* set the real, effective and saved group ID's */
     setid_priv_on(0);
@@ -181,7 +182,7 @@
 {
     delay_signaling();
 #ifdef SOLARIS_PRIVS
-    priv_on(PRIV_NET_PRIVADDR, got_privaddr_priv);
+    priv_on(PRIV_NET_PRIVADDR);
 #else
     (void) seteuid(uid);
 #endif
@@ -191,7 +192,7 @@
 void port_priv_off(uid_t uid)
 {
 #ifdef SOLARIS_PRIVS
-    priv_off(PRIV_NET_PRIVADDR, got_privaddr_priv);
+    priv_off(PRIV_NET_PRIVADDR);
 #else
     (void) seteuid(uid);
 #endif
@@ -203,8 +204,8 @@
 {
     delay_signaling();
 #ifdef SOLARIS_PRIVS
-    priv_on(PRIV_FILE_DAC_READ, got_read_priv);
-    priv_on(PRIV_FILE_DAC_SEARCH, got_search_priv);
+    priv_on(PRIV_FILE_DAC_READ);
+    priv_on(PRIV_FILE_DAC_SEARCH);
 #endif
     /* necessary on Solaris for access over NFS */
     (void) seteuid(uid);
@@ -213,8 +214,8 @@
 void access_priv_off(uid_t uid)
 {
 #ifdef SOLARIS_PRIVS
-    priv_off(PRIV_FILE_DAC_READ, got_read_priv);
-    priv_off(PRIV_FILE_DAC_SEARCH, got_search_priv);
+    priv_off(PRIV_FILE_DAC_READ);
+    priv_off(PRIV_FILE_DAC_SEARCH);
 #endif
     (void) seteuid(uid);
     enable_signaling();
@@ -226,7 +227,7 @@
 {
     delay_signaling();
 #ifdef SOLARIS_PRIVS
-    priv_on(PRIV_PROC_SETID, got_setid_priv);
+    priv_on(PRIV_PROC_SETID);
 #else
     (void) seteuid(uid);
 #endif
@@ -236,7 +237,7 @@
 void setid_priv_off(uid_t uid)
 {
 #ifdef SOLARIS_PRIVS
-    priv_off(PRIV_PROC_SETID, got_setid_priv);
+    priv_off(PRIV_PROC_SETID);
 #else
     (void) seteuid(uid);
 #endif
@@ -248,7 +249,7 @@
 {
     delay_signaling();
 #ifdef SOLARIS_PRIVS
-    priv_on(PRIV_FILE_CHOWN, got_chown_priv);
+    priv_on(PRIV_FILE_CHOWN);
 #endif
     /* necessary on Solaris for chown over NFS */
     (void) seteuid(uid);
@@ -257,7 +258,7 @@
 void chown_priv_off(uid_t uid)
 {
 #ifdef SOLARIS_PRIVS
-    priv_off(PRIV_FILE_CHOWN, got_chown_priv);
+    priv_off(PRIV_FILE_CHOWN);
 #endif
     (void) seteuid(uid);
     enable_signaling();
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm	Fri Jun 05 09:55:17 2009 +0200
@@ -19,7 +19,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -40,7 +40,7 @@
 
 our (@EXPORT_OK, %EXPORT_TAGS);
 my @constants = qw(PRIV_STR_SHORT PRIV_STR_LIT PRIV_STR_PORT PRIV_ON PRIV_OFF
-	PRIV_SET PRIV_AWARE PRIV_DEBUG);
+	PRIV_SET PRIV_AWARE PRIV_AWARE_RESET PRIV_DEBUG);
 my @syscalls = qw(setppriv getppriv setpflags getpflags);
 my @libcalls = qw(priv_addset priv_copyset priv_delset
     priv_emptyset priv_fillset priv_intersect priv_inverse priv_ineffect
--- a/usr/src/cmd/ptools/ppriv/ppriv.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/cmd/ptools/ppriv/ppriv.c	Fri Jun 05 09:55:17 2009 +0200
@@ -19,14 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Program to examine or set process privileges.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdio_ext.h>
 #include <stdlib.h>
@@ -649,6 +647,7 @@
 	{ PRIV_DEBUG, "PRIV_DEBUG" },
 	{ PRIV_AWARE, "PRIV_AWARE" },
 	{ PRIV_AWARE_INHERIT, "PRIV_AWARE_INHERIT" },
+	{ PRIV_AWARE_RESET, "PRIV_AWARE_RESET" },
 	{ PRIV_XPOLICY, "PRIV_XPOLICY" },
 	{ NET_MAC_AWARE, "NET_MAC_AWARE" },
 	{ NET_MAC_AWARE_INHERIT, "NET_MAC_AWARE_INHERIT" },
--- a/usr/src/cmd/truss/print.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/cmd/truss/print.c	Fri Jun 05 09:55:17 2009 +0200
@@ -2275,6 +2275,7 @@
 		case PRIV_DEBUG:	s = "PRIV_DEBUG";	break;
 		case PRIV_AWARE:	s = "PRIV_AWARE";	break;
 		case PRIV_XPOLICY:	s = "PRIV_XPOLICY";	break;
+		case PRIV_AWARE_RESET:  s = "PRIV_AWARE_RESET"; break;
 		case NET_MAC_AWARE:	s =  "NET_MAC_AWARE";	break;
 		case NET_MAC_AWARE_INHERIT:
 			s = "NET_MAC_AWARE_INHERIT";
--- a/usr/src/lib/pam_modules/unix_cred/unix_cred.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/lib/pam_modules/unix_cred/unix_cred.c	Fri Jun 05 09:55:17 2009 +0200
@@ -596,18 +596,23 @@
 		}
 		if (!priv_issubset(lim, tset))
 			priv_intersect(tset, lim);
-		/*
-		 * In order not to suprise certain applications, we
-		 * need to retain privilege awareness and thus we must
-		 * also set P and E.
-		 */
-		if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0 ||
-		    setppriv(PRIV_SET, PRIV_PERMITTED, lim) != 0) {
+		if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0) {
 			syslog(LOG_AUTH | LOG_ERR,
 			    "pam_setcred: setppriv(limitpriv) failed: %m");
 			ret = PAM_CRED_ERR;
+			goto out;
 		}
+		/*
+		 * In order not to surprise certain applications, we
+		 * need to get rid of privilege awareness and thus we must
+		 * set this flag which will cause a reset on set*uid().
+		 */
+		(void) setpflags(PRIV_AWARE_RESET, 1);
 	}
+	/*
+	 * This may fail but we do not care as this will be reset later
+	 * when the uids are set to their final values.
+	 */
 	(void) setpflags(PRIV_AWARE, 0);
 
 out:
--- a/usr/src/uts/common/os/priv.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/uts/common/os/priv.c	Fri Jun 05 09:55:17 2009 +0200
@@ -614,18 +614,19 @@
 }
 
 /*
- * Set the privilege aware bit, adding L to E/P if
- * necessasry.
+ * Set the privilege aware bit, adding L to E/P if necessary.
+ * Each time we set it, we also clear PRIV_AWARE_RESET.
  */
 void
 priv_set_PA(cred_t *cr)
 {
 	ASSERT(cr->cr_ref <= 2);
 
-	if (CR_FLAGS(cr) & PRIV_AWARE)
+	if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) == PRIV_AWARE)
 		return;
 
 	CR_FLAGS(cr) |= PRIV_AWARE;
+	CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 
 	if (cr->cr_uid == 0)
 		priv_union(&CR_LPRIV(cr), &CR_EPRIV(cr));
@@ -661,8 +662,10 @@
 	ASSERT(cr->cr_ref <= 2);
 
 	if (!(CR_FLAGS(cr) & PRIV_AWARE) ||
-	    !priv_can_clear_PA(cr))
+	    !priv_can_clear_PA(cr)) {
+		CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
 		return;
+	}
 
 	if (CR_FLAGS(cr) & PRIV_AWARE_INHERIT)
 		return;
@@ -679,5 +682,50 @@
 		priv_intersect(&CR_IPRIV(cr), &CR_PPRIV(cr));
 	}
 
-	CR_FLAGS(cr) &= ~PRIV_AWARE;
+	CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
 }
+
+/*
+ * Reset privilege aware bit if so requested by setting the PRIV_AWARE_RESET
+ * flag.
+ */
+void
+priv_reset_PA(cred_t *cr, boolean_t finalize)
+{
+	ASSERT(cr->cr_ref <= 2);
+
+	if ((CR_FLAGS(cr) & (PRIV_AWARE|PRIV_AWARE_RESET)) !=
+	    (PRIV_AWARE|PRIV_AWARE_RESET)) {
+		CR_FLAGS(cr) &= ~PRIV_AWARE_RESET;
+		return;
+	}
+
+	/*
+	 * When PRIV_AWARE_RESET is enabled, any change of uids causes
+	 * a change to the P and E sets.  Bracketing with
+	 * seteuid(0) ... seteuid(uid)/setreuid(-1, 0) .. setreuid(-1, uid)
+	 * will cause the privilege sets "do the right thing.".
+	 * When the change of the uid is "final", e.g., by using setuid(uid),
+	 * or setreuid(uid, uid) or when the last set*uid() call causes all
+	 * uids to be the same, we set P and E to I & L, like when you exec.
+	 * We make an exception when all the uids are 0; this is required
+	 * when we login as root as in that particular case we cannot
+	 * make a distinction between seteuid(0) and seteuid(uid).
+	 * We rely on seteuid/setreuid/setuid to tell us with the
+	 * "finalize" argument that we no longer expect new uid changes,
+	 * cf. setreuid(uid, uid) and setuid(uid).
+	 */
+	if (cr->cr_suid == cr->cr_ruid && cr->cr_suid == cr->cr_uid) {
+		if (finalize || cr->cr_uid != 0) {
+			CR_EPRIV(cr) = CR_IPRIV(cr);
+			priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
+			CR_PPRIV(cr) = CR_EPRIV(cr);
+			CR_FLAGS(cr) &= ~(PRIV_AWARE|PRIV_AWARE_RESET);
+		} else {
+			CR_EPRIV(cr) = CR_PPRIV(cr);
+		}
+	} else if (cr->cr_uid != 0 && (cr->cr_ruid == 0 || cr->cr_suid == 0)) {
+		CR_EPRIV(cr) = CR_IPRIV(cr);
+		priv_intersect(&CR_LPRIV(cr), &CR_EPRIV(cr));
+	}
+}
--- a/usr/src/uts/common/sys/priv.h	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/uts/common/sys/priv.h	Fri Jun 05 09:55:17 2009 +0200
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_PRIV_H
 #define	_SYS_PRIV_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* from TSOL 8 */
-
 #include <sys/types.h>
 #include <sys/cred.h>
 #include <sys/priv_names.h>
@@ -137,11 +135,12 @@
 #define	__PROC_PROTECT			0x0008		/* Private */
 #define	NET_MAC_AWARE			0x0010		/* Is MAC aware */
 #define	NET_MAC_AWARE_INHERIT		0x0020		/* Inherit MAC aware */
+#define	PRIV_AWARE_RESET		0x0040		/* Reset on setuid() */
 #define	PRIV_XPOLICY			0x0080		/* Extended policy */
 
 /* user-settable flags: */
 #define	PRIV_USER	(PRIV_DEBUG | NET_MAC_AWARE | NET_MAC_AWARE_INHERIT |\
-			    PRIV_XPOLICY)
+			    PRIV_XPOLICY | PRIV_AWARE_RESET)
 
 /*
  * Header of the privilege info data structure; multiple structures can
@@ -234,6 +233,7 @@
 
 extern void priv_set_PA(cred_t *);
 extern void priv_adjust_PA(cred_t *);
+extern void priv_reset_PA(cred_t *, boolean_t);
 extern boolean_t priv_can_clear_PA(const cred_t *);
 
 extern int setpflags(uint_t, uint_t, cred_t *);
--- a/usr/src/uts/common/syscall/ppriv.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/uts/common/syscall/ppriv.c	Fri Jun 05 09:55:17 2009 +0200
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
@@ -238,7 +236,8 @@
 
 	if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
 	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT &&
-	    flag != __PROC_PROTECT && flag != PRIV_XPOLICY)) {
+	    flag != __PROC_PROTECT && flag != PRIV_XPOLICY &&
+	    flag != PRIV_AWARE_RESET)) {
 		return (EINVAL);
 	}
 
@@ -262,10 +261,13 @@
 
 	newflags = CR_FLAGS(pcr);
 
-	if (val != 0)
+	if (val != 0) {
+		if (flag == PRIV_AWARE)
+			newflags &= ~PRIV_AWARE_RESET;
 		newflags |= flag;
-	else
+	} else {
 		newflags &= ~flag;
+	}
 
 	/* No change */
 	if (CR_FLAGS(pcr) == newflags) {
@@ -342,7 +344,7 @@
 {
 	if (flag != PRIV_DEBUG && flag != PRIV_AWARE &&
 	    flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT &&
-	    flag != PRIV_XPOLICY)
+	    flag != PRIV_XPOLICY && flag != PRIV_AWARE_RESET)
 		return ((uint_t)-1);
 
 	return ((CR_FLAGS(cr) & flag) != 0);
--- a/usr/src/uts/common/syscall/uid.c	Fri Jun 05 09:44:41 2009 +0200
+++ b/usr/src/uts/common/syscall/uid.c	Fri Jun 05 09:55:17 2009 +0200
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -27,8 +27,6 @@
  * 	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
@@ -136,6 +134,9 @@
 		newcr->cr_suid = uid;
 		newcr->cr_uid = uid;
 		crsetsid(newcr, ksp, KSID_USER);
+
+		priv_reset_PA(newcr, B_TRUE);
+
 		ASSERT(uid != oldruid ? uidchge : 1);
 		mutex_exit(&p->p_crlock);
 	} else {
@@ -230,6 +231,7 @@
 		p->p_cred = newcr;
 		newcr->cr_uid = uid;
 		crsetsid(newcr, ksp, KSID_USER);
+		priv_reset_PA(newcr, B_FALSE);
 		mutex_exit(&p->p_crlock);
 		if (do_nocd) {
 			mutex_enter(&p->p_lock);
@@ -364,6 +366,7 @@
 		    cr->cr_suid != newcr->cr_suid))
 			do_nocd = 1;
 
+		priv_reset_PA(newcr, ruid != -1 && euid != -1 && ruid == euid);
 		crfree(cr);
 	}
 	mutex_exit(&p->p_crlock);