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.
A privileged process cannot be exploited by making privileges available to another process.
A bug in the application code is less likely to cause misuse of a privilege if the privilege is turned off when not needed.
The principle of least privilege is enforced because the process uses only the privileges it needs for the interfaces it is currently calling.
The evaluation of a trusted application is easier because privilege bracketing shows the person evaluating the code exactly where privileges are used.
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.
Privileges with broad effects are those that override mandatory access control or discretionary access control policies.
Privileges with narrower effects are those that allow access to a restricted operation such as mounting a file system.
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.
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 |
Clear the effective set at the beginning of the application.
Permitted = file_mac_write,file_setpriv,proc_setid Effective = none |
Bracket the setfpriv() system call.
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 |
Turn off the effective set immediately after the setfpriv() system call.
Permitted = file_mac_write,file_setpriv,proc_setid Effective = none |
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");
Turning the entire effective privilege set off is followed by application code until a privilege is needed.
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 ...*/
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);