|
Softpanorama
(slightly skeptical)
Open Source Software Educational Society |
May the
source be with you,
but remember the KISS principle ;-)
|
Solaris Privilege Sets
Quotes for
The Least Privilege Model in the Solaris ...
... Many software exploits count on this escalated privilege to gain
superuser access to a machine via bugs like buffer overflows and data
corruption. To combat this problem, the Solaris 10 Operating System
includes a new least privilege model, which gives a specified
process only a subset of the superuser powers and not full access to
all privileges.
The least privilege model evolved from Sun's experiences with Trusted
Solaris and the tighter security model used there. The Solaris
10 OS least privileged model conveniently enables normal users to do
things like mount file systems, start daemon processes that bind to
lower numbered ports, and change the ownership of files. On
the other hand, it also protects the system against programs that previously
ran with full root privileges because they needed limited access to
things like binding to ports lower than 1024, reading from and writing
to user home directories, or accessing the Ethernet device. Since
setuid root binaries and daemons that run with full root privileges
are rarely necessary under the least privilege model, an exploit in
a program no longer means a full root compromise. Damage due
to programming errors like buffer overflows can be contained to a non-root
user, which has no access to critical abilities like reading or writing
protected system files or halting the machine.
The Solaris 10 OS least privilege model includes nearly 50 fine-grained
privileges as well as the basic privilege set.
- The defined privileges are broken into the
groups
contract,
cpc, dtrace,
file, ipc,
net, proc,
and sys.
- The basic privilege set includes all privileges
granted to unprivileged processes under the traditional security
model:
proc_fork,
proc_exec, proc_session,
proc_info, and file_link_any.
Each process has four privilege sets in its kernel credentials:
- The Inheritable set (
I): The privileges
inherited on exec.
- The Permitted set (
P): The maximum set
of privileges for the process.
- The Effective set (
E): The privileges
currently in effect, a subset of P.
- The Limit set (
L): The upper bound of
the privileges a process and its children may obtain. Any changes to
the set L take effect on the next
exec.
Each process also has a privilege awareness state (PAS)
which can be set to Privilege Aware (PA) or Not-Privilege
Aware (NPA). Privilege awareness is a mechanism
which allows legacy applications to retain full compatibility with the traditional
full privilege model. Legacy applications that are NPA
will appear to be granted all privileges in the set
L if any of the EUID, RUID, or SUID are 0 (root).
When a process calls exec(2), the kernel tries
to relinquish privilege awareness. For unprivileged processes,
I, P, and
E are generally the same as the basic set of
privileges, and L is typically the full set of
defined privileges. For a more detailed explanation of the theory behind
the implementation, take a look at
Casper Dik's weblog on
blogs.sun.com and the
Process Rights Management Tutorial.
Once launched, a process uses the privilege
manipulation functions to add or remove privileges from the privilege
sets. Privileges can always be removed, but only privileges found in the
permitted set can be added to the effective and inheritable set. As a result,
the inheritable set can be larger than the permitted set. The limit set
can never grow.
Often system administrators wish to grant certain users select privileges
so that they may perform system tasks. If the user does not have the correct
privileges, then the system outputs an error and the task is not performed.
Say that the SUID bit has been removed from the file
/usr/sbin/traceroute so that normal users cannot use it. Any system
administrator should be able to use traceroute
from his or her personal account without needing to be root, though. Without
the correct privileges, a user will see the following error when trying
to traceroute to the host
www:
traceroute www
traceroute: icmp socket: Permission denied
To determine which privilege is missing from various commands, use the
debugging functionality of ppriv(1) in the shell:
ppriv -D $$
traceroute www
traceroute[2885]: missing privilege "net_icmpaccess" (euid = 1001,
syscall = 230) for "devpolicy" needed at so_socket+0xa4
traceroute: icmp socket: Permission denied
Now that it's clear that the person with the UID 1001 is missing the
PRIV_NET_ICMPACCESS
privilege, it can be granted so that UID 1001 may successfully run
traceroute. Be sure to turn off debugging in
that shell after diagnosing the problem:
ppriv -N $$
Instead of debugging every command in the shell, the user can also debug
just one process at a time:
ppriv -D -e dtrace -D test.d
The RBAC facility, present in the Solaris OS since version 8, is used
to assign specific privileges to roles or users. Solaris RBAC configuration
is controlled through four main files, /etc/security/exec_attr,
/etc/security/prof_attr,
/etc/security/auth_attr, and /etc/user_attr.
exec_attr(4) specifies the execution attributes
associated with profiles. This generally includes the user and group IDs,
commands, and default/limit privileges. prof_attr(4)
contains a collection of execution profile names, descriptions, and other
attributes. auth_attr(4) contains authorization
definitions and descriptions. user_attr(4) contains
user and role definitions along with their assigned authorizations, profiles,
and projects. For a better understanding of how RBAC operates, read the
above-mentioned man pages along with rbac(5),
policy.conf(4), chkauthattr(3SECDB)
man pages, and the
Roles, Rights Profiles, and Privileges section of the
Solaris
10 System Administrator Collection.
To allow a group of users to use DTrace, the
system administrator would either create a role that had access to the
DTrace privileges or assign the privilege directly
to a user. The following would create a "debug"
role and grant it the appropriate privileges:
roleadd -u 201 -d /export/home/debug -P "Process Management" debug
rolemod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user debug
Now add the necessary users to the debug role
with usermod:
usermod -R debug username
The users with the role debug can now use
su to access debug,
providing the appropriate password, and run the necessary
DTrace commands.
Instead of adding roles and making the users access the role via
su, the system administrator can also directly
assign privileges to a user. The user must be logged out in order for the
following command to succeed:
usermod -K defaultpriv=basic,dtrace_kernel,dtrace_proc,dtrace_user username
If additional privileges are required, pinpoint them by running
dtrace command ppriv
again.
RBAC can also be used in conjunction with the least privilege model to
more securely run daemons, like httpd, that need
to bind to privileged ports. Many such programs do not actually need root
access for anything other than listening on a port below 1024, so granting
the role/user that runs the process net_privaddr
would remove the need for ever running the process with EUID 0.
The Defined Privilege Set
The defined privileges under the new least privilege model are listed
as in the privileges(5) man page, but here are
some that system administrators are more likely to use:
-
PRIV_CPC_CPU
-
Allow a process to access per-CPU hardware performance counters.
-
PRIV_DTRACE_PROC
-
Allow
DTrace process-level tracing. Allow
process-level tracing probes to be placed and enabled in processes to
which the user has permissions.
-
PRIV_DTRACE_USER
-
Allow
DTrace user-level tracing. Allow use
of the syscall and profile DTrace providers
to examine processes to which the user has permissions.
-
PRIV_DTRACE_KERNEL
-
Allow
DTrace kernel-level tracing.
-
PRIV_FILE_CHOWN
-
Allow a process to change a file's owner user ID. Allow a process to
change a file's group ID to one other than the process's effective group
ID or one of the process's supplemental group IDs.
-
PRIV_FILE_CHOWN_SELF
-
Allow a process to give away its files. A process with this privilege
will run as if
{_POSIX_CHOWN_RESTRICTED}
is not in effect.
-
PRIV_FILE_DAC_READ
-
Allow a process to read a file or directory whose permission bits or
ACL would otherwise disallow the process read permission.
-
PRIV_FILE_DAC_SEARCH
-
Allow a process to search a directory whose permission bits or ACL would
not otherwise allow the process search permission.
-
PRIV_FILE_DAC_WRITE
-
Allow a process to write a file or directory whose permission bits or
ACL do not allow the process write permission. All privileges are required
to write files owned by UID 0 in the absence of an effective UID of
0.
-
PRIV_FILE_OWNER
-
Allow a process that is not the owner of a file to modify that file's
access and modification times. Allow a process that is not the owner
of a directory to modify that directory's access and modification times.
Allow a process that is not the owner of a file or directory to remove
or rename a file or directory whose parent directory has the "save text
image after execution" (sticky) bit set. Allow a process that is not
the owner of a file to mount a
namefs upon
that file. Allow a process that is not the owner of a file or directory
to modify that file's or directory's permission bits or ACL.
-
PRIV_NET_ICMPACCESS
-
Allow a process to send and receive ICMP packets.
-
PRIV_NET_PRIVADDR
-
Allow a process to bind to a privileged port number. The privilege port
numbers are 1-1023 (the traditional UNIX privileged ports) as well as
those ports marked as "
udp/tcp_extra_priv_ports"
with the exception of the ports reserved for use by NFS.
-
PRIV_PROC_SETID
-
Allow a process to set its UIDs at will, assuming UID 0 requires all
privileges to be asserted.
-
PRIV_PROC_ZONE
-
Allow a process to trace or send signals to processes in other zones.
See
zones(5).
-
PRIV_SYS_ADMIN
-
Allow a process to perform system administration tasks such as setting
node and domain name and specifying
coreadm(1M)
and nscd(1M) settings.
-
PRIV_SYS_CONFIG
-
Allow a process to perform various system configuration tasks. Allow
file system-specific administrative procedures, such as file system
configuration ioctls, quota calls, creation and deletion of snapshots,
and manipulating the PCFS boot sector.
-
PRIV_SYS_DEVICES
-
Allow a process to create device special files. Allow a process to successfully
call a kernel module that calls the kernel
drv_priv(9F)
function to check for allowed access. Allow a process to open the real
console device directly. Allow a process to open devices that have been
exclusively opened.
-
PRIV_SYS_MOUNT
-
Allow a process to mount and unmount file systems that would otherwise
be restricted (that is, most file systems except
namefs). Allow a process to add and remove swap devices.
|
|
Notes:
- This is a Spartan WHYFF (We Help
You For Free) site written by people for whom English
is not a native language.
Some amount of grammar and spelling errors should be
expected.
- The site contain some broken links
as it develops like a living tree...
Please try to use Google, Open directory,
etc. to find a replacement link (see
HOWTO search the WEB for details). We would appreciate
if you can
mail us a correct link.
|
|
|
Feb 12, 2006 (Glenn Brunette's Security Weblog)
Just this month,
Darren
Moffat and I have published a
Sun BluePrint article and opened a
OpenSolaris Security Project on privilege debugging which
includes a cool, new tool, called
privdebug.
Together these resources can help you quickly and easily
determine which privileges are used by any process, service
or application. With this information, you can configure SMF
to limit the privileges granted to it using the approach described
here.
Everything is freely available. So why not give it a try!
We would love to hear what you think!
Take care,
Glenn
Introduction
This Tech Tip explores using Process Rights Management (PRM) in the
Solaris 10 OS, and how PRM enables us to execute
setuid and setgid commands without
the setuid or setgid
flags.
Objective
PRM in the Solaris 10 OS allows us to remove
setuid/setgid flags from executables
that would normally have them set, while also allowing a selected set
of non-privileged users to execute them.
In the Solaris 10 OS, although most of the "normal"
setuid/setgid
executables have been re-written to be privilege aware (PA), they still
have their setuid/setgid
flags set. This is necessary for the program to first gain the appropriate
root privilege and then drop the unnecessary ones. However, this would
require the program to be fully privilege aware and some
setuid/setgid
programs out there might not have been ported as yet.
This Tech Tip suggests a method to remove the
setuid/setgid flag, while allowing
a selected non-root user to execute the program appropriately.
Example Using ping
A good example of a setuid binary would
be the ping program.
$ ls -al /usr/sbin/ping
-r-sr-xr-x 1 root bin 45016 Apr 26 2005 /usr/sbin/ping
Now rewritten to be PA, the ping program
drops unnecessary root privileges immediately upon startup:
root@solaris # ppriv -v 1325
1325: ping -s 192.168.0.1
flags = PRIV_AWARE
E: file_link_any,proc_exec,proc_fork,proc_info,proc_session
I: file_link_any,proc_exec,proc_fork,proc_info,proc_session
P: file_link_any,proc_exec,proc_fork,proc_info,proc_session
L: none
Let's say we now remove the setuid flag
from /usr/sbin/ping:
root@solaris # ls -al /usr/sbin/ping
-r-xr-xr-x 1 root bin 45016 Apr 26 2005 /usr/sbin/ping
Subsequently, a normal non-root user would no longer be able to properly
execute ping:
$ ping -s 192.168.0.1
ping: socket Permission denied
Why ping Failed
ping failed because it is now missing
the net_icmpaccess privilege. To illustrate
this, we run ping with the Solaris 10 OS
privilege inspection and debugging feature (using
ppriv):
$ ppriv -e -D ping -s 192.168.0.1
ping[1391]: missing privilege "net_icmpaccess" (euid = 100, syscall = 230) for
"devpolicy" needed at so_socket+0x9d
ping: socket Permission denied
The above occurs because the setuid flag
has been removed from ping.
Let's look at the privilege of the parent user shell executing the
ping command:
root@solaris # ppriv -v 955
955: -ksh
flags = <none>
E: file_link_any,proc_exec,proc_fork,proc_info,proc_session
I: file_link_any,proc_exec,proc_fork,proc_info,proc_session
P: file_link_any,proc_exec,proc_fork,proc_info,proc_session
L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,dtrace_proc,
dtrace_user,file_chown,file_chown_self,file_dac_execute,file_dac_read,
file_dac_search,file_dac_write,file_link_any,file_owner,file_setid,ipc_dac_read,
ipc_dac_write,ipc_owner,net_icmpaccess,net_privaddr,
net_rawaccess,proc_audit,proc_chroot,proc_clock_highres,proc_exec,proc_fork,
proc_info,proc_lock_memory,proc_owner,proc_priocntl,proc_session,proc_setid,
proc_taskid,proc_zone,sys_acct,sys_admin,sys_audit,sys_config,sys_devices,
sys_ipc_config,sys_linkdir,sys_mount,sys_net_config,sys_nfs,sys_res_config,
sys_resource,sys_suser_compat,sys_time
This clearly is missing the net_icmpaccess
privilege from its E, I, and P privilege set.
The Parent Shell Privileges
Let's assign the net_icmpaccess privilege
to the parent shell process (pid 955):
#ppriv -s PEI-net_icmpaccess 955
Once again, let's look at the shell privileges:
root@solaris # ppriv -v 955
955: -ksh
flags = <none>
E: file_link_any,net_icmpaccess,proc_exec,proc_fork,proc_info,proc_session
I: file_link_any,net_icmpaccess,proc_exec,proc_fork,proc_info,proc_session
P: file_link_any,net_icmpaccess,proc_exec,proc_fork,proc_info,proc_session
L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,dtrace_proc,
dtrace_user,file_chown,file_chown_self,file_dac_execute,file_dac_read,
file_dac_search,file_dac_write,file_link_any,file_owner,file_setid,ipc_dac_read,
ipc_dac_write,ipc_owner,net_icmpaccess,net_privaddr,
net_rawaccess,proc_audit,proc_chroot,proc_clock_highres,proc_exec,proc_fork,
proc_info,proc_lock_memory,proc_owner,proc_priocntl,proc_session,proc_setid,
proc_taskid,proc_zone,sys_acct,sys_admin,sys_audit,sys_config,sys_devices,
sys_ipc_config,sys_linkdir,sys_mount,sys_net_config,sys_nfs,sys_res_config,
sys_resource,sys_suser_compat,sys_time
We now try a ping as a non-root user from shell process 955:
$ ping -s 192.168.0.1
PING 192.168.0.1: 56 data bytes
64 bytes from silence.mshome.net (192.168.0.1): icmp_seq=0. time=0.313 ms
64 bytes from silence.mshome.net (192.168.0.1): icmp_seq=1. time=0.607 ms
64 bytes from silence.mshome.net (192.168.0.1): icmp_seq=2. time=0.566 ms
Success!
Automatic Assignment
But how do we assign individual shells the necessary privileges?
Do we have to assign them every time the user logs in or requires them?
Well, one way is to add the following user entry to
/etc/user_attr, like so:
johndoe::::defaultpriv=basic,net_icmpaccess
The above would automatically provide user johndoe
(a non-root privilege user) the appropriate privileges to run
ping without requiring that
ping have the setuid/setgid
flag set on its executable binary.
The above example illustrates a method to allow us to clear
setuid/setgid
flags from non-PA executables, which would normally require them.
Flaw
There is a flaw in using /etc/user_attr
to set the default privilege, of course: All the processes of user
admin would now also have
net_icmpaccess, even though they might not
require this particular privilege.
a Sun BluePrints article, describes how to profile applications and
services to determine which Solaris 10 privileges they attempt to use.
Organizations can then restrict those applications and services so that
they are granted only the absolutely necessary privileges that they
need to fulfill their intended purpose.
Learn how to use Role-Based Access Control to enforce the "Two Man
Rule", which restricts access so that two people must work in concert
to execute highly privileged operations.
This module provides wrappers for the Privilege-related system and
library calls. Also provided are constants from the various Privilege-related
headers and dynamically generated constants for all the privileges and
privilege sets.
So what makes Solaris Privileges different? Why didn't we copy something
else like Trusted Solaris Privileges or "POSIX" capabilities?
Let's start from what we formulated as our requirements near the beginning
of our project.
One of the important features of Solaris is complete binary backward
compatibility; in order to offer that we needed to design the privilege
subsystem in such a manner that current practices, binaries and products
would continue to work. Of course, some have solved this issue by providing
a system wide knob to turn: root / root + privileges / just privileges.
We don't like knobs in our OS; specifically not ones which drastically
alter the behaviour of a system. It makes it harder to develop software;
it needs to work for all settings. Certain products may require conflicting
settings, and so on. So we decided on a "per-process" knob which is
largely automatic
With backward compatibility comes the onus on the software developer
to develop future proof interfaces; that ruled out all other interfaces
as they all have fixed bitmaps and fixed privilege/capability numbers,
fixed structure sizes in the programmer visible parts of the system.
Solaris Privileges have none of that. And while we could savely reuse
the names of the Trusted Solaris interfaces we can not redefine interfaces
even from a defunct standard. So we have interfaces which smell like
Trusted Solaris but with a completely new userland representation of
privileges and privilege sets. We can never have more signals; but we
can have more privileges and more privilege sets!
The privileges and privilege sets in Solaris 10 are represented to userland
processes and non-core kernel modules as strings; privilege sets are
bitmasks of undetermined size; they can only be allocated through the
C library routines. Privilege set names are also strings and not plain
integer indices; this gives us even more flexibility. A Solaris binary
compiled for 4 privilege sets of each 32 privileges will continue to
work on a Solaris system with 5 privilege sets each of which can contain
64 privileges and with all the privileges having their internal representation
renumbered.
Most UNIX operating systems run a large number of their system processes
with root privileges, giving the program the capability to read and
modify other processes, memory, I/O devices, and so on. While this gives
the system processes the power needed to perform their tasks, it also
provides them with unnecessary access to other protected parts of the
system. Many software exploits count on this escalated privilege to
gain superuser access to a machine via bugs like buffer overflows and
data corruption. To combat this problem, the Solaris 10 Operating System
includes a new least privilege model, which gives a specified
process only a subset of the superuser powers and not full access to
all privileges.
The least privilege model evolved from Sun's experiences with Trusted
Solaris and the tighter security model used there. The Solaris 10 OS
least privileged model conveniently enables normal users to do things
like mount file systems, start daemon processes that bind to lower numbered
ports, and change the ownership of files. On the other hand, it also
protects the system against programs that previously ran with full root
privileges because they needed limited access to things like binding
to ports lower than 1024, reading from and writing to user home directories,
or accessing the Ethernet device. Since setuid root binaries and daemons
that run with full root privileges are rarely necessary under the least
privilege model, an exploit in a program no longer means a full root
compromise. Damage due to programming errors like buffer overflows can
be contained to a non-root user, which has no access to critical abilities
like reading or writing protected system files or halting the machine.
The Solaris 10 OS least privilege model includes
nearly 50 fine-grained privileges as well as the basic privilege set.
The defined privileges are broken into the groups
contract, cpc,
dtrace, file,
ipc, net,
proc, and sys.
The basic privilege set includes all privileges granted to unprivileged
processes under the traditional security model:
proc_fork, proc_exec,
proc_session, proc_info,
and file_link_any.
cool feature i am using (Score:5,
Interesting)
by Anonymous Coward on Friday February 20, @08:08AM (#8338473)
|
i try with solaris express and I find a cool feature called
"ppriv" like this:
gta3# ppriv $$
1124: bash
flags = 0x0
E: all
I: basic
P: all
L: all
Ok, so I am root I have all privileges I think
but now look at rpcbind, it is running as daemon but has less
priviliges even than normal processes
gta3# ppriv 100182
100182:
/usr/sbin/rpcbind
flags = 0x2
E: net_privaddr,proc_fork,sys_nfs
I: none
P: net_privaddr,proc_fork,sys_nfs
L: all
see, it does not have privilege to do 'exec'... there are 30
or more privileges and it has only 3. So i guess this means
some stack attack will not work against it like exec shell
also i can run and see privileges like thids
gta3$ ppriv -D -e cat /etc/shadow
cat[100619]: missing privilege "file_dac_read" (euid = 77293,
syscall = 225) needed at ufs_iaccess+0xd2
cat: cannot open /etc/shadow
not sure what this means?
|
In case of broken links
please try to use Google search. If you find the page please notify
us about new location
General info:
Process privilege sets and their attributes are viewed and modified by
the program ppriv(1). The
ppriv(1) program arguments follow the syntax:
/usr/bin/ppriv -l [-v] [privilege-specification...]
/usr/bin/ppriv [-v] [-S] [-D | -N] [-s spec] [pid | core]
/usr/bin/ppriv -e [-D | -N] [-s spec] command [arg...]
The preceding options are defined as:
-D: Turns on privilege debugging for
the processes or command supplied.
-e: Interprets the remainder of the arguments
as a command line and runs the command line with specified privilege
attributes and sets.
-l: Lists all currently defined privileges
on stdout.
-N: Turns off privilege debugging for
the processes or command supplied.
-s spec: Modifies a process's privilege
sets according to spec. Modifying the same
set with multiple -s options is possible
as long as you make either precisely one assignment to an individual
set or any number of additions and removals. That is, assignment and
addition or removal for one set are mutually exclusive.
spec is a specification with the format [AEILP][+-=]privsetspec,
containing no spaces, where:
AEILP: Includes one or more letters
indicating which privilege sets to change. These are case insensitive,
for example, either a or
A indicates all privilege sets.
+-=: Indicates a modifier to respectively
add (+), remove (-),
or assign (=) the listed privileges to
the specified set(s) in privsetspec.
privsetspec: Indicates a comma-separated
privilege set specification (priv1,
priv2, and so on), as described in
priv_str_to_set(3C).
-S: Short. Reports the shortest possible
output strings for sets. The default is portable output. See
priv_str_to_set(3C).
-v: Verbose. Reports privilege sets using
privilege names.
Viewing Process Privileges
Let's take a look at a few processes with the ppriv(1)
command to see how they differ, depending on whether or not they are PA
and have had their privileges modified. In this first example, we examine
the third-party user process screen which is
not privilege-aware. The flags are not set to
PRIV_AWARE, and P,
I, and E are all identically
defined as the basic privilege set. The set L
is the entire defined privilege set:
ppriv -v 1746
In this second example we examine the inetd
process. It is not privilege aware, but its P
and E sets have been modified to match
L because it's running with EUID/RUID/SUID 0:
pcred 193
193: e/r/suid=0 e/r/sgid=0
ppriv -v 193
193: /usr/lib/inet/inetd start
flags = <none>
E: contract_event,contract_observer,cpc_cpu,dtrace_kernel,
dtrace_proc,dtrace_user,file_chown,file_chown_self,
file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,file_setid,
ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,
net_privaddr,net_rawaccess,proc_audit,proc_chroot,
proc_clock_highres,proc_exec,proc_fork,proc_info,
proc_lock_memory,proc_owner,proc_priocntl,proc_session,
proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,
sys_audit,sys_config,sys_devices,sys_ipc_config,
sys_linkdirsys_mount,sys_net_config,sys_nfs,
sys_res_config,sys_resource,sys_suser_compat,
sys_time
I: file_link_any,proc_exec,proc_fork,proc_info,proc_session
P: contract_event,contract_observer,cpc_cpu,dtrace_kernel,
dtrace_proc,dtrace_user,file_chown,file_chown_self,
file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,file_setid,
ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,
net_privaddr,net_rawaccess,proc_audit,proc_chroot,
proc_clock_highres,proc_exec,proc_fork,proc_info,
proc_lock_memory,proc_owner,proc_priocntl,proc_session,
proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,
sys_audit,sys_config,sys_devices,sys_ipc_config,
sys_linkdir,sys_mount,sys_net_config,sys_nfs,
sys_res_config,sys_resource,sys_suser_compat,sys_time
L: contract_event,contract_observer,cpc_cpu,dtrace_kernel,
dtrace_proc,dtrace_user,file_chown,file_chown_self,
file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,file_setid,
ipc_dac_read,ipc_dac_write,ipc_owner,net_icmpaccess,
net_privaddr,net_rawaccess,proc_audit,proc_chroot,
proc_clock_highres,proc_exec,proc_fork,proc_info,
proc_lock_memory,proc_owner,proc_priocntl,proc_session,
proc_setid,proc_taskid,proc_zone,sys_acct,sys_admin,
sys_audit,sys_config,sys_devices,sys_ipc_config,sys_linkdir,
sys_mount,sys_net_config,sys_nfs,sys_res_config,
sys_resource,sys_suser_compat,sys_time
In this third example, we take a look at fmd(1M),
a process that is privilege aware. Note the flags
setting and the limitations on E,
I, P, and
L:
ppriv -v 306
306: /usr/lib/fm/fmd/fmd
flags = PRIV_AWARE
E: file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,proc_exec,
proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,
sys_admin,sys_config,sys_devices,sys_res_config
I: file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,proc_exec,
proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,
sys_admin,sys_config,sys_devices,sys_res_config
P: file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,proc_exec,
proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,
sys_admin,sys_config,sys_devices,sys_res_config
L: file_dac_execute,file_dac_read,file_dac_search,
file_dac_write,file_link_any,file_owner,proc_exec,
proc_fork,proc_info,proc_owner,proc_priocntl,proc_session,
sys_admin,sys_config,sys_devices,sys_res_config
In this final example, we take a look at the lockd(1M)
process which is PRIV_AWARE and extremely limited
in its access:
ppriv -v 161
161: /usr/lib/nfs/lockd
flags = PRIV_AWARE
E: sys_nfs
I: none
P: sys_nfs
L: none
[May 20, 2004]
Secure programmer Minimizing privileges David A. Wheeler
(dwheelerNOSPAM@dwheeler.com)
Research Staff Member, Institute for Defense Analyses.
Secure programs must minimize privileges so that any bugs are less
likely to be become security vulnerabilities. This article discusses how
to minimize privileges by minimizing the privileged modules, the privileges
granted, and the time the privileges are active. The article discusses not
only some of the traditional UNIX-like mechanisms for privileges, but some
of the newer mechanisms like the FreeBSD jail(), the Linux
Security Modules (LSM) framework, and Security-Enhanced Linux (SELinux).
On March 3rd, 2003, Internet Security Systems warned of a serious
vulnerability in Sendmail. All electronic mail is transferred using
a mail transfer agent (MTA), and Sendmail is the most popular MTA, so
this warning affected many organizations worldwide. The problem was
that an e-mail message with a carefully-crafted "from," "to," or "cc"
field could give the sender complete (root) control over any machine
running Sendmail as it's commonly configured. Even worse, typical firewalls
would
not protect interior machines from this attack.
The immediate cause of the vulnerability was that one of Sendmail's
security checks was flawed, permitting a buffer overflow. But a significant
contributing factor is that Sendmail is often installed as a monolithic
"setuid root" program, with complete control over the system it runs
on. Thus, any flaw in Sendmail can give an attacker immediate control
over the entire system.
Is this design necessary? No; a popular competing MTA is Wietse Venema's
Postfix. Postfix, like Sendmail, does a number of security checks, but
Postfix is also designed as a set of modules that
minimize privilege. As a result, Postfix is generally accepted as
a more secure program than Sendmail. This article discusses how to minimize
privileges, so you can apply the same ideas to your programs.
Basics of minimizing privileges
Real-world programs have bugs in them. It's not what we want, but it's
certainly what we get. Complicated requirements, schedule pressure,
and changing environments all conspire to make useful bugless programs
unlikely. Even programs formally proved correct using sophisticated
mathematical techniques can have bugs. Why? One reason is that proofs
must make many assumptions, and usually some of those assumptions aren't
completely true. Most programs aren't examined that rigorously anyway,
for a variety of reasons. And even if there are no bugs today (unlikely),
a maintenance change or a change in the environment may introduce a
bug later on. So, to handle the real world, we have to somehow develop
secure programs
in spite of the bugs in our programs.
One of the most important ways to secure programs, in spite of these
bugs, is to
minimize privileges. A privilege is simply permission to do something
that not
everyone is allowed to do. On a UNIX-like system, having the privileges
of the "root" user, of another user, or being a member of a group are
some of the most common kinds of privileges. Some systems let you give
privileges to read or write a specific file. But no matter what, to
minimize privileges:
- Give a privilege to only the parts of the program needing it
- Grant only the specific privileges that part absolutely requires
- Limit the time those privileges are active or can be activated
to the absolute minimum
These are really goals, not hard absolutes. Your infrastructure (such
as your operating system or virtual machine) may not make this easy
to do precisely, or the effort to do it precisely may be so complicated
that you'll introduce more bugs trying to do it precisely. But the closer
you get to these goals, the less likely it will be that bugs will cause
a security problem. Even if a bug causes a security problem, the problems
it causes are likely to be less severe. And if you can ensure that only
a tiny part of the program has special privileges, you can spend a lot
of extra time making sure
that one part resists attacks. This idea isn't new; the excellent
1975 paper by Saltzer and Schroeder discussing security principles specifically
identifies minimizing privileges as a principle (see
Resources). Some ideas, such as minimizing privileges, are timeless.
The next three sections discuss these goals in turn, including how
to implement them on UNIX-like systems. After that we'll discuss some
of the special mechanisms available in FreeBSD and Linux, including
a discussion about NSA's Security-Enhanced Linux (SELinux).
Minimize privileged modules
As noted earlier, only the parts of the program that need a privilege
should have the privilege. This means that when you're designing your
program, try to break the program into separate parts so that only small
and independent parts require special privileges.
If different parts must run concurrently, use processes (not threads)
on UNIX-like systems. Threads share their security privileges, and a
malfunctioning thread can interfere with all the other threads in a
process. Write the privileged parts as though the rest of the program
was attacking it: it might, someday! Make sure that the privileged part
only does as little as possible; limited functionality means there's
less to exploit.
One common approach is to create a command-line tool with special
privileges (such as being setuid or setgid) that has an extremely limited
function. The UNIX passwd command is an example;
it's a command-line tool with special privileges to change the password
(setuid root), but the only thing it can do is change passwords. Various
GUI tools can then ask passwd to do the actual changing.
Where possible, try to avoid creating setuid or setgid programs at all,
because it's very difficult to make sure that you're really protecting
all inputs. Nevertheless, sometimes you need to create setuid/setgid
programs, so when it's necessary, make the program as small and as limited
as possible.
There are many other approaches. For example, you could have a small
"server" process that has special privileges; that server allows only
certain requests, and only after verifying that the requester is allowed
to make the request. Another common approach is to start a program with
privileges, which then forks a second process that gives up all privileges
and then does most of the work.
Be careful how these modules communicate with each other. On many
UNIX-like systems, the command-line values and environment variable
values can be viewed by other users, so they aren't a good way to privately
send data between processes. Pipes work well, but be careful to avoid
deadlock (a simple request/response protocol, with flushing on both
sides, works well).
Minimize privileges granted
Ensure that you only grant the privileges a program actually needs --
and no more. The primary way that UNIX processes get privileges are
the user and groups they can run as. Normally, processes run as the
user and groups of their user, but a "setuid" or "setgid" program picks
up the privileges of the user or group that owns the program.
Sadly, there are still developers on UNIX-like systems that reflexively
give programs "setuid root" privileges. These developers think that
they've made things "easy" for themselves, because now they don't have
to think hard about exactly what privileges their programs need. The
problem is that, since these programs can do literally anything on most
UNIX-like systems, any bugs can quickly become a security disaster.
Don't give all possible privileges just because you need one simple
task done. Instead, give programs only the privileges they need. If
you can, run them as setgid not setuid -- setgid gives fewer privileges.
Create special users and groups (don't use root), and use those for
what you need. Make sure your executables are owned by root and only
writeable by root, so others can't change them. Set very restrictive
file permissions -- don't let anyone read or write files unless absolutely
necessary, and use those special users and groups. An example of all
this might be the standard conventions for game "top ten" scores. Many
programs are "setgid games" so that only the game programs can modify
the "top ten" scores, and the files storing the scores are owned by
the group games (and only writeable by that group). Even if an attacker
broke into a game program, all he could do would be to change the score
files. Game developers still need to write their programs to protect
against malicious score files, however.
One useful tool -- that unfortunately is a little hard to use --
is the chroot() system call. This system call changes what
the process views when it views the "root" of the filesystem. If you
plan to use this -- and it can be useful -- be prepared to take time
to use it well. The "new root" has to be carefully prepared, which is
complicated because correct application depends on the specifics of
the platform and of the application. You
must be root to make the chroot() call, and you
should quickly change to non-root (a root user can escape a
chroot environment, so if it's to be effective, you need
to drop that privilege). And chroot doesn't change the
network access. This can be a useful system call, so it's sometimes
necessary to consider it, but be prepared for effort.
One often-forgotten tool is to limit resources, both for storage
and for processes. This can be especially useful for limiting denial-of-service
attacks:
- For storage, you can set quotas (limits) for the amount
of storage or the number of files, per user and per group, for every
mounted filesystem. On GNU/Linux systems see quota(1), quotactl(2),
and quotaon(8) for more about this, but although they're not quite
everywhere, quota systems are included in most UNIX-like systems.
On GNU/Linux and many other systems, you can set "hard" limits (never
to exceed) and "soft" limits (which can be temporarily exceeded).
- For processes, you can set a number of limits such as
the number of open files, number of processes, and so on.
Such capabilities are actually part of standards (such as the
Single UNIX Specification), so they've nearly ubiquitous on UNIX-like
systems; for more information, see getrlimit(2), setrlimit(2), and
getrusage(2), sysconf(3), and ulimit(1). Processes can never exceed
the "current limit," but they can raise the current limits all the
way up to the "upper limit." Unfortunately, there's a weird terminology
problem here that can trip you up. The "current limit" is also called
the "soft" limit, and the upper limit is also called the "hard"
limit. Thus, you have the bizarre situation that processes can
never exceed the soft (current) limit of the process limits
-- while for quotas you can exceed the soft limits. I suggest
using the terms "current limit" and "upper limit" for process limits
(never using the terms "soft" and "hard") so there's no confusion.
Minimize privileges' time
Give privileges only when they're needed -- and not a moment longer.
Where possible, use whatever privileges you need immediately and
then
permanently give them up. Once they're permanently given up, an
attack later on can't try to exploit those privileges in novel ways.
For example, a program that needs a single root privilege may get started
as root (say, by being setuid root) and then switch to running as a
less-privileged user. This is the approach taken by many Internet servers
(including the Apache Web server). UNIX-like systems don't let just
any program open up the TCP/IP ports 0 through 1023; you have to have
root privileges. But most servers only need to open the port when they
first start up, and after that they don't need the privilege any more.
One approach is to run as root, open the privileged port as soon as
possible, and then permanently drop root privileges (including any privileged
groups the process belongs to). Try to drop all other derived privileges
too; for example, close files requiring special privileges to open as
soon as you can.
If you can't permanently give up the privilege, then you can at least
temporarily drop the privilege as often as possible. This isn't as good
as permanently dropping the privilege, since if an attacker can take
control of your program, the attacker can re-enable the privilege and
exploit it. Still, it's worth doing. Many attacks only work if they
trick the privileged program into doing something unintended while its
privileges are enabled (for example, by creating weird symbolic links
and hard links). If the program doesn't normally have its privileges
enabled, it's harder for an attacker to exploit the program.
Newer mechanisms
The principles we've discussed up to this point are actually true
for just about any operating system, and the general mechanisms have
been very similar between just about all UNIX-like systems since the
1970s. That doesn't mean they're useless; simplicity and the test of
time have their own advantages. But some newer UNIX-like systems have
added mechanisms to support least privilege that are worth knowing about.
While it's easy to find out about the time-tested mechanisms, information
about the newer mechanisms isn't as widely known. So, here I'll discuss
a few selected worthies: the FreeBSD jail(), the Linux
Security Modules (LSM) framework, and Security-Enhanced Linux (SELinux).
FreeBSD jail()
The system call chroot() has a number of problems, as noted
above. For example, it's hard to use correctly, root users can still
escape from it, and it doesn't control network access at all. The FreeBSD
developers decided to add a new system call to counteract these problems,
named jail(). This call is similar to chroot(),
but strives to be both easier to use and more effective. Inside a jail,
all requests (even root's) are limited to the jail, processes can only
communicate with other processes in that jail, and the system blocks
the typical ways root users try to escape from the jail. A jail is assigned
a specific IP address, and can't use any others as its own address.
The jail() call is unique to FreeBSD, which currently
limits its utility. But, there's a lot of cross-pollination between
the various OSS/FS kernels. For example, a version of this jail has
been developed for Linux using the Linux Security Framework. And
FreeBSD 5 has added a flexible MAC framework (from the TrustedBSD
project), including a module with functionality essentially like SELinux's.
So don't be surprised to see more of this in the future.
Linux Security Modules
(LSM)
At the 2001 Linux Kernel Summit, Linus Torvalds had a problem. Several
different security projects, including the Security-Enhanced Linux (SELinux)
project, had asked him to add their security approach to the Linux kernel.
Problem was, these different approaches were often incompatible. Torvalds
didn't have an easy way to determine which was best, so instead he asked
the projects to work together to create some sort of general security
framework for Linux. That way, administrators could install whichever
security approach they wanted on their particular system. After some
discussion with Torvalds, Crispin Cowan formed a group to create a general
security framework. This framework was named the Linux Security Modules
(LSM) framework, and is now part of the standard Linux kernel (as of
kernel version 2.6).
Conceptually, the LSM framework is very simple. The Linux kernel
still does its normal security checks; for example, if you want to write
to a file, you still need write permission to it. However, any time
that the Linux kernel needs to decide if access should be granted, it
also checks -- asks a security module via a "hook" -- to determine whether
or not the action is okay. This way, an administrator can simply pick
the security module he wants to use and insert it like any other Linux
kernel module. From then on, that security module decides what's allowed.
The LSM framework was designed to be so flexible that it can implement
many different kinds of security policies. In fact, several different
projects worked together to make sure that the LSM framework is sufficient
for real work. For example, the LSM framework includes several calls
when internal objects are created and deleted -- not because those operations
might get stopped, but so that the security module can keep track of
critical data. Several different analysis tools have been used to make
sure that the LSM framework didn't miss any important hooks for its
purposes. This project turned out to be harder than many imagined, and
its success was hard-won.
The LSM made a fundamental design decision that's worth understanding.
Fundamentally, the LSM framework was intentionally designed so that
almost all of its hooks would be restrictive, not authoritative. An
authoritative hook makes the absolute final decision: if the hook
says a request should be granted, then it's granted no matter what.
In contrast, a
restrictive hook can only add additional restrictions; it can't
grant new permissions. In theory, if all LSM hooks were authoritative,
the LSM framework would be more flexible. One hook, named capable(),
is authoritative -- but only because it it has to be to support normal
POSIX capabilities. But making
all the hooks authoritative would have involved many radical changes
to the Linux kernel, and there was doubt that such changes would be
accepted.
There were also many concerns that even the smallest bugs would be
disastrous if most hooks were authoritative; while making the hooks
restrictive meant that users would be unsurprised (no matter what, the
original UNIX permissions would still normally work). So the LSM framework
developers intentionally chose the restrictive approach, and most of
its developers decided that they could work within the framework.
It's important to understand some of the LSM framework's other limitations,
too. The LSM framework is designed to support only access control, not
other security issues such as auditing. By themselves LSM modules can't
log all requests or their results, because they won't see them all.
Why? One reason is because the kernel might reject a request without
even calling an LSM module; a problem if you wanted to audit the rejection.
Also, due to concerns about performance, some proposed LSM hooks and
data fields for networks were rejected for the mainline kernel. It's
possible to control some network accesses, but it's not enough to support
"labelled" network flows (where different packets have different security
labels handled by the operating system). These are unfortunate limitations,
and not fundamental to the general idea; hopefully the LSM framework
will be extended someday to eliminate these limitations.
Still, even with these limitations, the LSM framework can be very
useful for adding limits to privileges. Torvalds' goals were essentially
met by the LSM framework: "I'm not interested in the fight between different
security people. I want the indirection that gets
me out of that picture, and then the market can fight out which
policy and implementation actually ends up getting
used."
So, if you want to limit the privileges you give your programs on
Linux, you could create your very own Linux security module. If you
want to impose truly exotic limitations, that may be necessary -- and
the nice thing is that it's possible. However, this isn't trivial; no
matter what, you're still writing kernel code. If possible, you're better
off using one of the existing Linux security modules than trying to
write your own. There are several LSM modules available, but one of
the most mature of the Linux security modules is the Security-Enhanced
Linux (SELinux) module, so let's look at that.
Copyright © 1996-2009 by Dr. Nikolai Bezroukov.
www.softpanorama.org was
created as a service to the UN Sustainable Development Networking Programme (SDNP)
in the author free time.
Submit
comments This document is an industrial compilation designed and created
exclusively for educational use and is placed under the copyright of the
Open Content License(OPL).
Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made
for educational purposes only in compliance with the fair use doctrine.
Disclaimer:
- The statements, views and opinions presented on
this web page are those of the author and are not endorsed by, nor do they necessarily
reflect, the opinions of the author present and former employers, SDNP or any other
organization the author may be associated with.
- We do not warrant the correctness of the information provided or its
fitness for any purpose
- In no way this site is associated with or endorse cybersquatters
using
the term "softpanorama" with other main or country domains (e.g. softpanorama.com) with
bad faith intent to profit from the goodwill belonging to
someone else.
Last modified:
August 12, 2009