Trusted Solaris Developer's Guide

Chapter 3 Privileges

Privileges organize security-related powers into discrete pieces where each piece (or privilege) maps to a single security-related task. Privileges enable a program to perform specific tasks normally prohibited by the system security policy. Prohibited tasks are such things as accessing a file or directory to which the program does not have the appropriate mandatory or discretionary access.

A program turns on (makes effective) one or more privileges to perform one security-related task. For example, if the program does not have mandatory write access to a file, it turns on the file_mac_write privilege. If the program does not have discretionary write access either, it also turns on the file_dac_write privilege. However, if the program has both mandatory and discretionary write access, it needs no privileges. Most programs do not use privileges because they operate within the bounds of the system security policy.

This chapter describes the programming interfaces for handling privileges.

Types of Privileges

The Trusted Solaris environment allows up to 128 different privileges. The total includes the following types of Trusted Solaris privileges and site-defined privileges. See priv_desc(4) for a description of the Trusted Solaris privileges.

Privilege Sets

Privileges are organized into file privilege sets and process privilege sets.

File Privilege Sets

Executable files, interpreted files, and CDE actions have file privilege sets assigned through the File Manager, with setfpriv(1), or by another privileged program. The file privilege sets are the forced set and the allowed set.

Allowed Set

The allowed set contains the privileges that will be assigned to the executable file (forced file set) or inherited and used by the executing process. When a process inherits a privilege from another process, it cannot use that privilege unless the privilege is in the allowed set of its executable file.

Allowed privileges provide Trojan horse protection because they protect against an untrusted process entering the system and inheriting privileges from another process. See "Inheritable Set" for more information on inheriting privileges.

Forced Set

The forced set contains the privileges a program must have when it begins execution for security-related tasks performed by any user. Commands with forced privileges can be invoked from any shell, and CDE actions with forced privileges can be invoked from any workspace. The forced set must always be equal to or a subset of the allowed set, and so, every privilege in the forced set is also in the allowed set.

Interpreted Files

Interpreted files are scripts that begin with #! and go through an interpreter to be executed. The script file can have forced and allowed privilege sets and the interpreter can have forced and allowed privilege sets. The final forced set is the combination of the forced set assigned to the script and the forced set assigned to the interpreter restricted by the allowed set of the interpreter. The allowed set of the script does not restrict the final forced set.

Process Privilege Sets

Executing processes have process privilege sets computed from algorithms based on the contents of the file sets and any privileges inherited from the calling process. The process privilege sets are the inheritable, saved, permitted, and effective sets.

Inheritable Set

The inheritable set contains the privileges (if any) received from the parent process. A process passes its inheritable set to a new program during an exec(1) or a new process during a fork(2). The inheritable set of the new program or process always equals the inheritable set of the calling process. The new process or program can use only those inherited privileges that are also in the allowed set of its executable file, but passes all inheritable privileges to a new program or process. A program can clear its inheritable set and add any privileges in its permitted set to the inheritable set prior to a fork() or exec().

The system administrator can assign an inheritable set to a CDE action or command in an execution profile. The privileges are inherited when the user or role to which the execution profile is assigned starts the CDE action or executes a command from the profile shell.


Note -

If a forced privilege is in the process's permitted set, that process can set the forced privilege in its own inheritable set and pass the forced privilege to a new process or program.


Saved Set

The saved set is a copy of the inherited privileges the process is allowed to use. The saved set equals the inheritable set restricted by the allowed set. Those privileges in the inheritable set also in the allowed set are put in the saved set. There are no interfaces for changing the saved set.

A program can query its saved set to determine the origination of a privilege. If the privilege is in the saved set, it is inherited for the current program invocation. If the privilege is not in the saved set, it is forced for the current program invocation.

A process may take a more limited (workstation-wide) action on a security-related task when started by a normal user (forced privilege), and a wider (network-wide) action on the same security-related task when started by an authorized user in an administrative role (inherited privilege).

Permitted Set

The permitted set contains the forced and inherited privileges a process can use. The permitted set is the forced set plus the inheritable set restricted by the allowed set. Those privileges in the inheritable set also in the allowed set are combined with the forced set and placed in the permitted set. A privileged process is a process with a permitted set not equal to zero.

Privileges can be removed from the permitted set, but not added. Once a permitted privilege is removed, it cannot be added back, it cannot be added to the inheritable set, and is removed from the inheritable set if it was added to the inheritable set prior to being removed from the permitted set.

As a security precaution, you can remove the privileges from the permitted set the program never uses. This way a program can never make use of an allowed privilege incorrectly assigned to its executable file or accidentally inherited.

Effective Set

Effective privileges are those permitted privileges a process uses for a single security-related task. By default, the effective set is initially equal to the permitted set, but a program should turn the effective set off at the beginning of execution to prepare for privilege bracketing.

Privilege bracketing is the practice of turning the effective privilege set off, then turning on (making effective) only those privileges needed for a specific security-related task, and turning them off as soon as they are no longer needed. See "Bracketing Effective Privileges".

Change in User ID

Privilege-unaware programs change their UIDs either to gain or give up rights associated with the new UID. To simulate that action in a privilege-based system rather than a UID-based system, the effective and saved privilege sets are modified across setuid calls. If the setuid(2), setreuid(2), or seteuid(2) system call is called, the effective privilege set is copied to the saved set and the effective set is cleared. If you need the effective set, copy it back from the saved set or turn the effective privileges you need back on. If you need the original saved set (to determine the origination of a privilege), do the tests first or make a copy of the saved set.

The effective set is cleared based on the principle that a process cannot use privileges granted to the original caller while the user ID is changed. A setuid program can still manipulate privileges from the permitted set by putting them into the effective set. When a set UID program changes from its saved UID ID to the calling user ID, it gives up its privilege. When it changes back to the saved UID ID, it regains privilege.

Since set UID programs may not be aware of privileges, their privilege bracketing (see "Use Privilege Bracketing") is tracked in the privilege sets.

Types of Privileged Applications

All privileged applications are part of the Trusted Computing Base (TCB). Some privileged applications have one or more forced privileges and might or might not inherit privileges. These applications are the Trusted Solaris equivalent of setuid applications in standard UNIX systems.

Other privileged applications have no forced privileges and always inherit privileges from the calling process. These applications are always called by a privileged process.

Privilege Names and Descriptions

The priv_desc(4) man page lists privilege names, manifest constant names, and description text for all system privileges.

Privileged Operations

The system calls that get and set file privilege sets require mandatory access and discretionary access to the file and may require privilege if access is denied. See the fgetfpriv(2) man page for specific details.

Setting File Privilege Sets

The file_setpriv privilege is required to set file privilege sets with the setfpriv(1) and fsetfpriv(2) system calls.

Keeping File Privilege Sets on an Executable File

When a process writes information to an executable file, the file_setpriv privilege is needed to prevent the file's forced and allowed privilege sets being set to none.

Core Files

The proc_dumpcore privilege must be effective for a privileged process to create a core file because the core file from a privileged process is likely to contain sensitive information. If this privilege is not effective, the process will not create a core file when it dies. For debugging purposes (only), you could make this privilege effective at the beginning of execution and leave it effective until the process dies.

Setting IDs

The calling process needs the proc_setid privilege in its effective set to change its user ID, group ID, or supplemental group ID.

Privilege Guidelines

Privileged applications should be developed in an isolated, protected environment separate from an operational Trusted Solaris system. Unfinished privileged applications are inherently untrustworthy and should not have an opportunity to compromise the security of a functioning system. The following additional practices are recommended for all privileged applications.

See Appendix B, Trusted Solaris Interfaces Reference for information on secure application packaging.

Use Privilege Bracketing

When an application uses privilege, system security policy is being breached. Privileged tasks should be bracketed and carefully controlled to ensure that sensitive information is not compromised. See "Bracketing Effective Privileges" for information on how to bracket privileges.

Avoid Shell Escapes

Shell escapes in an application can enable an end user to violate trust. For example, some mail applications interpret the !command line as a command and execute it. If a mail application is a trusted process, it runs with privileges. The end user can use this feature to create a script to take advantage of the mail application privileges. Applications should have this capability removed when they run in a trusted environment.

Avoid Command Line Execution

Running applications directly from the command line should be avoided if the application has been given privileges because the end user can take advantage of the privileges. For example, many application allow the end user to enter a command to execute followed by a document name. If the application has been given the privilege to override mandatory access controls (if the application needs to write down to an outside application), this could result in the end user opening a document that he or she does not ordinarily have the privileges to see.

Eliminate Covert Channels

Covert channels in privileged applications should be sought out and eliminated. A covert channel is an unintended path through which information can be transmitted in ways not protected by mandatory access controls. For example, in a privileged multilabel client/server application, the server has a queue of service requests. If unprivileged clients can add and remove requests from the queue and the queue has a finite size, the information on the full or not-full state of the queue can be exploited as a covert channel.

Data Types, Header Files, and Libraries

To use the programming interfaces described in this chapter, you need the following header file.

#include <tsol/priv.h>

The examples in this chapter compile with the following library:


-ltsol

Single Privileges

One privilege is represented by the priv_t type definition. You initialize a variable of type priv_t with a privilege ID that can be either the constant name or numeric ID. The constant name is preferred because it makes your code easier to read.

priv_t priv_id = PRIV_FILE_DAC_WRITE;

Privilege Set Structure

Privilege sets are represented by the priv_set_t data structure. You initialize variables of type priv_set_t with the str_to_priv_set(3TSOL) routine or the PRIV_ASSERT macro depending on whether you want to assert one privilege at a time using its privilege ID (PRIV_ASSERT) or convert a string of one or more privileges into a privilege set using a single interface (str_to_priv_set).

File Privilege Sets

The type of file privilege set to be worked on is represented by the priv_ftype_t type definition. Values are PRIV_ALLOWED and PRIV_FORCED.

Process Privilege Sets

The type of process privilege set to be worked on is represented by the priv_ptype_t type definition. Values are PRIV_EFFECTIVE, PRIV_INHERITABLE, PRIV_PERMITTED, and PRIV_SAVED.

Operations on File and Process Sets

The type of operation performed on a file or process privilege set is represented by the priv_op_t type definition. Not all operations are valid for every type of privilege set. Read the privilege set descriptions in "Privilege Sets" for details.

Values are the following:

Privilege Macros

The privilege macros operate on single privileges and privilege sets. They are described on the priv_macros(5) man page. The macros do not directly change the privilege sets associated with files or processes, but manipulate variables of type priv_set_t.

Privilege Macro 

Description 

PRIV_ASSERT(priv_set, priv_id)

Put the privilege (priv_id) into the set (priv_set).

PRIV_ISASSERT(priv_set, priv_id)

Return non-zero if the privilege (priv_id) is asserted in (priv_set).

PRIV_EQUAL(priv_set_a, Priv_set_b)

Return non-zero if the sets are identical. 

PRIV_EMPTY(priv_set)

Initialize the set to empty. 

PRIV_FILL(priv_set)

Fill the set with all privileges. 

PRIV_ISEMPTY(priv_set)

Return non-zero if the set is empty, and 0 if not empty. 

PRIV_ISFULL(priv_set)

Return non-zero if the privilege contains all privileges defined for the system, and 0 otherwise. 

PRIV_CLEAR(priv_set, priv_id)

Remove the privilege (priv_id) from set (priv_set).

PRIV_INTERSECT(priv_set_a, priv_set_b)

Store the intersection of set_a and set_b in set_b.

PRIV_INVERSE(priv_set)

Stores the inverse of priv_set in priv_set.

PRIV_UNION(priv_set_a, priv_set_b)

Store the union of set_a and set_b in set_b.

PRIV_XOR(priv_set_a, priv_set_b,)

Store the exclusive or of set_a and set_b in set_b.

PRIV_ISSUBSET(priv_set_a, priv_set_b)

Returns non-zero when all privileges asserted in priv_set_a are also asserted in priv_set_b, and 0 otherwise.

PRIV_TEST(priv_id, errno) 

Test whether priv_id is in the effective set, and sets errno to 1 if True and 0 if False.

Interface Declarations

The following interfaces are available for handling file and process privilege sets. Where there is one set of interfaces to access a file using the pathname and another to access a file by the file descriptor, the examples use the pathname interfaces only because the syntax is almost identical.

System Calls

These system calls get and set file and process privilege sets.

File Sets

These system calls get and set the file privilege set using the full path name of the file. Refer to the getfpriv(2) man page.

int getfpriv( char *path,
	priv_ftype_t type,
	priv_set_t *priv_set);

int setfpriv( char *path,
	priv_op_t op,
	priv_ftype_t type,
	priv_set_t *priv_set);

These system calls get and set file privilege set using a file descriptor. Refer to the getfpriv(2) man page.

int fgetfpriv(int fd,
	priv_ftype_t type,
	priv_set_t *priv_set);

int fsetfpriv(int fd,
	priv_op_t op,
	priv_ftype_t type,
	priv_set_t *priv_set);

Process Sets

These system calls get and set process privilege sets. Refer to the getppriv(2) man page.

int getppriv(priv_ptype_t type, priv_set_t *priv_set);

int setppriv(priv_op_t op,
	priv_ptype_t type,
	priv_set_t *priv_set);

Note -

You can also use the library routines below to access process privilege sets. The syntax is a little different, but the semantics are the same.


Library Routines

These library routines get process privilege sets, convert a privilege ID or privilege set between binary and text, and get the privilege description text for a specified privilege ID.

Process Privilege Sets

These library routines set the effective, permitted, and inheritable privilege sets on a process. Refer to the set_effective_priv(3TSOL) man page.

int set_effective_priv(priv_op_t op, int privno, priv_t priv_id);

int set_permitted_priv(priv_op_t op, int privno, priv_t priv_id);

int set_inheritable_priv(priv_op_t op, int privno, priv_t priv_id);

Note -

You can also use setppriv(2) and getppriv(2) to access process privilege sets. The syntax is a little different, but the semantics are the same.


Binary and Text Privilege Translation

These library routines translate a privilege ID or a privilege set between binary and text. Refer to the priv_to_str(3TSOL) man page.

char* priv_to_str(const priv_t priv_id);

priv_t str_to_priv(const char *priv_name);

char* priv_set_to_str(priv_set_t *priv_set,
	const char sep,
	char *buf, int *blen);

char* str_to_priv_set(const char *priv_names,
	priv_set_t *priv_set,
	const char *sep);

Privilege Description Text

These library routines get the privilege text for a specified privilege ID. Refer to the priv_to_str(3TSOL) man page.

char* get_priv_text(const priv_t priv_id);

Translating Privileges

These library routines convert the specified privilege ID to its corresponding external name or numeric ID and back. These routines read the privilege names database file described on the priv_name(4) man page to translate between the priv_id and *string.

Privilege ID to String

In this example, priv_id is initialized to the manifest constant name PRIV_FILE_DAC_WRITE and passed to priv_to_str(3TSOL) routine to convert it to the external name.

The header files and declarations for the code segments in this section are provided in the first program.

#include <tsol/priv.h>

main()
{
	priv_t priv_id = PRIV_FILE_DAC_WRITE;
	char *string;

	string = priv_to_str(priv_id);
	printf("Priv string = %s\n", string);
}

The printf statement prints the following:


Priv string = file_dac_write

String to Privilege ID

In the next example, the string returned from the priv_to_str(3TSOL) routine is passed to the str_to_priv(3TSOL) routine to convert the string to the numeric ID.

	priv_id = str_to_priv(string);
	printf("Priv ID = %d\n", priv_id);

The printf statement prints the following:


Priv ID = 6

Get Description Text for Privilege ID

The get_priv_text(3TSOL) routine returns the description text for the specified priv_id. The priv_name(4) man page lists the description text for all privileges in the system.

	string = get_priv_text(priv_id);
	printf("%s\n", string);

The printf statement prints the following:


Allows a process to write a file or directory whose 
permission bits or ACL do not allow the process write permission.

Setting and Getting File Privilege Sets

The Trusted Solaris environment provides the user commands and programming interfaces described here for setting and getting the privilege sets of an executable file. If no forced and allowed privileges are set, by default the forced and allowed privilege sets contain none.


Note -

If you set file privilege sets prior to execution, the new privilege sets take effect immediately and are used to compute the process privilege sets for the current execution. If you set file privilege sets during execution, they do not take effect until the next execution and have no effect on the process privilege sets for the current execution.


Commands for File Sets

To set and get the file privilege sets from the command line, use setfpriv(1) and getfpriv(1). The file_setpriv privilege is required with setfpriv(1) so this command must be executed from the profile shell with this privilege. See "Assigning File Privileges using a Script" for information on using setfpriv(1) in a script.

This command line sets the file privilege sets on executable for the examples in this chapter. When you specify more than one privilege, the names are separated by commas with no spaces. If you want to use spaces, enclose the privilege names in double quotes ("privilege1, privilege2").


phoenix% setfpriv -s -f file_setpriv \
-a file_mac_write,proc_setid,file_setpriv executable

This command line produces output to verify the file privilege sets were set:


phoenix% getfpriv executable
executable FORCED: file_setpriv 
ALLOWED: file_mac_write,file_setpriv,proc_setid

Programming Interfaces for File Sets

The privilege macros and system calls described in this section get and set file privilege sets. The program below has the header files and variable declarations for the entire series of examples for this chapter. It also contains code to set and get the file privilege sets for execfile, which will be exec'd later to show what happens to process sets during an exec.

The setfpriv(1) system call sets the forced and allowed privilege sets on execfile and requires the file_setpriv privilege. The file_setpriv privilege is in the forced set for executable to make it available in the permitted set during execution. By default, the effective set equals the permitted set, and all effective privileges are on until explicitly turned off in preparation for privilege bracketing. The use of file_setpriv in this code does not follow security guidelines until privilege bracketing is put into effect as described in "Bracketing Effective Privileges".

/* cc priv.c -o executable -ltsol */

#include <tsol/priv.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>

/* Global Variables*/
extern int errno;
char buffer [3*1024];

main()
{
	char *priv_names = "file_mac_write,proc_setid";
	char *string;
	char *privilege;
	char *file = "/export/home/zelda/executable";
	char *execfile = "/export/home/zelda/execfile";
	priv_set_t priv_set, priv_get, permitted_privs, saved_privs;
	int length = sizeof(buffer);
	int retval;
	pid_t pid;

/* To use with exec() later */
	char *argv[8] = {"execfile"};

/* Initialize privilege set data structures */

	PRIV_EMPTY(&priv_get);
	PRIV_EMPTY(&priv_set);

/* Turn allowed privileges off. See text for discussion. */

	retval = setfpriv(execfile, PRIV_SET, PRIV_ALLOWED, &priv_get);
/* Assert the privileges in priv_names in a privilege set */
/* structure and assign to execfile. See text below for discussion */
/* on methods for asserting privileges */

	if((string = str_to_priv_set(priv_names, &priv_set, ",")) != NULL)
	printf("string = %s errno = %d\n", string, errno);
	retval = setfpriv(execfile,PRIV_ON, PRIV_ALLOWED, &priv_set);

/* Check that the allowed privilege set contains the privileges */

	retval = getfpriv(execfile, PRIV_ALLOWED, &priv_get);
	priv_set_to_str(&priv_get, ',', buffer, &length);
	printf("execfile Allowed = %s\n", buffer);

/* Initialize privilege set data structures */

	PRIV_EMPTY(&priv_set);
	PRIV_EMPTY(&priv_get);

/* Assert file_mac_write in a privilege set structure */

	PRIV_ASSERT(&priv_set, PRIV_FILE_MAC_WRITE);

/* Set the forced privilege set on execfile */

	retval = setfpriv(execfile, PRIV_ON, PRIV_FORCED, &priv_set);

/* Check that the forced privilege set contains the privilege */

	retval = getfpriv(execfile, PRIV_FORCED, &priv_get);
	priv_set_to_str(&priv_get, `,', buffer, &length);
	printf("execfile Forced =%s\n", buffer);
}

The printf statements print the file privilege sets for execfile as follows:


execfile Allowed = file_mac_write,proc_setid
execfile Forced = file_mac_write

The output uses a comma (",") to separate the allowed privileges. The separator is specified in the calls to priv_set_to_str(3TSOL). The separator is not used when there is only one privilege in the set.

Turn Allowed Privileges Off

The forced set is a subset of the allowed set. Any privileges in the forced set are cleared when the allowed set is cleared. The allowed set is none by default, but it is a good practice to clear it first so you know you are starting from zero. Always clear and set the allowed set before you set the forced set. After the following code executes, the allowed and forced sets are both none.

PRIV_EMPTY(&priv_set);
retval = setfpriv(execfile, PRIV_SET, PRIV_ALLOWED, &priv_set);

Assert Privileges in Privilege Set Structure

You can use the PRIV_ASSERT macro or the str_to_priv_set(3TSOL) routine to assert privileges in a privilege set structure. str_to_priv_set() works well when you have two or more privileges to assert because you can do it in one statement; whereas, PRIV_ASSERT must be called for each privilege asserted in the set. This code uses the str_to_priv_set() routine for the allowed set and PRIV_ASSERT for the forced set. The str_to_priv() routine returns NULL on success and the string passed to it in priv_names on failure.

if((string = str_to_priv_set(priv_names, &priv_set, ",")) != NULL)
	printf("string = %s errno = %d\n", string, errno);

 PRIV_EMPTY(&priv_set);
 PRIV_ASSERT(&priv_set, PRIV_FILE_MAC_WRITE);

Contents of Privilege Sets

The next examples operate on the process sets. It might be helpful to see the of file and process privilege sets before any operations. The process sets are calculated from the algorithms in "Process Privilege Sets".


executable Allowed = file_mac_write,file_setpriv,proc_setid
executable Forced = file_setpriv
Permitted = file_mac_write,file_setpriv,proc_setid
Effective = file_mac_write,file_setpriv,proc_setid
Saved = file_mac_write,proc_setid
Inheritable = file_mac_write&file_setpriv,proc_setid

Bracketing Effective Privileges

Privilege bracketing involves turning the effective privileges off (they are on and equal the permitted set by default), then turning on (making effective) only those permitted privileges needed for a given interface call, and turning them off when the privileged call completes.

When you analyze which privileges are needed for an interface, look at what the interface does and the purpose of the privileges described on the man page for that interface. Some privileges have broader effects than others and should be treated with greater scrutiny.

For example, it is relatively easy to examine a segment of code to see that it uses a privilege with the mount(1M) system call and tell whether the use of that privilege can be exploited in any way. It is more difficult to tell if the use of a privilege to override the mandatory or discretionary access policy to access a restricted file can be exploited.

It is up to you to perform privilege bracketing in your code and to do it correctly. Always remember that all privileges override some policy that is not allowed to untrusted processes, and handle your use of privileges with the needed care.

Procedure for Bracketing Privileges

The procedure for bracketing the setfpriv(1) system call and the effects it has on the effective set are summarized here. The code is shown in the next headings.

At the start of execution before bracketing, the permitted and effective sets contain these privileges:


Permitted = file_mac_write,file_setpriv,proc_setid
Effective = file_mac_write,file_setpriv,proc_setid
  1. Clear the effective set at the beginning of the application.


    Permitted = file_mac_write,file_setpriv,proc_setid
    Effective = none
  2. Bracket the setfpriv() system call.

    1. Turn the file_setpriv privilege on in the effective set right before you call the setfpriv() system call.


      Permitted = file_mac_write,file_setpriv,proc_setid
      Effective = file_setpriv
    2. Turn off the effective set immediately after the setfpriv() system call.


      Permitted = file_mac_write,file_setpriv,proc_setid
      Effective = none

Clear Effective Set

The example uses set_effective_priv(3TSOL) to clear the effective set at the beginning of the application. The PRIV_SET parameter clears the effective privilege set, and the zero (0) indicates there is no parameter list of privilege IDs.

if (set_effective_priv(PRIV_SET, 0) == -1)
	perror("Cannot clear effective privileges");

Continue Application Code

Turning the entire effective privilege set off is followed by application code until a privilege is needed.

Bracketing the Call

The example uses set_effective_priv(3TSOL) to bracket. The first call turns the file_setpriv privilege on (asserts it) in the effective set; the second call turns it off. The 1 indicates the privilege parameter list has one privilege constant (PRIV_FILE_SETPRIV) in it.

/* Turn file_setpriv on in effective set */
	if (set_effective_priv(PRIV_ON, 1, PRIV_FILE_SETPRIV) == -1)
		perror("Cannot assert PRIV_FILE_SETPRIV");

/* Make interface call */
	retval = setfpriv(execfile, PRIV_SET, PRIV_ALLOWED, &priv_get);

/* Turn the file_setpriv privilege off */
	if (set_effective_priv(PRIV_OFF, 1, PRIV_FILE_SETPRIV) == -1)
		perror("Cannot clear PRIV_FILE_SETPRIV");

/* Continue application code ...*/

Bracketing in Example

This next example shows the body of the example application code with comments indicating the places where setfpriv(1) should be bracketed.

	PRIV_EMPTY(&priv_get);
	PRIV_EMPTY(&priv_set);

/* Turn file_setpriv on in the effective set */
	retval = setfpriv(execfile, PRIV_SET, PRIV_ALLOWED, &priv_get);
/* Turn the file_setpriv privilege off */

	if((string = str_to_priv_set(priv_names, &priv_set, ",")) != NULL)
		printf("string = %s errno = %d\n", string, errno);

/* Turn file_setpriv on in the effective set */
	retval = setfpriv(execfile,PRIV_ON, PRIV_ALLOWED, &priv_set);
/* Turn the file_setpriv privilege off */

	retval = getfpriv(execfile, PRIV_ALLOWED, &priv_get);
	priv_set_to_str(&priv_get, ',', buffer, &length);
	printf("execfile Allowed = %s\n", buffer);

	PRIV_EMPTY(&priv_set);
	PRIV_EMPTY(&priv_get);
	PRIV_ASSERT(&priv_set, PRIV_FILE_MAC_WRITE);

/* Turn file_setpriv on in the effective set */
	retval = setfpriv(execfile, PRIV_ON, PRIV_FORCED, &priv_set);
/* Turn the file_setpriv privilege off */

	retval = getfpriv(execfile, PRIV_FORCED, &priv_get);
	priv_set_to_str(&priv_get, `,', buffer, &length);
	printf("execfile Forced =%s\n", buffer);

Checking and Modifying Privileges

Applications can notify users that privileges are missing, and establish the privilege sets for a program.

Check Permitted Privileges

An application can check the permitted privilege set to be sure the application has all privileges it needs to function. This way, if an application is missing a privilege, it can issue an error message to that effect. Continuing without all the needed privileges typically produces error messages that are more difficult to interpret.

The following example gets the permitted set and checks for PRIV_FILE_MAC_WRITE, PRIV_PROC_SETID, and PRIV_FILE_SETPRIV. The PRIV_ISSUBSET macro provides another way (not shown) to check if one privilege set contains all the privileges in another privilege set from within your source code.

/* Initialize privilege set data structure */
 PRIV_EMPTY(&permitted_privs);

/* Test for privileges in permitted set. */

 if (getppriv(PRIV_PERMITTED, &permitted_privs) == -1)
	perror("Cannot get list of permitted privileges\n");

 if (!PRIV_ISASSERT(&permitted_privs, PRIV_FILE_MAC_WRITE))
	fprintf(stderr, "Need: file_mac_write.\n");

 if (!PRIV_ISASSERT(&permitted_privs, PRIV_PROC_SETID))
	fprintf(stderr, "Need: proc_setid.\n");

 if (!PRIV_ISASSERT(&permitted_privs, PRIV_FILE_SETPRIV))
	fprintf(stderr, "Need: file_setpriv.\n");

Remove a Permitted Privilege

You can remove privileges from the permitted set, but once a privilege is removed it cannot be added back. Only privileges in the permitted set can be in the inheritable set so do not remove a permitted privilege that needs to be in the inheritable set. This example removes the file_mac_write privilege from the permitted set. The 1 indicates the parameter list has one privilege constant.

if(set_permitted_priv(PRIV_OFF, 1, PRIV_FILE_MAC_WRITE) == -1)
	perror ("Cannot remove file_mac_write from permitted set");

Before this call the permitted set contains these privileges:


executable Permitted = file_mac_write,file_setpriv,proc_setid

After this call the permitted set contains these privileges:


executable Permitted = file_setpriv,proc_setid

Check Saved Privileges

An application can check the saved privilege set to determine the origin of a privilege to take action based on the findings. This example gets the saved set and checks for PRIV_PROC_SETID and PRIV_FILE_SETPRIV and finds that the file_setpriv privilege is not inherited, but the proc_setid privilege is inherited.

PRIV_EMPTY(&saved_privs);

 if (getppriv(PRIV_SAVED, &saved_privs) == -1)
	perror("Cannot get list of saved privileges\n");
 if (!PRIV_ISASSERT(&saved_privs, PRIV_PROC_SETID))
	fprintf(stderr, "proc_setid not in saved set. \n");

 if (!PRIV_ISASSERT(&saved_privs, PRIV_FILE_SETPRIV))
	fprintf(stderr, "file_setpriv not in saved set.\n");

Clear and Set the Inheritable Set

To set the privileges that will be active after a new program is started using exec(2), first clear the inheritable set of the process, then initialize it with the privileges that you want the program to inherit.

This example clears the inheritable privilege set. The PRIV_SET parameter clears the inheritable privilege set, and the zero (0) parameter indicates there is no parameter list of privilege IDs.

if (set_inheritable_priv(PRIV_SET, 0) == -1)
	perror("Cannot clear inheritable privileges");

Before this call the inheritable set contains these privileges:


Inheritable = file_mac_write,file_setpriv,proc_setid

After this call the inheritable set contains this privilege:


Inheritable = none

The following example sets the proc_setid privilege in the inheritable privilege set. Any privilege in the permitted set can be placed in the inheritable set and placing any other privilege in the inheritable set results in an Invalid Argument error. Because the proc_setid privilege is in the permitted set for executable, it can be placed in the inheritable set. Because it is also in the allowed set for execfile, it can be used by the new program when execfile is exec'd in "Execute a File".

if (set_inheritable_priv(PRIV_ON, 1, PRIV_PROC_SETID) == -1)
	perror("Cannot set proc_setid privilege in inheritable set");

After this call the inheritable set contains this privilege:


Inheritable = proc_setid

Fork a Process

When a child process is created by fork, its process sets are identical to the parent's process sets. This can be proven by querying the process privilege sets, forking a process, and querying the child process privilege sets:

Parent Process Privilege Sets

Before the fork, the parent process has the following privileges:


Forked Inheritable = proc_setid
Forked Saved = file_setpriv,proc_setid
Forked Permitted = file_setpriv,proc_setid
Forked Effective = none

System Call and Code

pid = fork();
if (pid > 0)
	exit(0);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_INHERITABLE, &priv_get);
printf("retval = %d errno = %d\n", retval, errno);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Forked Inheritable = %s\n", buffer);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_SAVED, &priv_get);
printf("retval = %d errno = %d\n", retval, errno);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Forked Saved = %s\n", buffer);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_PERMITTED, &priv_get);
printf("retval = %d errno = %d\n", retval, errno);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Forked Permitted = %s\n", buffer);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_EFFECTIVE, &priv_get);
printf("retval = %d errno = %d\n", retval, errno);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Forked Effective = %s\n", buffer);

New Process Privilege Sets

After the fork(2) system call, the printf statements print the following:


Forked Inheritable = proc_setid
Forked Saved = file_setpriv,proc_setid
Forked Permitted = file_setpriv,proc_setid
Forked Effective = none

Execute a File

When a file is exec'd, the process sets are computed based on the algorithms described in "Process Privilege Sets".

Privilege Sets

The execfile for the new program has the following file privilege sets, which were set by the exec'ing process's application code:

execfile Allowed = file_mac_write,proc_setid
execfile Forced = file_mac_write

The exec'ing process has the following process sets:


Exec'd Inheritable = proc_setid
Exec'd Saved = file_setpriv,proc_setid
Exec'd Permitted = file_setpriv,proc_setid
Exec'd Effective = none

System Call

retval = execv(execfile, argv);

New Process Privilege Sets

After the exec(2) system call, the process sets are as follows.


execfile Allowed = file_mac_write,proc_setid
execfile Forced = file_mac_write
Exec'd Inheritable = proc_setid
Exec'd Saved = proc_setid
Exec'd Permitted = file_mac_write,proc_setid
Exec'd Effective = file_mac_write,proc_setid

Set User ID

The exec'd program's effective privileges are on by default. Because the new program has the proc_setid privilege in its effective set, you can call setuid(2) to see how the effective and saved sets change when the User ID changes. See "Change in User ID" for the discussion.

retval = setuid(0);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_EFFECTIVE, &priv_get);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Executable setuid effective = %s\n", buffer);

PRIV_EMPTY(&priv_get);
retval = getppriv(PRIV_SAVED, &priv_get);
priv_set_to_str(&priv_get, ',', buffer, &length);
printf("Executable setuid saved = %s\n", buffer);

The printf statements print the following:


Executable setuid effective = none
Executable setuid saved = file_mac_write,proc_setid