PSARC 2009/686 Improving the use and debugging of the basic privilege set.
authorCasper H.S. Dik <Casper.Dik@Sun.COM>
Mon, 18 Jan 2010 11:49:54 +0100
changeset 11537 8eca52188202
parent 11536 4c36e6a8710f
child 11538 887ee1196411
PSARC 2009/686 Improving the use and debugging of the basic privilege set. PSARC/2009/685 Basic Network Privilege 6434380 Expanding the basic privilege set in order to restrict network access and IPC 6912229 Multiple applications mishandle privilege operations, particular they ignore the basic set 6915243 dladm mishandles basic privileges 6915244 in.tftpd mishandles privileges operations 6915250 NDMP mishandles basic privileges 6915257 smbd mishandles basic privileges 6915277 login audit mishandles basic privileges 6915284 su audit mishandles basic privileges 6915778 lpd-port mishandles basic privileges 6915782 zlogin mishandles basic privileges
usr/src/cmd/cmd-inet/lib/nwamd/main.c
usr/src/cmd/cmd-inet/usr.sbin/in.tftpd.c
usr/src/cmd/dlmgmtd/dlmgmt_main.c
usr/src/cmd/login/login_audit.c
usr/src/cmd/ndmpd/ndmp/ndmpd_main.c
usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c
usr/src/cmd/smbsrv/smbd/smbd_main.c
usr/src/cmd/su/su.c
usr/src/cmd/zlogin/zlogin.c
usr/src/head/priv.h
usr/src/lib/libc/port/gen/privlib.c
usr/src/lib/libc/port/mapfile-vers
usr/src/lib/libnsl/nss/getipnodeby.c
usr/src/lib/print/libpapi-lpd/common/lpd-port.c
usr/src/pkgdefs/common_files/i.devpolicy
usr/src/uts/common/inet/sockmods/socksctp.c
usr/src/uts/common/inet/sockmods/socksdp.c
usr/src/uts/common/inet/tcp/tcp.c
usr/src/uts/common/inet/udp/udp.c
usr/src/uts/common/os/exec.c
usr/src/uts/common/os/policy.c
usr/src/uts/common/os/priv.c
usr/src/uts/common/os/priv_defs
usr/src/uts/common/sys/policy.h
usr/src/uts/common/sys/priv.h
usr/src/uts/common/syscall/ppriv.c
--- a/usr/src/cmd/cmd-inet/lib/nwamd/main.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/main.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -316,14 +316,9 @@
 		dprintf("started with privs %s", p != NULL ? p : "Unknown");
 		free(p);
 	}
-	priv_freeset(priv_set);
 
 	/* always start with the basic set */
-	priv_set = priv_str_to_set("basic", ",", NULL);
-	if (priv_set == NULL) {
-		syslog(LOG_ERR, "converting basic privilege set: %m");
-		exit(EXIT_FAILURE);
-	}
+	priv_basicset(priv_set);
 	(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
 	(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
 	(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.tftpd.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.tftpd.c	Mon Jan 18 11:49:54 2010 +0100
@@ -18,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -194,19 +194,17 @@
 		gid_nobody = pwd->pw_gid;
 	}
 
-	(void) __init_daemon_priv(
-	    PU_LIMITPRIVS,
-	    uid_nobody, gid_nobody,
-	    PRIV_PROC_FORK, PRIV_PROC_CHROOT, PRIV_NET_PRIVADDR, NULL);
+	/* Tftp will not start new executables; clear the limit set.  */
+	(void) __init_daemon_priv(PU_CLEARLIMITSET, uid_nobody, gid_nobody,
+	    PRIV_PROC_CHROOT, PRIV_NET_PRIVADDR, NULL);
 
-	/*
-	 *  Limit set is still "all."  Trim it down to just what we need:
-	 *  fork and chroot.
-	 */
-	(void) priv_set(PRIV_SET, PRIV_ALLSETS,
-	    PRIV_PROC_FORK, PRIV_PROC_CHROOT, PRIV_NET_PRIVADDR, NULL);
-	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
-	(void) priv_set(PRIV_SET, PRIV_INHERITABLE, NULL);
+	/* Remove the unneeded basic privileges everywhere. */
+	(void) priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_PROC_EXEC,
+	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_PROC_SESSION, NULL);
+
+	/* Remove the other privileges from E until we need them. */
+	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_CHROOT,
+	    PRIV_NET_PRIVADDR, NULL);
 
 	while ((c = getopt(argc, argv, "dspST:")) != EOF)
 		switch (c) {
@@ -272,14 +270,15 @@
 		sin6_ptr->sin6_port = htons(IPPORT_TFTP);
 
 		/* Enable privilege as tftp port is < 1024 */
-		(void) priv_set(PRIV_SET,
+		(void) priv_set(PRIV_ON,
 		    PRIV_EFFECTIVE, PRIV_NET_PRIVADDR, NULL);
 		if (bind(reqsock, (struct sockaddr *)&client,
 		    clientlen) == -1) {
 			perror("bind");
 			exit(1);
 		}
-		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_PRIVADDR,
+		    NULL);
 
 		if (debug)
 			(void) puts("running in standalone mode...");
@@ -296,15 +295,14 @@
 
 	(void) chdir(homedir);
 
-	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 	if ((child = fork()) < 0) {
 		syslog(LOG_ERR, "fork (main): %m");
 		exit(1);
 	}
-	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 
 	if (child == 0) {
-		(void) priv_set(PRIV_SET, PRIV_ALLSETS, NULL);
 		delayed_responder();
 	} /* child */
 
@@ -809,17 +807,17 @@
 	 * new socket as that requires library access to system files
 	 * and devices.
 	 */
-	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 	switch (fork()) {
 	case -1:
 		syslog(LOG_ERR, "fork (tftp): %m");
-		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 		return;
 	case 0:
-		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 		break;
 	default:
-		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
 		return;
 	}
 
@@ -829,8 +827,8 @@
 	 * the chroot() call.  We only want to execute the chroot()  once.
 	 */
 	if (securetftp && firsttime) {
-		(void) priv_set(
-		    PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_CHROOT, NULL);
+		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_CHROOT,
+		    NULL);
 		if (chroot(homedir) == -1) {
 			syslog(LOG_ERR,
 			    "tftpd: cannot chroot to directory %s: %m\n",
@@ -841,10 +839,12 @@
 		{
 			firsttime = B_FALSE;
 		}
-		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_CHROOT,
+		    NULL);
 		(void) chdir("/");  /* cd to  new root */
 	}
-	(void) priv_set(PRIV_SET, PRIV_ALLSETS, NULL);
+	(void) priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_PROC_CHROOT,
+	    PRIV_NET_PRIVADDR, NULL);
 
 	ecode = (*pf->f_validate)(tp->th_opcode);
 	if (ecode != 0)
--- a/usr/src/cmd/dlmgmtd/dlmgmt_main.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/dlmgmtd/dlmgmt_main.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -379,18 +379,22 @@
 	 * sysevents, and PRIV_SYS_DL_CONFIG to initialize link properties in
 	 * dlmgmt_upcall_linkprop_init().
 	 *
-	 * We remove all privileges from the permitted (and thus effective)
-	 * set in the non-global zone.  When executing in a non-global zone,
-	 * dlmgmtd only needs to read and write to files that it already owns.
+	 * We remove non-basic privileges from the permitted (and thus
+	 * effective) set.  When executing in a non-global zone, dlmgmtd
+	 * only needs to read and write to files that it already owns.
 	 */
-	priv_emptyset(pset);
+	priv_basicset(pset);
+	(void) priv_delset(pset, PRIV_PROC_EXEC);
+	(void) priv_delset(pset, PRIV_PROC_INFO);
+	(void) priv_delset(pset, PRIV_PROC_SESSION);
+	(void) priv_delset(pset, PRIV_FILE_LINK_ANY);
 	if (zoneid == GLOBAL_ZONEID) {
 		ptype = PRIV_EFFECTIVE;
-		if (priv_addset(pset, PRIV_PROC_FORK) == -1 ||
-		    priv_addset(pset, PRIV_SYS_CONFIG) == -1 ||
+		if (priv_addset(pset, PRIV_SYS_CONFIG) == -1 ||
 		    priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1)
 			err = errno;
 	} else {
+		(void) priv_delset(pset, PRIV_PROC_FORK);
 		ptype = PRIV_PERMITTED;
 	}
 	if (err == 0 && setppriv(PRIV_SET, ptype, pset) == -1)
--- a/usr/src/cmd/login/login_audit.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/login/login_audit.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <assert.h>
 #include <priv.h>
 #include <pwd.h>
@@ -132,7 +130,7 @@
 	}
 	if ((priv = priv_allocset())  == NULL) {
 		syslog(LOG_AUTH | LOG_ALERT,
-		    "login audit_logout: could not alloc privs: %m");
+		    "login audit_logout: could not alloc basic privs: %m");
 		adt_free_event(logout);
 		return;
 	}
@@ -177,7 +175,12 @@
 	/*
 	 * Reduce privileges to just those needed.
 	 */
-	priv_emptyset(priv);
+	priv_basicset(priv);
+	(void) priv_delset(priv, PRIV_PROC_EXEC);
+	(void) priv_delset(priv, PRIV_PROC_FORK);
+	(void) priv_delset(priv, PRIV_PROC_INFO);
+	(void) priv_delset(priv, PRIV_PROC_SESSION);
+	(void) priv_delset(priv, PRIV_FILE_LINK_ANY);
 	if ((priv_addset(priv, PRIV_PROC_AUDIT) != 0) ||
 	    (setppriv(PRIV_SET, PRIV_PERMITTED, priv) != 0)) {
 		syslog(LOG_AUTH | LOG_ALERT,
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_main.c	Mon Jan 18 11:49:54 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -120,21 +120,35 @@
 {
 	sigset_t set, oset;
 	pid_t pid;
+	priv_set_t *pset = priv_allocset();
 
 	/*
 	 * Set effective sets privileges to 'least' required. If fails, send
 	 * error messages to log file and proceed.
 	 */
-	if (priv_set(PRIV_SET, PRIV_EFFECTIVE,
-	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, PRIV_PROC_SESSION,
-	    PRIV_PROC_FORK, PRIV_PROC_EXEC,
-	    PRIV_PROC_AUDIT, PRIV_PROC_SETID, PRIV_PROC_OWNER, PRIV_FILE_CHOWN,
-	    PRIV_FILE_CHOWN_SELF, PRIV_FILE_DAC_READ, PRIV_FILE_DAC_SEARCH,
-	    PRIV_FILE_DAC_WRITE, PRIV_FILE_OWNER, PRIV_FILE_SETID,
-	    PRIV_SYS_LINKDIR, PRIV_SYS_DEVICES, PRIV_SYS_MOUNT, PRIV_SYS_CONFIG,
-	    NULL))
-		syslog(LOG_ERR,
-		    "Failed to set least required privileges to the service.");
+	if (pset != NULL) {
+		priv_basicset(pset);
+		(void) priv_addset(pset, PRIV_PROC_AUDIT);
+		(void) priv_addset(pset, PRIV_PROC_SETID);
+		(void) priv_addset(pset, PRIV_PROC_OWNER);
+		(void) priv_addset(pset, PRIV_FILE_CHOWN);
+		(void) priv_addset(pset, PRIV_FILE_CHOWN_SELF);
+		(void) priv_addset(pset, PRIV_FILE_DAC_READ);
+		(void) priv_addset(pset, PRIV_FILE_DAC_SEARCH);
+		(void) priv_addset(pset, PRIV_FILE_DAC_WRITE);
+		(void) priv_addset(pset, PRIV_FILE_OWNER);
+		(void) priv_addset(pset, PRIV_FILE_SETID);
+		(void) priv_addset(pset, PRIV_SYS_LINKDIR);
+		(void) priv_addset(pset, PRIV_SYS_DEVICES);
+		(void) priv_addset(pset, PRIV_SYS_MOUNT);
+		(void) priv_addset(pset, PRIV_SYS_CONFIG);
+	}
+
+	if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) {
+		syslog(LOG_ERR, "Failed to set least required privileges to "
+		    "the service.");
+	}
+	priv_freeset(pset);
 
 	/*
 	 * Block all signals prior to the fork and leave them blocked in the
--- a/usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c	Mon Jan 18 11:49:54 2010 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1911,22 +1911,23 @@
 		NDMP_LOG(LOG_ERR, "Out of memory.");
 		return (-1);
 	}
-	priv_emptyset(priv_set);
-	(void) priv_addset(priv_set, "basic");
-	(void) priv_addset(priv_set, "proc_audit");
-	(void) priv_addset(priv_set, "proc_setid");
-	(void) priv_addset(priv_set, "proc_owner");
-	(void) priv_addset(priv_set, "file_chown");
-	(void) priv_addset(priv_set, "file_chown_self");
-	(void) priv_addset(priv_set, "file_dac_read");
-	(void) priv_addset(priv_set, "file_dac_search");
-	(void) priv_addset(priv_set, "file_dac_write");
-	(void) priv_addset(priv_set, "file_owner");
-	(void) priv_addset(priv_set, "file_setid");
-	(void) priv_addset(priv_set, "sys_linkdir");
-	(void) priv_addset(priv_set, "sys_devices");
-	(void) priv_addset(priv_set, "sys_mount");
-	(void) priv_addset(priv_set, "sys_config");
+
+	priv_basicset(priv_set);
+
+	(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
+	(void) priv_addset(priv_set, PRIV_PROC_SETID);
+	(void) priv_addset(priv_set, PRIV_PROC_OWNER);
+	(void) priv_addset(priv_set, PRIV_FILE_CHOWN);
+	(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
+	(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
+	(void) priv_addset(priv_set, PRIV_FILE_DAC_SEARCH);
+	(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
+	(void) priv_addset(priv_set, PRIV_FILE_OWNER);
+	(void) priv_addset(priv_set, PRIV_FILE_SETID);
+	(void) priv_addset(priv_set, PRIV_SYS_LINKDIR);
+	(void) priv_addset(priv_set, PRIV_SYS_DEVICES);
+	(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
+	(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
 
 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
 		NDMP_LOG(LOG_ERR, "Additional privileges required.");
@@ -1942,10 +1943,13 @@
 {
 	priv_set_t *priv_set;
 
-	if ((priv_set = priv_str_to_set("all", ",", NULL)) == NULL) {
-		NDMP_LOG(LOG_ERR, "Could not set privileges to 'all'.");
+	if ((priv_set = priv_allocset()) == NULL) {
+		NDMP_LOG(LOG_ERR, "Out of memory.");
 		return (-1);
 	}
+
+	priv_fillset(priv_set);
+
 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) != 0) {
 		NDMP_LOG(LOG_ERR, "Additional privileges required.");
 		return (-1);
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -391,7 +391,7 @@
 	if (pset == NULL)
 		return;
 
-	priv_emptyset(pset);
+	priv_basicset(pset);
 
 	/* list of privileges for smbd */
 	(void) priv_addset(pset, PRIV_NET_MAC_AWARE);
--- a/usr/src/cmd/su/su.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/su/su.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -864,7 +864,7 @@
 	}
 	if ((priv = priv_allocset())  == NULL) {
 		syslog(LOG_AUTH | LOG_ALERT,
-		    "su audit_logout: could not alloc privs: %m");
+		    "su audit_logout: could not alloc basic privs: %m");
 		adt_free_event(event);
 		return;
 	}
@@ -907,7 +907,12 @@
 	/*
 	 * Reduce privileges to just those needed.
 	 */
-	priv_emptyset(priv);
+	priv_basicset(priv);
+	(void) priv_delset(priv, PRIV_PROC_EXEC);
+	(void) priv_delset(priv, PRIV_PROC_FORK);
+	(void) priv_delset(priv, PRIV_PROC_INFO);
+	(void) priv_delset(priv, PRIV_PROC_SESSION);
+	(void) priv_delset(priv, PRIV_FILE_LINK_ANY);
 	if ((priv_addset(priv, PRIV_PROC_AUDIT) != 0) ||
 	    (setppriv(PRIV_SET, PRIV_PERMITTED, priv) != 0)) {
 		syslog(LOG_AUTH | LOG_ALERT,
--- a/usr/src/cmd/zlogin/zlogin.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/cmd/zlogin/zlogin.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -190,19 +190,24 @@
 {
 	if ((dropprivs = priv_allocset()) == NULL)
 		return (1);
-	priv_emptyset(dropprivs);
+
+	priv_basicset(dropprivs);
+	(void) priv_delset(dropprivs, PRIV_PROC_INFO);
+	(void) priv_delset(dropprivs, PRIV_PROC_FORK);
+	(void) priv_delset(dropprivs, PRIV_PROC_EXEC);
+	(void) priv_delset(dropprivs, PRIV_FILE_LINK_ANY);
 
 	/*
-	 * We need these privileges in order to query session information and
+	 * We need to keep the basic privilege PROC_SESSION and all unknown
+	 * basic privileges as well as the privileges PROC_ZONE and
+	 * PROC_OWNER in order to query session information and
 	 * send signals.
 	 */
 	if (interactive == 0) {
-		if (priv_addset(dropprivs, "proc_session") == -1)
-			return (1);
-		if (priv_addset(dropprivs, "proc_zone") == -1)
-			return (1);
-		if (priv_addset(dropprivs, "proc_owner") == -1)
-			return (1);
+		(void) priv_addset(dropprivs, PRIV_PROC_ZONE);
+		(void) priv_addset(dropprivs, PRIV_PROC_OWNER);
+	} else {
+		(void) priv_delset(dropprivs, PRIV_PROC_SESSION);
 	}
 
 	return (0);
--- a/usr/src/head/priv.h	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/head/priv.h	Mon Jan 18 11:49:54 2010 +0100
@@ -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,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_PRIV_H_
 #define	_PRIV_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/priv.h>
 
 #ifdef	__cplusplus
@@ -67,6 +64,7 @@
 extern void priv_freeset(priv_set_t *);
 
 extern void priv_emptyset(priv_set_t *);
+extern void priv_basicset(priv_set_t *);
 extern void priv_fillset(priv_set_t *);
 extern boolean_t priv_isemptyset(const priv_set_t *);
 extern boolean_t priv_isfullset(const priv_set_t *);
@@ -104,6 +102,7 @@
 extern void priv_freeset(/* priv_set_t * */);
 
 extern void priv_emptyset(/* priv_set_t * */);
+extern void priv_basicset(/* priv_set_t * */);
 extern void priv_fillset(/* priv_set_t * */);
 extern boolean_t priv_isemptyset(/* const priv_set_t * */);
 extern boolean_t priv_isfullset(/* const priv_set_t * */);
--- a/usr/src/lib/libc/port/gen/privlib.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/lib/libc/port/gen/privlib.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,18 +20,17 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #pragma weak _getprivimplinfo	= getprivimplinfo
 #pragma weak _priv_addset	= priv_addset
 #pragma weak _priv_allocset	= priv_allocset
 #pragma weak _priv_copyset	= priv_copyset
 #pragma weak _priv_delset	= priv_delset
 #pragma weak _priv_emptyset	= priv_emptyset
+#pragma weak _priv_basicset	= priv_basicset
 #pragma weak _priv_fillset	= priv_fillset
 #pragma weak _priv_freeset	= priv_freeset
 #pragma weak _priv_getbyname	= priv_getbyname
@@ -870,6 +869,16 @@
 }
 
 void
+priv_basicset(priv_set_t *set)
+{
+	priv_data_t *d;
+
+	LOADPRIVDATA(d);
+
+	priv_copyset(d->pd_basicset, set);
+}
+
+void
 __priv_fillset(priv_data_t *d, priv_set_t *set)
 {
 	(void) memset(set, ~0, d->pd_setsize);
--- a/usr/src/lib/libc/port/mapfile-vers	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/lib/libc/port/mapfile-vers	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -141,6 +141,7 @@
 	posix_spawn_file_actions_addclosefrom_np;
 	posix_spawnattr_getsigignore_np;
 	posix_spawnattr_setsigignore_np;
+	priv_basicset;
 	pthread_key_create_once_np;
 	pthread_mutexattr_getrobust;
 	pthread_mutexattr_setrobust;
--- a/usr/src/lib/libnsl/nss/getipnodeby.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/lib/libnsl/nss/getipnodeby.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * This file defines and implements the re-entrant getipnodebyname(),
@@ -742,6 +742,12 @@
 	return (*num);
 fail:
 	free(buf);
+	/*
+	 * If the process is running without the NET_ACCESS basic privilege,
+	 * pretend we still have inet/inet6 interfaces.
+	 */
+	if (errno == EACCES)
+		return (1);
 	return (-1);
 }
 
--- a/usr/src/lib/print/libpapi-lpd/common/lpd-port.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-port.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  */
@@ -686,7 +686,7 @@
 	char *host = NULL, *queue = NULL;
 	uid_t uid = getuid();
 #ifdef	PRIV_ALLSETS
-	priv_set_t *saveset = NULL;
+	priv_set_t *saveset;
 #endif
 
 	openlog("lpd-port", LOG_PID, LOG_LPR);
@@ -695,31 +695,34 @@
 
 	/* lose as much as we can perminently and temporarily drop the rest. */
 
-	if ((saveset = priv_str_to_set("PRIV_NET_PRIVADDR,"
-	    "PRIV_FILE_DAC_READ,PRIV_FILE_DAC_WRITE,",
-	    ",", (const char **)NULL)) == NULL) {
-		syslog(LOG_ERR,
-		    "lpd_port: priv_str_to_set saveset failed: %m\n");
+	if ((saveset = priv_allocset()) == NULL) {
+		syslog(LOG_ERR, "lpd_port: priv_allocset saveset failed: %m\n");
 		return (-1);
 	}
 
+	priv_basicset(saveset);
+	(void) priv_addset(saveset, PRIV_NET_PRIVADDR);
+	(void) priv_addset(saveset, PRIV_FILE_DAC_READ);
+	(void) priv_addset(saveset, PRIV_FILE_DAC_WRITE);
+
 	if ((setppriv(PRIV_SET, PRIV_PERMITTED, saveset)) < 0) {
 		syslog(LOG_ERR, "lpd_port:setppriv:priv_set failed: %m");
 		return (-1);
 	}
 
+	priv_freeset(saveset);
+
 	/*
 	 * These privileges permanently dropped in next_job_id() and
 	 * reserved_port()
 	 */
 
-	if ((setppriv(PRIV_OFF, PRIV_EFFECTIVE, saveset)) < 0) {
-		syslog(LOG_ERR, "lpd_port:setppriv:priv_off failed: %m");
+	if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_PRIVADDR,
+	    PRIV_FILE_DAC_READ, PRIV_FILE_DAC_WRITE, (char *)NULL) < 0) {
+		syslog(LOG_ERR, "lpd_port:priv_set:priv_off failed: %m");
 		return (-1);
 	}
 
-	priv_freeset(saveset);
-
 	syslog(LOG_DEBUG, "using privs");
 #else
 
--- a/usr/src/pkgdefs/common_files/i.devpolicy	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/pkgdefs/common_files/i.devpolicy	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #  NOTE:  When a change is made to the source file for
@@ -37,6 +37,10 @@
 	# changes
 	cp $dest $dest.$$
 	sed < $dest.$$ > $dest \
+	    -e '/^sctp6\{0,1\}[ 	]/'d \
+	    -e '/^sdp6\{0,1\}[ 	]/'d \
+	    -e '/^tcp6\{0,1\}[ 	]/'d \
+	    -e '/^udp6\{0,1\}[ 	]/'d \
 	    -e '/md:admin/s/read_priv_set=sys_config/			/' \
 	    -e '/^icmp[ 	]*read_priv_set=net_rawaccess[ 	]*write_priv_set=net_rawaccess$/d' \
 	    -e '/^icmp6[ 	]*read_priv_set=net_rawaccess[ 	]*write_priv_set=net_rawaccess$/d' \
--- a/usr/src/uts/common/inet/sockmods/socksctp.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/inet/sockmods/socksctp.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +37,7 @@
 #include <sys/cmn_err.h>
 #include <sys/sysmacros.h>
 #include <sys/filio.h>
+#include <sys/policy.h>
 
 #include <sys/project.h>
 #include <sys/tihdr.h>
@@ -176,6 +177,7 @@
 	struct sctp_sonode *pss;
 	sctp_sockbuf_limits_t sbl;
 	sock_upcalls_t *upcalls;
+	int err;
 
 	ss = SOTOSSO(so);
 
@@ -206,6 +208,10 @@
 		ASSERT(so->so_type == SOCK_SEQPACKET);
 		upcalls = &sosctp_assoc_upcalls;
 	}
+
+	if ((err = secpolicy_basic_net_access(cr)) != 0)
+		return (err);
+
 	so->so_proto_handle = (sock_lower_handle_t)sctp_create(so, NULL,
 	    so->so_family, so->so_type, SCTP_CAN_BLOCK, upcalls, &sbl, cr);
 	if (so->so_proto_handle == NULL)
--- a/usr/src/uts/common/inet/sockmods/socksdp.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/inet/sockmods/socksdp.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,6 +36,7 @@
 #include <sys/stropts.h>
 #include <sys/cmn_err.h>
 #include <sys/sysmacros.h>
+#include <sys/policy.h>
 
 #include <sys/filio.h>
 #include <sys/sockio.h>
@@ -150,6 +151,9 @@
 		return (0);
 	}
 
+	if ((error = secpolicy_basic_net_access(cr)) != 0)
+		return (error);
+
 	upcalls = &sosdp_sock_upcalls;
 
 	so->so_proto_handle = (sock_lower_handle_t)sdp_create(so, NULL,
--- a/usr/src/uts/common/inet/tcp/tcp.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Mon Jan 18 11:49:54 2010 +0100
@@ -7805,6 +7805,12 @@
 		ASSERT(tcps != NULL);
 	} else {
 		netstack_t *ns;
+		int err;
+
+		if ((err = secpolicy_basic_net_access(credp)) != 0) {
+			*errorp = err;
+			return (NULL);
+		}
 
 		ns = netstack_find_by_cred(credp);
 		ASSERT(ns != NULL);
--- a/usr/src/uts/common/inet/udp/udp.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/inet/udp/udp.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -198,7 +198,7 @@
 static void	udp_ulp_recv(conn_t *, mblk_t *, uint_t, ip_recv_attr_t *);
 
 /* Common routine for TPI and socket module */
-static conn_t	*udp_do_open(cred_t *, boolean_t, int);
+static conn_t	*udp_do_open(cred_t *, boolean_t, int, int *);
 static void	udp_do_close(conn_t *);
 static int	udp_do_bind(conn_t *, struct sockaddr *, socklen_t, cred_t *,
     boolean_t);
@@ -1515,6 +1515,7 @@
 	conn_t		*connp;
 	dev_t		conn_dev;
 	vmem_t		*minor_arena;
+	int		err;
 
 	/* If the stream is already open, return immediately. */
 	if (q->q_ptr != NULL)
@@ -1549,10 +1550,10 @@
 		return (0);
 	}
 
-	connp = udp_do_open(credp, isv6, KM_SLEEP);
+	connp = udp_do_open(credp, isv6, KM_SLEEP, &err);
 	if (connp == NULL) {
 		inet_minor_free(minor_arena, conn_dev);
-		return (ENOMEM);
+		return (err);
 	}
 	udp = connp->conn_udp;
 
@@ -5051,7 +5052,7 @@
  */
 
 static conn_t *
-udp_do_open(cred_t *credp, boolean_t isv6, int flags)
+udp_do_open(cred_t *credp, boolean_t isv6, int flags, int *errorp)
 {
 	udp_t		*udp;
 	conn_t		*connp;
@@ -5060,6 +5061,11 @@
 	udp_stack_t 	*us;
 	int		len;
 
+	ASSERT(errorp != NULL);
+
+	if ((*errorp = secpolicy_basic_net_access(credp)) != 0)
+		return (NULL);
+
 	ns = netstack_find_by_cred(credp);
 	ASSERT(ns != NULL);
 	us = ns->netstack_udp;
@@ -5079,6 +5085,7 @@
 	connp = ipcl_conn_create(IPCL_UDPCONN, flags, ns);
 	if (connp == NULL) {
 		netstack_rele(ns);
+		*errorp = ENOMEM;
 		return (NULL);
 	}
 	udp = connp->conn_udp;
@@ -5183,11 +5190,9 @@
 	else
 		isv6 = B_FALSE;
 
-	connp = udp_do_open(credp, isv6, flags);
-	if (connp == NULL) {
-		*errorp = ENOMEM;
+	connp = udp_do_open(credp, isv6, flags, errorp);
+	if (connp == NULL)
 		return (NULL);
-	}
 
 	udp = connp->conn_udp;
 	ASSERT(udp != NULL);
--- a/usr/src/uts/common/os/exec.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/os/exec.c	Mon Jan 18 11:49:54 2010 +0100
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -731,6 +731,16 @@
 			oldcred = curthread->t_cred;
 			curthread->t_cred = cred;
 			crfree(oldcred);
+
+			if (priv_debug && priv_basic_test >= 0 &&
+			    !PRIV_ISASSERT(&CR_IPRIV(newcred),
+			    priv_basic_test)) {
+				pid_t pid = pp->p_pid;
+				char *fn = PTOU(pp)->u_comm;
+
+				cmn_err(CE_WARN, "%s[%d]: exec: basic_test "
+				    "privilege removed from E/I", fn, pid);
+			}
 		}
 		/*
 		 * On emerging from a successful exec(), the saved
--- a/usr/src/uts/common/os/policy.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/os/policy.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,7 +63,12 @@
  */
 #define	MAXPRIVSTACK		6
 
+#ifdef DEBUG
+int priv_debug = 1;
+#else
 int priv_debug = 0;
+#endif
+int priv_basic_test = -1;
 
 /*
  * This file contains the majority of the policy routines.
@@ -1902,6 +1907,12 @@
 	return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL));
 }
 
+int
+secpolicy_basic_net_access(const cred_t *cr)
+{
+	return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL));
+}
+
 /*
  * Additional device protection.
  *
--- a/usr/src/uts/common/os/priv.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/os/priv.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -88,6 +88,15 @@
 	PRIV_UNSAFE_ASSERT(&priv_unsafe);
 	priv_fillset(&priv_fullset);
 
+	/*
+	 * When booting with priv_debug set, then we'll add an additional
+	 * basic privilege and we verify that it is always present in E.
+	 */
+	if (priv_debug == 1 &&
+	    (priv_basic_test = priv_getbyname("basic_test", PRIV_ALLOC)) >= 0) {
+		priv_addset(priv_basic, priv_basic_test);
+	}
+
 	devpolicy_init();
 }
 
--- a/usr/src/uts/common/os/priv_defs	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/os/priv_defs	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
 INSERT COMMENT
@@ -115,6 +115,11 @@
 	This privilege is interpreted only if the system is configured
 	with Trusted Extensions.
 
+privilege PRIV_FILE_FLAG_SET
+
+	Allows a process to set immutable, nounlink or appendonly
+	file attributes.
+
 basic privilege PRIV_FILE_LINK_ANY
 
 	Allows a process to create hardlinks to files owned by a uid
@@ -152,11 +157,6 @@
 	This privilege is interpreted only if the system is configured
 	with Trusted Extensions.
 
-privilege PRIV_FILE_FLAG_SET
-
-	Allows a process to set immutable, nounlink or appendonly
-	file attributes.
-
 privilege PRIV_GRAPHICS_ACCESS
 
 	Allows a process to make privileged ioctls to graphics devices.
@@ -165,7 +165,7 @@
 	privileged graphics device mappings.
 
 privilege PRIV_GRAPHICS_MAP
-	
+
 	Allows a process to perform privileged mappings through a
 	graphics device.
 
@@ -196,6 +196,10 @@
 	Additional restrictions apply if the owner of the object has uid 0
 	and the effective uid of the current process is not 0.
 
+basic privilege PRIV_NET_ACCESS
+
+	Allows a process to open a TCP, UDP, SDP or SCTP network endpoint.
+
 privilege PRIV_NET_BINDMLP
 
 	Allow a process to bind to a port that is configured as a
@@ -212,7 +216,7 @@
 
 privilege PRIV_NET_MAC_AWARE
 
-	Allows a process to set NET_MAC_AWARE process flag by using 
+	Allows a process to set NET_MAC_AWARE process flag by using
 	setpflags(2). This privilege also allows a process to set
 	SO_MAC_EXEMPT socket option by using setsockopt(3SOCKET).
 	The NET_MAC_AWARE process flag and the SO_MAC_EXEMPT socket
@@ -270,7 +274,7 @@
 	Allows a process to call fork1()/forkall()/vfork()
 
 basic privilege PRIV_PROC_INFO
-	
+
 	Allows a process to examine the status of processes other
 	than those it can send signals to.  Processes which cannot
 	be examined cannot be seen in /proc and appear not to exist.
@@ -353,7 +357,7 @@
 	Allows a process to open devices that have been exclusively opened.
 
 privilege PRIV_SYS_IPC_CONFIG
-	
+
 	Allows a process to increase the size of a System V IPC Message
 	Queue buffer.
 
@@ -368,7 +372,7 @@
 	of snapshots.
 	Allows a process to mount and unmount filesystems which would
 	otherwise be restricted (i.e., most filesystems except
-	namefs). 
+	namefs).
 	A process performing a mount operation needs to have
 	appropriate access to the device being mounted (read-write for
 	"rw" mounts, read for "ro" mounts).
@@ -584,7 +588,7 @@
 	Set of privileges currently in effect.
 
 set PRIV_INHERITABLE
-	
+
 	Set of privileges that comes into effect on exec.
 
 set PRIV_PERMITTED
--- a/usr/src/uts/common/sys/policy.h	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/sys/policy.h	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -171,6 +171,7 @@
 int secpolicy_basic_exec(const cred_t *, vnode_t *);
 int secpolicy_basic_fork(const cred_t *);
 int secpolicy_basic_link(const cred_t *);
+int secpolicy_basic_net_access(const cred_t *);
 int secpolicy_basic_proc(const cred_t *);
 int secpolicy_basic_procinfo(const cred_t *, struct proc *, struct proc *);
 
--- a/usr/src/uts/common/sys/priv.h	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/sys/priv.h	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -198,6 +198,9 @@
 
 #define	PRIV_ALLOC			0x1
 
+extern int priv_debug;
+extern int priv_basic_test;
+
 struct proc;
 struct prpriv;
 struct cred;
--- a/usr/src/uts/common/syscall/ppriv.c	Mon Jan 18 13:03:01 2010 +0530
+++ b/usr/src/uts/common/syscall/ppriv.c	Mon Jan 18 11:49:54 2010 +0100
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,6 +35,7 @@
 #include <sys/policy.h>
 #include <sys/ddi.h>
 #include <sys/thread.h>
+#include <sys/cmn_err.h>
 #include <c2/audit.h>
 
 /*
@@ -181,6 +182,21 @@
 		mutex_exit(&p->p_lock);
 	}
 
+	/*
+	 * The basic_test privilege should not be removed from E;
+	 * if that has happened, then some programmer typically set the E/P to
+	 * empty. That is not portable.
+	 */
+	if ((type == PRIV_EFFECTIVE || type == PRIV_PERMITTED) && priv_debug &&
+	    priv_basic_test >= 0 && !PRIV_ISASSERT(target, priv_basic_test)) {
+		proc_t *p = curproc;
+		pid_t pid = p->p_pid;
+		char *fn = PTOU(p)->u_comm;
+
+		cmn_err(CE_WARN, "%s[%d]: setppriv: basic_test privilege "
+		    "removed from E/P", fn, pid);
+	}
+
 	crset(p, cr);		/* broadcast to process threads */
 
 	return (0);