Wednesday Nov 04, 2009

NEW: Solaris 10 Security Deep Dive Presentation

Today, I am very happy to announce the availability of a new Solaris 10 Security Deep Dive training. This version has been updated for Solaris 10 10/2009 (also known as Update 8). From a security perspective, there have only been a few updates since my last posted version, but it is always good to be current. Items added in this new version include: ZFS user and group quotas, ZFS pre-defined ACL sets, NTPv4, and nss_ldap shadowAccount support. In addition, there was a bit of cleanup throughout and a new example was added for Trusted Extensions.

As usual, I have made this content available in both OpenDocument Format (ODF) and PDF. If you are using Microsoft Office, you can use the Sun MS Office ODF Plugin to read the source document.

For those of you who have downloaded one of the previous versions, thank you! There have been nearly 8,000 downloads of this presentation so far! If you have not had a chance, I would encourage you to download and check out a copy today. It is really amazing how many new and updated security features and capabilities there are in Solaris 10. If you have been away from Solaris (even Solaris 10) for a while, I am sure you will be shocked with what you can do today! As always, feedback is greatly appreciated!

Take care!

Glenn

Technorati Tag:

Monday Jun 15, 2009

NEW: Solaris 10 Security Deep Dive Presentation

It has sure been a busy month and really it has just begun. Today, I am happy to announce the availability of my Solaris 10 Security Deep Dive presentation, updated for the just released Solaris 10 05/2009 (Update 7). From a security perspective, there have only been a few updates since my last posted version, for Solaris 10 10/2008 (Update 6), but it is always good to be current. Of particular interest is a new slide focused on IPsec and IKE. As usual, I have made this content available in both OpenDocument Format (ODF) and PDF. If you are using Microsoft Office, you can use the Sun MS Office ODF Plugin to read the source document.

For those of you who have downloaded one of the previous versions, thank you! There have been nearly 5,000 downloads of this presentation so far! If you have not had a chance, I would encourage you to download and check out a copy today. It is really amazing how many new and updated security features and capabilities there are in Solaris 10. If you have been away from Solaris (even Solaris 10) for a while, I am sure you will be shocked with what you can do today! As always, feedback is greatly appreciated!

Take care!

Glenn

Technorati Tag:

Friday Feb 13, 2009

Solaris Security Chat in SecondLife

Virtual Glenn is a pretty strange concept, but for those who can move past it, check this out! This is a picture of my SecondLife avatar in front of the Solaris Campus stage. On February 24th, 2009 at 9 AM PT / 12 PM ET, I will be participating in an expert chat that will be loosely based around my blog article titled Top 5 Solaris 10 Security Features You Should Be Using. I will be talking a bit about each of the five items as well as answering questions. In total, the event will last about an hour and should be a lot of fun (assuming I can overcome being a SecondLife n00b!)

This will be my first presentation inside of a virtual world, and I would encourage anyone who is interested to get a login, a copy of the client, and join me on the 24th to have a little fun a world away. For more information, check out the Sun Virtual Worlds posting for the event! Hope to see you there!

Wednesday Dec 10, 2008

mod_privileges for Apache HTTPD

Special thanks to Matt Ingenthron for pointing out that mod_privileges has been integrated back in the Apache trunk (manual) recently. For more information check out NIQ's Soapbox posting on the subject.

Looks like I will have to find a new target (I am looking at you MySQL!) for my BluePrints. I have used the Apache with SMF privileges example in a few publications including Limiting Service Privileges in the Solaris 10 Operating System (2005) and Privilege Debugging in the Solaris 10 Operating System (2006). The content of these papers is still relevant in the general sense, but with the introduction of mod_security, some of this content will no longer be as useful for Apache. That said, lots of other services can and do benefit from the techniques described.

If you find yourself ever wanting to do something similar - converting your services to be privilege aware on Solaris 10, check out the Sun BluePrints article Privilege Bracketing in the Solaris 10 Operating System (2006). Also, check out the OpenSolaris Security Community project on Privilege Debugging as it can help you in finding out what privileges your programs and services need.

Until next time!

Glenn

Technorati Tag:

Friday Nov 14, 2008

NEW: Solaris 10 Security Deep Dive Presentation

It must be that time of year again. At Sun's Customer Engineering Conference this year, I unveiled the latest update to my Solaris 10 Security Deep Dive Presentation. This version has been updated based upon Solaris 10 10/08 (Update 6) which means it is in sync with the most recently shipping version of Solaris 10. This version is in OpenDocument Format. Should you want a PDF version, you can use this copy.

The last update that I had posted was downloaded more than 2,000 times. That is a great number for such a specialized and technical topic. With all of these downloads, however, I have yet to hear from you! Please be sure to send along your feedback! I am particularly interested in things like:

  • Does the content meet your needs? How can it be improved?
  • What are your security requirements not met today by Solaris 10? What is your wish list?
  • Is their content where you would like more detailed information (e.g., a BluePrint)?

As I said in my last Solaris 10 Security Update... If you have not taken a look into what Solaris 10 can offer recently, you really must give it a look! Also, be on the look out for a posting very soon on a project called Immutable Service Containers. With that as a teaser, I will sign off for today... Take care!

Glenn

Technorati Tag:

Tuesday Apr 25, 2006

I see you! snoop(1M)'ing in non-global zones!

Dear diary... It has been quite a while since my last posting...

While I have not posted very much to my blog lately, I have been quite busy writing. In fact, since February, the following Sun BluePrints articles have been published:

Today's article talks about how to enable snoop(1M) in a non-global (or local) zone. In Solaris 10 today, the ability to use the snoop(1M) command or any other packet sniffer for that matter is restricted to the global zone. There is no way to snoop traffic from within a zone. Enter the Configurable Privileges for Zones project which integrated into Nevada build 37 and of course is available in OpenSolaris today.

Using this project and a little device manipulation, you can today get snoop working in a non-global zone, and here is how to do it... But first, a few warnings:

WARNING #1: This approach will allow the local zone to see all of the network traffic associated with the device that is added. Unless you use separate network interfaces for the global zone and other non-global zones, this means that following these instructions will allow a zone to see traffic intended for or exchanged with another zone.

WARNING #2: This approach is likely not generally recommended. This is meant only as an illustration of what can be done and may serve as a useful workaround in some environments until a more recommended, secure and supportable solution is available.

With that out of the way, let's give it a try!

First, you must configure your zone to include the net_rawaccess privilege. This is done using a new zonecfg(1M) parameter, limitpriv. In the following example, we will assume that we have previously created and installed a non-global zone, called test. To add the new net_rawaccess privilege, simply use the following command:

# zonecfg -z test
zonecfg:test> set limitpriv=default,net_rawaccess
zonecfg:test> exit
Next, let's boot up the zone and check that the privilege has been successfully added:

# zoneadm -z test boot
# zlogin test
[Connected to zone 'test' pts/5]
Last login: Mon Apr 24 23:49:15 on pts/5
Sun Microsystems Inc.   SunOS 5.11      snv_38  October 2007
# ppriv $$
4547:   -sh
flags = 
        E: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
        I: basic
        P: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
        L: basic,contract_event,contract_observer,file_chown,file_chown_self,file_dac_execute,
           file_dac_read,file_dac_search,file_dac_write,file_owner,file_setid,ipc_dac_read,
           ipc_dac_write,ipc_owner,net_bindmlp,net_icmpaccess,net_mac_aware,net_privaddr,
           net_rawaccess,proc_audit,proc_chroot,proc_owner,proc_setid,proc_taskid,sys_acct,
           sys_admin,sys_audit,sys_mount,sys_nfs,sys_resource
Technically speaking what comes next is likely not recommended, but it does work and can help you out in a pinch if you need to get this functionality working in a non-global zone until a more recommended method becomes available.

In order to get snoop working in a non-global zone, you must also introduce the network devices into the zone. The following commands must be executed from the global zone and are representative only (based on my system's configuration). The actual command you should use will vary (based on the actual interface name and the major/minor numbers of the device.

On my system, the network interface name is nge0. My first goal is to determine the major and minor device number associated with the network interface:

# ls -l /dev/nge0
lrwxrwxrwx   1 root     root          38 Apr 21 10:02 /dev/nge0 -> ../devices/pci@0,0/pci108e,5347@a:nge0
# ls -l /devices/pci@0,0/pci108e,5347@a:nge0
crw-rw-rw-   1 root     root      96,  1 Apr 22 10:46 /devices/pci@0,0/pci108e,5347@a:nge0
With this information, we can now create the network device in the non-global zone:
# zonecfg -z test info zonepath
zonepath: /my/zones/test
# cd /my/zones/test/dev
# mknod nge0 c 96 1
# ls -l nge0
crw-r--r--   1 root     root      96,  1 Apr 25 13:00 nge0
All the hard work is now done. With the privilege and device added to the zone, you can now use snoop!

# snoop -d nge0
Using device /dev/nge0 (promiscuous mode)
192.168.1.11 -> test         TCP D=22 S=62991 Syn Seq=2109859625 Len=0 Win=49640 Options=
      test   -> 192.168.1.11 TCP D=62991 S=22 Syn Ack=2109859626 Seq=377273646 Len=0 Win=49640 Options=
192.168.1.11 -> test         TCP D=22 S=62991 Ack=377273647 Seq=2109859626 Len=0 Win=49640
      test   -> 192.168.1.11 TCP D=62991 S=22 Push Ack=2109859626 Seq=377273647 Len=20 Win=49640
Voila! Piece of cake! Just use this tip with caution as you do not inadvertantly want to expose yourself. Peek-a-boo! I'll see you (later!)

Take care,

g

Technorati Tag:

Saturday Feb 11, 2006

Try it for yourself: Solaris 10 Privilege Debugging

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

Technorati Tag:

Tuesday Jun 14, 2005

Privilege Enabling Set-ID Programs: Part 2

Previously, we talked about how the ping program was modified in Solaris 10 to be privilege aware.  During that discussion, it was noted that the functions used in the ping program were private to the OpenSolaris ON (OS and Networking) consolidation.  While this is fine for programs like ping that reside in that consolidation, it does not offer a solution to programs in other consolidations or for those developed external to OpenSolaris.  As a companion to that article, let's now discuss how we can adapt ping.c to use the public privilege manipulation functions yet still accomplish the same result - making the program privilege-aware and implementing bracketing around privileged operations.

Without further ado, let's just dive into the code.  By way of convention, I will be showing only the changes that need be implemented to covert the original ping.c program to use the new public functions.

The first thing that you will notice is that a different header file is used.  If you want to use the public interfaces, then you should be sure to include priv.h and not priv_utils.h:

72c72
< #include <priv_utils.h>
---
> #include <priv.h>

Next, we move to the section of the code that configured the privilege sets at the start of the program.  This was done in order to drop any privileges that were not needed and disable those that were left (and not needed right now).  This was originally accomplished using the __init_suid_priv function which provided a convenient wrapper for the functionality described below.  Rather than a single line, we need to do a little more work.  To make the code easier to follow, a new function, setup_privs, was created to do the initial privilege operations.  This handles the majority of the work originally done by __init_suid_priv.  This code is fairly well documented, so I will not go into too much detail as to what it does.

225a226
> static priv_set_t \*setup_privs(void);
227a229,298
>  \* setup_privs()
>  \*/
> priv_set_t \*
> setup_privs(void)
> {
>     priv_set_t \*pPrivSet = NULL;
>     priv_set_t \*lPrivSet = NULL;
>
>     /\*
>      \* Start with the 'basic' privilege set and then remove any
>      \* of the 'basic' privileges that will not be needed by this
>      \* process.  The 'net_icmpaccess' privilege will be added
>      \* since we know that we will need it for the permitted set.
>      \*/
>
>     if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
>             perror("priv_str_to_set");
>             return (NULL);
>     }
>
>     /\*
>      \* Let's clear all of the privileges we know we will not
>      \* need from the 'basic' set.
>      \*/
>
>     (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
>     (void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
>     (void) priv_delset(pPrivSet, PRIV_PROC_FORK);
>     (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
>     (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
>
>     /\* Next add the known required privilege, 'net_icmpaccess' \*/
>
>     (void) priv_addset(pPrivSet, PRIV_NET_ICMPACCESS);
>
>     /\* Set the permitted privilege set. \*/
>
>     if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
>             perror("setppriv(PRIV_SET, PRIV_PERMITTED)");
>             return (NULL);
>     }
>
>     /\* Ensure that the 'net_icmpaccess' privilege is off by default. \*/
>
>     if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS,
>             NULL) != 0) {
>             perror("priv_set(PRIV_OFF, PRIV_EFFECTIVE)");
>             return (NULL);
>     }
>
>     /\* Clear the limit set. \*/
>
>     if ((lPrivSet = priv_allocset()) == NULL) {
>             perror("priv_allocset");
>             return (NULL);
>     }
>
>     priv_emptyset(lPrivSet);
>
>     if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
>             perror("setppriv(PRIV_SET, PRIV_LIMIT)");
>             return (NULL);
>     }
>
>     priv_freeset(lPrivSet);
>
>     return (pPrivSet);
> }
>
> /\*

So, why do we go through the process of starting with the basic set of privileges and removing them all?  Why not just start out with no privileges and simply the code?  The answer lies in the fact that the basic privilege set is not intended to be static.  Over time additional non-administrative privileges may be added.  If you started with simply no privileges, then you may find that your code will fail as it will need a privilege for an operation that previously did not require one.  In essence, this is a way of future-proofing your code so that it can better adapt to changes in Solaris down the road.

So at this point, we have defined a function that will help minic most of the behavior that had been done by __init_suid_priv.  Let's take a look at how this function is used:

243a315
>     priv_set_t \*privSet = NULL;
252,253d323
<     (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
<         (char \*)NULL);
254a325,337
>     if ((privSet = setup_privs()) == NULL) {
>             exit(EXIT_FAILURE);
>     }
>
>     /\*
>      \* Reset the real and effective UIDs for this process.
>      \*/
>
>     if (setreuid(getuid(), getuid()) != 0) {
>             perror("setreuid");
>             exit(EXIT_FAILURE);
>     }
>

As you can see, the __init_suid_priv call has been replaced by calls to both setup_privs and setreuid(2) functions.  This is a fairly simple replacement since all of the "hard work" was done in the setup_privs function.  We capture the privilege set parameter, privSet, as we will need it later in the code when it comes time to relinquish our privileges.  Let's continue sequentially down the code to see where other replacements are needed.  Frankly, the hard part is over.  The rest of the changes needed to complete the conversion from private to public privilege manipulation functions are trivial.  Let's take a look at the next replacement:

602c685,687
<     __priv_relinquish();
---
>     /\*
>      \* Clear the permitted set of the 'net_icmpaccess' privilege.
>      \*/
603a689,696
>     (void) priv_delset(privSet, PRIV_NET_ICMPACCESS);
>
>     if (setppriv(PRIV_SET, PRIV_PERMITTED, privSet) != 0) {
>             perror("setppriv(PRIV_PERMITTED)");
>             exit(EXIT_FAILURE);
>     }
>     priv_freeset(privSet);
>

In this case, we are replacing the __priv_relinquish function with a call to setppriv(2).  Before we can do this however, we need to remove the net_icmpaccess privilege from privSet using the priv_delset function.  Remember that privSet (returned to us from setup_privs earlier in the code) contains the privileges from the basic set that we had not already dropped as well as the net_icmpaccess privilege.  By removing the net_icmpaccess privilege, setppriv will set to the process' permitted privilege set to the non-dropped basic privileges (which in this particular case is none although as Solaris continues to evolve and new non-administrative privileges are added, this may change).

Moving along to the next section of replacement code, we come to where the bracketing of the net_icmpaccess privilege is enforced.  In thiscase, the call to __priv_bracket is replaced with a call to priv_set(3C) function.  priv_set is called with the PRIV_ON parameter which enables the net_icmpaccess privilege for the process' effective privilege set.

1197c1290,1293
<     (void) __priv_bracket(PRIV_ON);
---
>     if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS, NULL) != 0) {
>             perror("priv_set(PRIV_ON, PRIV_EFFECTIVE)");
>             exit(EXIT_FAILURE);
>     }

Similarly, the companion instance of __priv_bracket is replaced with another call to priv_set once the privileged operations are complete to remove the net_icmpaccess privilege (from the process' effective privilege set) - therefore completing the bracketing of privilege.

1208c1304,1308
<     (void) __priv_bracket(PRIV_OFF);
---
>     if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_ICMPACCESS,
>             NULL) != 0) {
>             perror("priv_set(PRIV_OFF, PRIV_EFFECTIVE)");
>             exit(EXIT_FAILURE);
>     }

That is all there is to it.  As you can tell, there is a bit more work in the initial setup of a process' privilege sets, but once that is complete, the use of the public privilege manipulation functions is straightforward.  I know that this helps to illustrate how you can privilege enable your code whether you choose to use ON specific functions or the public ones defined in the Solaris product documentation.  For those who just can't get enough, check out Joep Vesseur's discussion of several developer-focused security enhancements in Solaris 10 (and OpenSolaris).

Last, but certainly not least, I would like to offer my sincere thanks to Casper, Joep and Darren for their help with this article.  You guys are the best!

Take care and have fun!

Technorati Tag:

Privilege Enabling Set-ID Programs

There have been quite a few posts, articles,and resources made available discussing the new process privilege model introduced the Solaris 10 operating system. The majority of them have focused on describing what this new privilege model is, why it is useful and how it can be used through mechanisms such as Solaris RBAC, SMF, and ppriv(1). Today, with the launch of OpenSolaris, I feel the urge to discuss privileges from the view of a software developer (not that I am one anymore, but please indulge me a bit).  If you are interested in this kind of thing, you can find more information about this in the Solaris 10 product documentation.

Today, let's look at a how a developer could develop a program to be privilege aware. In particular, for our example, let's take a set-id program and configure it such that it:

  1. drops any privileges that it will never need;
  2. enables the remaining privileges exactly when it needs them;
  3. relinquishes the use of privileges when they are no longer needed

Sounds pretty straight forward, right? Essentially, we just want to ensure that a program is only running with those privileges that it needs, and it activates those privileges only when it needs them. To illustrate this concept, let's take a look at ping.c. This program was converted to use Solaris privileges by Casper Dik way back in 2003. I chose to use it for this example because:

  1. the ping(1M) source code is simple and straightforward to read and understand, and
  2. all of the changes needed to make it privilege aware were contained in one file

There is nothing special about ping with respect to privileges and the same techniques described below could be applied to other programs whether they are set-id or not.

So, let's begin this tale back in February of 2003 before the ping command was made privilege aware. In those days, ping was a set-uid root program that controlled its use of privilege using seteuid(2). When the program started as root, it quickly set its effective UID to the UID of the calling user to run with less privilege. When it came time to execute a privileged operation, the code issued another seteuid call that reset its EUID to root so that the privileged operation could succeed.

With the introduction of process privileges in Solaris 10, this model was no longer needed. Rather than executing code as EUID 0, specific privileges are used to define the types of privileged operations that are be permitted. This is a huge step forward as privilege aware programs will now run only with the privileges that they need (exactly when they need them). So, enough of the fluff, let's get to the code! Note that all of the following code examples were taken from ping.c.

The first thing that you will notice that if you want to configure a program to be privilege aware, you will need to include a new header that will declare functions and define constants used by the privilege functions described below:

     72    #include <priv_utils.h>

With the header out of the way, we move into main where the first thing that we do is drop all of the privileges that we do not need:

    247         /\*
    248          \* This program needs the net_icmpaccess privileges.  We'll fail
    249          \* on the socket call and report the error there when we have
    250          \* insufficient privileges.
    251          \*/
    252         (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
    253             (char \*)NULL);

Remember that ping is still set-uid root. This means that when it is started, it will have the privileges that have been assigned to root which by default is all. The purpose of the __init_suid_priv function is to do the following (described in priv_utils.h):

     48 /\*
     49  \* Should be run at the start of a set-uid root program;
     50  \* if the effective uid == 0 and the real uid != 0,
     51  \* the specified privileges X are assigned as follows:
     52  \*
     53  \* P = I + X + B (B added insofar allowable from L)
     54  \* E = I
     55  \* (i.e., the requested privileges are dormant, not active)
     56  \* Then resets all uids to the invoking uid; no-op if euid == uid == 0.
     57  \*
     58  \* flags: PU_LIMITPRIVS, PU_CLEARLIMITSET, PU_CLEARINHERITABLE
     59  \*
     60  \* Caches the required privileges for use by __priv_bracket().
     61  \*
     62  \*/

So this function (as used in the ping.c code) will reset the real and effective UID of the process to that of the calling user so that it is no longer running as root.  Further, it will clear the limit set of the process which means that any children spawned by this process will themselves have no privileges.  Lastly, this function will also add the net_icmpaccess privilege to the process' permitted set so that it can be enabled and used when necessary.  The process' four privilege sets (effective, inheritable, permitted and limit) will look like this:

# ppriv -S `pgrep ping`
14527: ping localhost
flags = PRIV_AWARE
E: basic
I: basic
P: basic,net_icmpaccess
L: none

According to ppriv, the net_icmpaccess privilege is used to allow a process to send and receive ICMP packets:

$ ppriv -lv net_icmpaccess
net_icmpaccess
Allows a process to send and receive ICMP packets.

So rather than having the potential to access all of root's power, a ping process will now run as the calling user's UID with a single (non-basic) privilege that allows the sending or receiving ICMP packets.  Sounds great, but we are not done yet!  In priv_utils.h, you will find more instruction as to how to proceed:

     65 /\*
     66  \* After calling __init_suid_priv we can __priv_bracket(PRIV_ON) and
     67  \* __priv_bracket(PRIV_OFF) and __priv_relinquish to get rid of the
     68  \* privileges forever.
     69  \*/

Recall that before ping was made privilege aware, it used seteuid to control when its privileges were in effect. This was necessary for the program to only run in a privileged capacity when it needs to execute privileged operations. In the new model, the process leverages a capability called privilege bracketing which controls when a privilege (defined in the process' permitted set) is made effective. To see this capability in action, take a look at the following code which appears in the setup_socket function:

   1196         /\* now we need the net_icmpaccess privilege \*/
   1197         (void) __priv_bracket(PRIV_ON);
   1198
   1199         recv_sock = socket(family, SOCK_RAW,
   1200             (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
   1201
   1202         if (recv_sock < 0) {
   1203                 Fprintf(stderr, "%s: socket %s\\n", progname, strerror(errno));
   1204                 exit(EXIT_FAILURE);
   1205         }
   1206
   1207         /\* revert to non-privileged user after opening sockets \*/
   1208         (void) __priv_bracket(PRIV_OFF);

As you can see, the __priv_bracket function is used around the privileged operation (in this case the socket(2) call) to control whether or not the instructions are executed with privilege. This is one form of privilege bracketing that enables and disables all of the privileges cached by the __init_suid_priv function called earlier in the program (and described above). There are other privilege manipulation functions available to allow more fine grained control if needed.

Our final step is to relinquish the privileges when we are sure that we will no longer need them:

    602         __priv_relinquish();

The __priv_relinquish function is called after the setup_socket function has completed in main. Since the program will no longer need the net_raw_icmpaccess privilege (the only non-basic privilege available to the process), it can now be safely dropped. The __priv_relinquish function is used for just this purpose. Note that once a privilege is relinquished, it is gone. If you think that you may need the privilege later in the program, you should simply disable its use (removing it from the process' effective set) until you need it again.

That's all there is to it.  Pretty cool, eh?

One thing that I should mention, however.  In the development of this article, I was reminded by Darren Moffat that the privilege functions and header file described above are private to Solaris (and more specifically the ON [OS and Networking] consolidation).  So, the approach described above will work just fine if you are modifying set-id programs in ON such as atq, atrm, traceroute, lpstat, and the like.  If you want to make other programs privilege aware, you can do this using a set of privilege manipulation functions described in the Solaris 10 product documentation. Regardless of the method you use, however, there should be nothing to stop you from improving your code by making your programs privilege aware and bracketing privileged operations.

Take care and have fun!

Technorati Tag:

Friday Sep 24, 2004

How to Limit Display of Other User's Processes

This entry is a continuation of my list of lesser known and/or publicized security enhancements to the Solaris 10 OS. In this update, I will be talking about how to restrict the output of the ps(1) command such that users can only see processes that they own. This is a very useful capability especially for ISPs and other organizations that do not want to allow users to see what other users are doing.

This new feature would not have been possible without the introduction of process privileges into the Solaris 10 OS. For a great overview of process privileges, see Casper Dik's blog entry on this topic. Be sure to read his article to get a more in depth understanding of process privileges.

So, before we begin, let's see what the output of ps -aef might look like for an average user (in this case, gmb):

$ ps -aef
     UID   PID  PPID   C    STIME TTY         TIME CMD
    root     0     0   0   Sep 23 ?           0:07 sched
    root     1     0   0   Sep 23 ?           0:01 /sbin/init
    root     2     0   0   Sep 23 ?           0:00 pageout
    root     3     0   0   Sep 23 ?           2:31 fsflush
    root   393     1   0   Sep 23 ?           0:00 /usr/sbin/auditd
    root     7     1   0   Sep 23 ?           0:11 /lib/svc/bin/svc.startd
    root     9     1   0   Sep 23 ?           0:19 svc.configd
    root   176     1   0   Sep 23 ?           0:00 /usr/sbin/syslogd
    root    64     1   0   Sep 23 ?           0:00 /usr/sbin/nscd
  daemon    91     1   0   Sep 23 ?           0:02 kcfd
    root   170     1   0   Sep 23 ?           0:01 /usr/lib/utmpd
     gmb  1795  1792   0 22:17:26 pts/1       0:00 -sh
    root  1527     7   0 00:53:24 console     0:00 /usr/bin/login
    root    82     1   0   Sep 23 ?           0:00 /usr/lib/sysevent/syseventd
   smmsp   334     1   0   Sep 23 ?           0:00 /usr/lib/sendmail -Ac -q15m
  daemon   137     1   0   Sep 23 ?           0:06 /usr/sbin/rpcbind
    root    84     1   0   Sep 23 ?           0:00 /usr/lib/picl/picld
    root  1601  1527   0 07:36:19 console     0:00 -sh
    root   181     1   0   Sep 23 ?           0:04 /usr/lib/inet/inetd start
    root   281     1   0   Sep 23 ?           0:00 /usr/lib/nfs/mountd
    root   187     1   0   Sep 23 ?           0:00 /usr/sbin/cron
    root  1402     1   0 00:26:14 ?           0:00 /usr/lib/ssh/sshd
  daemon   289     1   0   Sep 23 ?           0:00 /usr/lib/nfs/nfsd
  daemon   264     1   0   Sep 23 ?           0:00 /usr/lib/nfs/statd
    root   303     1   0   Sep 23 ?           0:00 /usr/lib/fm/fmd/fmd
  daemon   268     1   0   Sep 23 ?           0:00 /usr/lib/nfs/lockd
    root   291     1   0   Sep 23 ?           0:00 /usr/lib/autofs/automountd
     gmb  1799  1795   0 22:17:28 pts/1       0:00 ps -aef
    root  1789   181   1 22:17:19 ?           0:00 /usr/sbin/in.telnetd
    root  1792  1789   1 22:17:19 pts/1       0:00 login -p -h 10.1.1.100 -d /dev/pts/1
    root   335     1   0   Sep 23 ?           0:06 /usr/lib/sendmail -bd -q15m
  daemon   296     1   0   Sep 23 ?           0:00 /usr/lib/nfs/nfsmapid

As you can see, the gmb user can see not only his processes but also those of the root, daemon, and smmsp accounts. We can change this behavior either globally or on a per-user basis. Just as we discussed in the Solaris 10 Account Lockout entry, we can use user-specific changes to force a subset of users to comply with some policy or use the user-specific changes to make exceptions for those users. The flexibility of this format allows it to be adapted quite easily to the needs of many organizations.

For our first example, we will illustrate how the global change can be made. So do this, we must edit the /etc/security/policy.conf file, uncomment the PRIV_DEFAULT entry and set its value as follows:

PRIV_DEFAULT=basic,!proc_info

For those not familiar with the proc_info privilege, you can find more information about it using the ppriv(1) command:

# ppriv -l -v proc_info
proc_info
        Allows a process to examine the status of processes other
        than those it can send signals to.  Processes which cannot
        be examined cannot be seen in /proc and appear not to exist.

This is all that you need to do to globally configure your Solaris 10 system so that users will only be able to see processes that they own. Note that this will obviously not apply to root who by default has all privileges or to other users or processes that have been explicitly given the proc_info privilege. Regardless, it is still a very quick and effective way to limit what processes users may see.

Returning to the gmb account example, I re-login to the system and again run the ps -aef command, but this time I receive different results:

$  ssh -l gmb sampleHost
gmb@sampleHost's password:
Last login: Fri Sep 24 22:25:18 2004 from 10.1.1.100
Sun Microsystems Inc.   SunOS 5.10      s10_67  May 2004
$ ps -aef
     UID   PID  PPID   C    STIME TTY         TIME CMD
     gmb  1823  1819   0 22:30:17 pts/1       0:00 ps -aef
     gmb  1819  1815   0 22:30:14 pts/1       0:00 -sh
$

As you can see, the gmb user may now only see his own processes. Way cool. Next, to illustrate the per-user configuration ability, I will leave this global configuration in place and use the per-user configuration ability to allow the gmb user to view processes owned by other users. This is just an example of how exceptions can be implemented. The same process could be used to enable this feature for just a user or subset of users on the system.

To accomplish this task, we go back to the user_attr(4) file. In this file, we will modify the existing entry for the gmb user (or create one if one had not already been there). The following example illustrates the change that needs to be made. Specifically you need to add the defaultpriv entry to specify the default list of privileges that will be available to this user. By modifying this parameter, you will change the default set of privileges available to a user (by either adding or removing privileges as needed.) In this case, we are returning the user's default set of privileges to basic from basic,!proc_info.

gmb::::lock_after_retries=no;defaultpriv=basic

So, let's see if this really works. In the following example, we will confirm the configuration of the system, login to the system as the gmb user, and run the ps -aef command to verify that the gmb user can see processes owned by other users.

# grep "\^PRIV_DEFAULT=" /etc/security/policy.conf
PRIV_DEFAULT=basic,!proc_info
# grep "\^gmb:" /etc/user_attr
gmb::::lock_after_retries=no;defaultpriv=basic
# ssh -l gmb localhost
Password:
Last login: Fri Sep 24 22:37:55 2004 from 10.1.1.100
Sun Microsystems Inc.   SunOS 5.10      s10_67  May 2004
$ id -a
uid=100(gmb) gid=1(other) groups=1(other)
$ ps -aef
     UID   PID  PPID   C    STIME TTY         TIME CMD
    root     0     0   0   Sep 23 ?           0:07 sched
    root     1     0   0   Sep 23 ?           0:01 /sbin/init
    root     2     0   0   Sep 23 ?           0:00 pageout
    root     3     0   0   Sep 23 ?           2:33 fsflush
    root   393     1   0   Sep 23 ?           0:00 /usr/sbin/auditd
    root     7     1   0   Sep 23 ?           0:11 /lib/svc/bin/svc.startd
    root     9     1   0   Sep 23 ?           0:19 svc.configd
    root   176     1   0   Sep 23 ?           0:00 /usr/sbin/syslogd
    root    64     1   0   Sep 23 ?           0:00 /usr/sbin/nscd
  daemon    91     1   0   Sep 23 ?           0:02 kcfd
    root   170     1   0   Sep 23 ?           0:01 /usr/lib/utmpd
    root  1900  1402   7 22:42:05 ?           0:02 /usr/lib/ssh/sshd
    root  1527     7   0 00:53:24 console     0:00 /usr/bin/login
    root    82     1   0   Sep 23 ?           0:00 /usr/lib/sysevent/syseventd
   smmsp   334     1   0   Sep 23 ?           0:00 /usr/lib/sendmail -Ac -q15m
  daemon   137     1   0   Sep 23 ?           0:06 /usr/sbin/rpcbind
    root    84     1   0   Sep 23 ?           0:00 /usr/lib/picl/picld
    root  1601  1527   0 07:36:19 console     0:00 -sh
    root   181     1   0   Sep 23 ?           0:04 /usr/lib/inet/inetd start
    root   281     1   0   Sep 23 ?           0:00 /usr/lib/nfs/mountd
    root   187     1   0   Sep 23 ?           0:00 /usr/sbin/cron
    root  1402     1   0 00:26:14 ?           0:00 /usr/lib/ssh/sshd
  daemon   289     1   0   Sep 23 ?           0:00 /usr/lib/nfs/nfsd
  daemon   264     1   0   Sep 23 ?           0:00 /usr/lib/nfs/statd
    root   303     1   0   Sep 23 ?           0:00 /usr/lib/fm/fmd/fmd
  daemon   268     1   0   Sep 23 ?           0:00 /usr/lib/nfs/lockd
    root   291     1   0   Sep 23 ?           0:00 /usr/lib/autofs/automountd
     gmb  1912  1908   0 22:42:12 pts/1       0:00 ps -aef
    root   335     1   0   Sep 23 ?           0:06 /usr/lib/sendmail -bd -q15m
  daemon   296     1   0   Sep 23 ?           0:00 /usr/lib/nfs/nfsmapid
     gmb  1908  1900   0 22:42:10 pts/1       0:00 -sh
    root  1899  1601   6 22:42:05 console     0:02 ssh -l gmb localhost

It worked! That was pretty easy, right? This is just one very small example of how you can use process privileges in your daily lives. I will try to add more interesting examples of practical uses for process privileges in the future.

Before ending, I do want to highlight that while these examples focused on the ps(1) command - other process related commands will also be impacted such as ptree(1), pcred(1), pmap(1), psig(1), etc. Further, as a user running without the proc_info privilege, you will not even be able to see other processes in the /proc directory:

$ id -a
uid=101(foo) gid=1(other) groups=1(other)
$ ppriv $$
1915:   -sh
flags = 
        E: basic,!proc_info
        I: basic,!proc_info
        P: basic,!proc_info
        L: all
$ ls -l /proc
total 4
dr-x--x--x   5 foo      other        832 Sep 24 22:52 1915
dr-x--x--x   5 foo      other        832 Sep 24 22:56 1932

I hope you enjoyed this article and please watch this space for new discussion of Solaris 10 security features. Take care and have a great weekend.

Technorati Tag:

About

gbrunett

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today