Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
HOWTO: Grsecurity quickstarting RBAC roles for Gentoo (x86)
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks
View previous topic :: View next topic  
Author Message
schmeggahead
Guru
Guru


Joined: 25 Feb 2003
Posts: 314
Location: Columbus, Ohio

PostPosted: Sat Jan 30, 2010 10:01 pm    Post subject: HOWTO: Grsecurity quickstarting RBAC roles for Gentoo (x86) Reply with quote

HOWTO: Grsecurity quickstarting RBAC roles for Gentoo (x86) Version 0.3

This guide is primarily addressing the Rule Based Access Control (RBAC) within grsecurity enhancements to the kernel.

The current guide is located here: http://www.gentoo.org/proj/en/hardened/grsecurity.xml
The current wiki book for the roles definition is here: http://en.wikibooks.org/wiki/Grsecurity/The_RBAC_System
Note: the wikibook is extensive but it is not obvious how to access various values in the RBAC policy statement. There are links to the value lists but they are not in the table of contents. Inside the "complete formal definition", click on these words to see valid values:
  • role mode
  • subject mode
  • object mode
  • capability name
  • resource name
  • pax flag
  • resource restrictions


I used this guide to bring up several systems and below is a sequence to start up that worked well for me compared to the dozen or so other more difficult routes to a successful grsecurity RBAC capable system with a minimal access policy.

  1. Prepare


      Requirements
    1. use the hardened stage and hardened-sources
    2. installed sys-apps/gradm package (version I used 2.1.13.200902232204-r1)
    3. bootable system
    4. kernel with grsecurity enabled (follow the guide section 3 RBAC) (Note: grsecurity is not enabled by default. However, in the hardened kernel configuration menus, many of the options are force selected once grsecurity is enabled. Reading the help on the few remaining choices is not that onerous)
    5. parts of the standard guide regarding learning roles and sysctl NOT completed

      So what you have now is a system that is booting with grsecurity enabled in the kernel but the RBAC system is off.


  2. Setup Passwords and Startup Learning

    1. Set your password for the RBAC system. Ensure this is a ridiculously hard password on a production system. On my dev system I make this easy because it is protected and not web accessible and wiped regularly.

      Code:
      #/sbin/gradm -P


    2. set your admin password:
      Code:
      #/sbin/gradm -P admin


      Note: I like to set an admin password and roles for admin that are more a decoy than the real admin role I use. I name my admin role something like omni and give it the rules admin normally receives. This means that even if the admin password is hacked, they cannot transition to another role and waste their time hacking that, hopefully leaving a trail in /var/log/kern.log such as:
        Jan 30 10:55:32 localhost kernel: [75498.299128] grsec: From 192.168.0.3: (root:U:/sbin/gradm) special role admin failure for /sbin/gradm[gradm:9324] uid/euid:0/0 gid/egid:0/0, parent /bin/bash[bash:8846] uid/euid:0/0 gid/egid:0/0


    3. set the init script to start gradm at startup:
      Code:
      #nano -w /etc/conf.d/local.start

      then insert the bottom two lines:
      Code:
      # /etc/conf.d/local.start

      # This is a good place to load any misc programs
      # on startup (use &>/dev/null to hide output)
      /sbin/gradm -F -L /gradm.initial.learning.log
      #/sbin/gradm -E


      we'll come back to this setup down further

      Note: I did create an init script for init.d and conf.d companion but since this is not a daemon using start-stop-daemon is totally overkill and local.start & local.stop work better. (thanks Hopeless!) I filed a bug report to have local.start local.stop added to the initscript doc in the handbook.

    4. now add the shutdown to local.stop
      Code:
      #nano -w /etc/conf.d/local.stop

      then insert the bottom line below:
      Code:
      # /etc/conf.d/local.stop

      # This is a good place to unload any misc.
      # programs you started above.
      # For example, if you are using OSS and have
      # "/usr/local/bin/soundon" above, put
      # "/usr/local/bin/soundoff" here.

      /sbin/gradm -D


      [TODO: modify the script to check if RBAC is enabled. Better yet, I would prefer that the shutdown doesn't proceed because it makes a big mess if the RBAC system is enabled and requires resetting the system to restart. Adding all the rules for shutdown opens up a lot of access during normal operation, so I avoid it.]


  3. Create Initial Learned Roles and Manage Learning

    1. Now, ensure that all of the services required on the system are enabled at startup (Note: if you add them in the future, you can repeat this learning process) then reboot the system:
      Code:
      shutdown -r now


      Note: upon reboot, if you use gpm, move the mouse on the terminal to ensure those accesses are logged otherwise there will be no rules for gpm. However, it is easy enough to generate those rules later. Also logging into each console that permits a user login will include those in the roles. Transition to su will also be a time saver. Since I limit root login to a single console, I perform that login as well. If you plan to connect and disconnect usb devices, do this also so the rules are added. I'm assuming no X at this point because I have been working with servers. [TODO: add X capability to the process.]

      This creates a learning log in /gradm.initial.learning.log file that can be used to generate roles (which is another term for a policy statement).

    2. To generate the intial policy statement:
      Code:
      #/sbin/gradm -F -L /gradm.initial.learning.log -O /gradm.initial.learning.roles


    3. Now you have your first policy, so put it where it will be useful.
      Code:
      #cat /gradm.initial.learning.roles >> /etc/grsec/policy


      and clean up
      Code:
      #rm /gradm.initial.learning*


    4. Then set to autostart rather than autolearn:
      Code:
      #nano -w /etc/conf.d/local.start

      then insert:
      Code:
      # /etc/conf.d/local.start

      # This is a good place to load any misc programs
      # on startup (use &>/dev/null to hide output)
      #/sbin/gradm -F -L /gradm.initial.learning.log
      /sbin/gradm -E


    5. Now, test the workability of the system active:
      Code:
      #/sbin/gradm -E

      and try the system in various ways.

    6. Examine the logs.
      If the system does not perform well, investigate the logs. Really, look at the logs anyway:
      Code:
      #/sbin/gradm -a admin
      (enter password)
      #grep grsec /var/log/kern.log | less


      Now locate the activate line in the log, something like this:

        Jan 29 13:59:45 localhost kernel: [ 151.460617] grsec: (root:U:/sbin/gram) grsecurity 2.1.13 RBAC system load by /sbin/gram[gram:4729] ui/eui:0/0 gi/egi:0/0, parent /sbin/runscript.sh[runscript.sh:4728] ui/eui:0/0 gi/egi:0/0


      and all the denied message following are your bogy to fix. Let's see how to fix those.

      The logging in grsecurity RBAC is pretty verbose and the role used for a specific denial is in the message. For example, take these two denial messages:

        Jan 30 04:21:01 localhost kernel: [51827.619562] grsec: (root:U:/usr/sbin/cron) denied access to hidden file /etc/crontab by /usr/sbin/cron[cron:4671] uid/euid:0/0 gid/egid:0/0, parent /sbin/init[init:1] uid/euid:0/0 gid/egid:0/0

        Jan 30 04:21:48 localhost kernel: [51873.847865] grsec: (root:U:/) denied executable mmap of /bin/nano by /bin/nano[nano:7419] uid/euid:0/0 gid/egid:0/0, parent /bin/bash[bash:7413] uid/euid:0/0 gid/egid:0/0


      The first was using the root role but the subject "/usr/sbin/cron" while the second rule is using the root role but the subject "/".

      To fix the second, we have some choices. This particular error occured because I had not transitioned to the admin role, so access is not available until I do (i.e. the error is not with the policy but between the keyboard and the chair ;-) )

      To fix the first, we'll need to add a rule to the role root and the subject /usr/sbin/cron to allow read access to /etc/crontab:


        role root uG

        ... additional subjects but no intervening role statements

        subject /usr/sbin/cron o {
        / h
        /etc/localtime r
        /etc/cron.d r
        /etc/crontab r
        /var/spool/cron/crontabs r
        -CAP_ALL
        bind disabled
        connect disabled
        }



      But also, looking at this list, we probably will fail hourly trying to run what is in /etc/cron.hourly, etc. So fixing that manually can be cumbersome. So lets try learning again, this time at the subject level by adding a lower case l to the subject:


        role root uG

        ... additional subjects but no intervening role statements

        subject /usr/sbin/cron ol {
        / h
        /etc/localtime r
        /etc/cron.d r
        /etc/crontab r
        /var/spool/cron/crontabs r
        -CAP_ALL
        bind disabled
        connect disabled
        }


      Note: I left the current rules in place. We'll need to merge them later because we may not encounter all situations in the current roles.

      Then start the system for learning:
      Code:
      # /sbin/gradm -L /gradm.cron.learning.log


      Note: we omitted the -F because we are learning a specific item, not full system learning. If you do accidentally leave the -F in you get the cryptic message:
        Duplicate role :::kernel::: on line 788 of /etc/grsec/policy.
        The RBAC system will not be allowed to be enabled until this error is fixed.


      Now generate the rules (it is a capital o not zero):

      Code:
      # /sbin/gradm -L /gradm.cron.learning.log -O /gradm.cron.learning.roles


      Merging the learned subject rules I recommend extracting the subject section of the learned roles and from the original roles and using diff to work with the differences. Diff rarely gives usable output from comparing the existing roles to the learned roles. I have a script (see below) to parse the roles and subjects into a directory structure with sorting. I created the script originally to help me understand the roles, but I find now that it helps with this merge process and really seeing the changes. The diff output from the directory structure is much cleaner. [TODO: complete testing on parser and post.]

      Here are the generated roles:

        ### THE BELOW SUBJECT(S) SHOULD BE ADDED TO THE USER ROLE "root" ###
        subject / o {
        / h
        -CAP_ALL
        bind disabled
        connect disabled
        }

        subject /usr/sbin/cron o {
        user_transition_allow root
        group_transition_allow root

        /
        /bin h
        /bin/bash x
        /etc r
        /etc/grsec h
        /etc/ssh h
        /etc/shadow- h
        /etc/gshadow h
        /etc/gshadow- h
        /etc/ppp/chap-secrets h
        /etc/ppp/pap-secrets h
        /etc/samba/smbpasswd h
        /lib rx
        /proc h
        /proc/sys/kernel/ngroups_max r
        /usr h
        /usr/sbin/cron rx
        /usr/sbin/ssmtp x
        /var h
        /var/run
        /var/spool/cron/crontabs r
        /dev/grsec h
        /dev/mem h
        /dev/kmem h
        /dev/port h
        /dev/log h
        /sys h
        /boot h
        -CAP_ALL
        +CAP_SETGID
        +CAP_SETUID
        bind disabled
        connect disabled
        }



      Then copy them to the appropriate place in the roles (where we did the learning in the first place) and remove the lower case l:

        role root uG

        ... additional subjects but no intervening role statements

        subject /usr/sbin/cron o {
        user_transition_allow root
        group_transition_allow root

        /
        /boot h
        /bin h
        /bin/bash x
        /dev/grsec h
        /dev/mem h
        /dev/kmem h
        /dev/port h
        /dev/log h
        /etc r
        /etc/grsec h
        /etc/ssh h
        /etc/shadow- h
        /etc/gshadow h
        /etc/gshadow- h
        /etc/ppp/chap-secrets h
        /etc/ppp/pap-secrets h
        /etc/samba/smbpasswd h
        /lib rx
        /proc h
        /proc/sys/kernel/ngroups_max r
        /sys h
        /usr h
        /usr/sbin/cron rx
        /usr/sbin/ssmtp x
        /var h
        /var/run

        /var/spool/cron/crontabs r
        -CAP_ALL
        +CAP_SETGID
        +CAP_SETUID

        bind disabled
        connect disabled
        }



  4. Finalizing.

    Once you have rebooted and confirmed the security is where you want it, finalize it by adding to /etc/sysctl.conf:
    Code:

    kernel.grsecurity.grsec_lock = 1
    kernel.grsecurity.disable_modules = 1


    Note: disabling module loading is not absolutely required. See the full grsecurity guide section 4 for other sysctl options to lock.

    Now, optionally and for the super paranoid, I edit the policy which will look something like this giving admin the same as default as my decoy and my real admin role (in this case omni) gets the admin capability and don't forget to allow root to transition to your new admin role:

      role omni sA
      subject / rvka
      / rwcdmlxi

      role admin
      subject / {
      / h
      -CAP_ALL
      connect disabled
      bind disabled
      }

      role default
      subject / {
      / h
      -CAP_ALL
      connect disabled
      bind disabled
      }

      role root uG
      role_transitions admin omni
      role_allow_ip 0.0.0.0/32
      subject / {
      / h

      ... lots of rules deleted
      }

      subject /usr/sbin/gpm o {
      / h
      /dev
      /dev/gpmctl wd
      /dev/tty0 rw
      /dev/grsec h
      /dev/mem h
      /dev/kmem h
      /dev/port h
      /dev/log h
      /var/run
      /var/run/gpm.pid wd
      -CAP_ALL
      +CAP_SYS_ADMIN
      +CAP_SYS_TTY_CONFIG
      bind disabled
      connect disabled
      }



    for reference, here is the policy I started with to make the above changes:

      role admin sA
      subject / rvka
      / rwcdmlxi

      role default
      subject / {
      / h
      -CAP_ALL
      connect disabled
      bind disabled
      }

      role root uG
      role_transitions admin
      role_allow_ip 0.0.0.0/32
      subject / {
      / h

      ... lots of rules deleted
      }

      subject /usr/sbin/gpm o {
      / h
      /dev
      /dev/gpmctl wd
      /dev/tty0 rw
      /dev/grsec h
      /dev/mem h
      /dev/kmem h
      /dev/port h
      /dev/log h
      /var/run
      /var/run/gpm.pid wd
      -CAP_ALL
      +CAP_SYS_ADMIN
      +CAP_SYS_TTY_CONFIG
      bind disabled
      connect disabled
      }





Here is my script to parse and compare rules.
It is rudimentary at this stage but by reviewing the results at the end, it is clear the differences between the policies.

In the current directory, save the existing policy as etc.grsec.policy and the new policy as etc.grsec.learned.policy.
The script creates a tree of existing rules in the existing/ directory and learned rules in the learned/ directory.
The "Only in" lines reflect full subject and role differences. The initial slash in paths of subjects are replaced by the word slash.
Rules are sorted to have better matching.

Here's the script:
Code:

#!/bin/bash
echo " ensure in the directory to save policy tree"
echo " press ctrl+c to exit "
read
wd="`pwd`"
echo " working directory ${wd}"
# verify learned policy file provided
learned="${wd}/etc.grsec.learned.policy"
# verify existing policy updated
existing="${wd}/etc.grsec.policy"
mkdir existing
mkdir learned
cd existing
#  verify updated file date matches last update of /etc/grsec/policy
for policyfile in ${existing} ${learned}
do
#policyfile=${existing}
# regenerate existing policy tree
mode=0
exec 3< ${policyfile}
while read aline <&3
do
echo " ${mode} processing line ${aline} "
case ${mode} in
   0)
      # test for role start
      # if [ `expr match "${v}" "role "` -eq 5 ] ; then echo "mess1" ; else echo "mess2"; fi
      if [ `expr match "${aline}" "role "` -eq 5 ] ; then
         # if role start found
         # set role name in role variable from statement
         role="`echo "${aline}" | cut -d" " -f 2`"
         echo " found role ${role} "
         # create role directory
         mkdir ${role}
         cd ${role}
         # create role file with role statement
         echo "${aline}" > role
         # set to role mode
         mode=role
      #else
         # skip record
      fi
#   break
   ;;
   role)
      # test for subject statements
      if [ `expr match "${aline}" "subject "` -eq 8 ] ; then
         # set subject to subject name
         subject="`echo "${aline}" | cut -d" " -f 2`"
         if [ "${subject}" == "/" ] ; then
            subject="slash"
         else
            subject="`echo "slash${subject}" | tr "/" "."`"
         fi
         echo " found subject ${subject} "
         # create subject file with subject statement
         echo "${aline}" > ${subject}
         # sort role file
         cat role | sort > role.sorted
         mv role.sorted role
         # set to subject mode
         mode=subject
      else
         if [ `expr match "${aline}" "role "` -eq 5 ] ; then
            # if role start found
            # move up dir
            cd ..
            # set role name in role variable from statement
            role="`echo "${aline}" | cut -d" " -f 2`"
            echo " found role ${role} "
            # create role directory
            mkdir ${role}
            cd ${role}
            # create role file with role statement
            echo "${aline}" >> role
            # set to role mode
            mode=role
         else
            # continue to write role statements
            echo "${aline}" >> role
         fi
      fi
#   break
   ;;
   subject)
      if [ `expr match "${aline}" "subject "` -eq 8 ] ; then
         # set subject to subject name
         subject="`echo "${aline}" | cut -d" " -f 2`"
         if [ "${subject}" == "/" ] ; then
            subject="slash"
         else
            subject="`echo "slash${subject}" | tr "/" "."`"
         fi
         echo " found subject ${subject} "
         # create subject file with subject statement
         echo "${aline}" > ${subject}
         # sort role file
         cat role | sort > role.sorted
         mv role.sorted role
         # set to subject mode
         mode=subject
      else
      # write subject to file
      echo "${aline}" >> ${subject}
      # test for end of subject
      if [ `expr match "${aline}" ".*}.*"` -gt 0 ] ; then
         # end of subject } found
         echo " found end of subject ${subject}"
         # set mode to role
         mode=role
         # sort subject files
         cat ${subject} | sort > ${subject}.sorted
         mv ${subject}.sorted ${subject}
      else
         if [ `expr match "${aline}" "role "` -eq 5 ] ; then
            # if role start found
            # move up dir
            cd ..
            # set role name in role variable from statement
            role="`echo "${aline}" | cut -d" " -f 2`"
            echo " found role ${role} "
            # create role directory
            mkdir ${role}
            cd ${role}
            # create role file with role statement
            echo "${aline}" >> role
            # set to role mode
            mode=role
         fi
      fi
      fi
#   break
   ;;
esac
done
exec 3>&-
cd ${wd}/learned
# repeat for learned policy to verify changes
done
# show differences, omitting deletions from existing tree
cd ${wd}
echo "========begin showing differences============="
diff existing/ learned/ > result1
diff existing/ learned/ | grep Common | cut -d" " -f 3,5 | xargs -l diff -y -B >> result1
echo 'enter in less to review changes in context "/[<>\|]" '
echo '  then enter /Only to see the newly added sections '
read
less result1


Last edited by schmeggahead on Sat Feb 13, 2010 4:39 pm; edited 1 time in total
Back to top
View user's profile Send private message
Sadako
Advocate
Advocate


Joined: 05 Aug 2004
Posts: 3792
Location: sleeping in the bathtub

PostPosted: Sun Feb 07, 2010 6:28 pm    Post subject: Reply with quote

No response to this yet?

I finally got a decent new machine, so I can make use of kvm (which runs perfectly under a fully hardened kernel, sweet), so I'll be playing around with grsec's RBAC within a vm, I'll use this as a starting point and get back to you with any feedback or issues.

Thanks.

Oh, when emerging stuff, do you disable RBAC completely?
_________________
"You have to invite me in"
Back to top
View user's profile Send private message
schmeggahead
Guru
Guru


Joined: 25 Feb 2003
Posts: 314
Location: Columbus, Ohio

PostPosted: Sun Feb 07, 2010 8:15 pm    Post subject: Reply with quote

I just figured out how to do the start up and shutdown learning using local.start and local.stop

I'm changing the local.stop process to include /sbin/gradm -D < .file.with.your.password

once restarting the system, use /sbin/gradm -F -L /full.learning.log.name -O /full.policy.name

But I went to the grsecurity forum and posted a poll to see who uses auto start and how here: http://forums.grsecurity.net/viewtopic.php?f=5&t=2248

no luck on the hardened chat either.
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Documentation, Tips & Tricks All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum