playing with grsecurity | a brief tutorial

This howto is intended for those looking for better means to secure the Linux kernel, and the userland by the means of a powerful and simple role based access control policy.

Contents

  1. What is grsecurity?
  2. Setting up grsecurity + gentoo in a VM
  3. The real thing: Grsecurity
    1. Getting familiar with gradm
    2. Generating the policy
    3. Fixing the errors
    4. Roles, subjects and objects
    5. The include directive
    6. Best Practices for /etc/grsec/policy
  4. Filtering grsecurity logs with rsyslog

What is grsecurity?

grsecurity is an innovative approach to security utilizing a multi-layered detection, prevention, and containment model. It is a set of patches for the Linux kernel with an emphasis on enhancing security. Its typical application is in web servers and systems that accept remote connections from untrusted locations, such as systems offering shell access to its users.

Extensive information about grsecurity can be found from the following links:

This tutorial briefly gives you an introduction on using grsecurity. The grsecurity wikibook is written by the creator(Bradley Spengler) of the subject in discussion.

Setting up grsecurity + gentoo in a VM

To test grsecurity’s features, we’ll setup gentoo hardened in a virtual machine using QEMU. Let’s get QEMU installed.

  • Redhat: yum install qemu qemu-img
  • Debian: aptitude install kvm
  • Gentoo: emerge -av qemu-kvm with the following use flags: aio hardened jpeg ncurses png qemu_softmmu_targets_arm qemu_softmmu_targets_i386 qemu_softmmu_targets_x86_64 qemu_user_targets_x86_64 ssl

Create a raw image and set it up:

# qemu-img create -f raw grsec.gentoo.img 2G
# fdisk grsec.gentoo.img
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xe2c8c9c9.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4, default 1): 1
First sector (2048-4194303, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-4194303, default 4194303):
Using default value 4194303

Command (m for help): a
Partition number (1-4): 1

Command (m for help): p

Disk grsec.gentoo.img: 2147 MB, 2147483648 bytes
255 heads, 63 sectors/track, 261 cylinders, total 4194304 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xe2c8c9c9

	   Device Boot      Start         End      Blocks   Id  System
grsec.gentoo.img1   *        2048     4194303     2096128   83  Linux

Command (m for help): w
The partition table has been altered!

Syncing disks.
# losetup -v -o $((512*2048)) -f grsec.gentoo.img
Loop device is /dev/loop0
# mkfs.ext4 -L "grsec.gentoo" /dev/loop0
# mkdir grsec.gentoo-rootfs
# mount /dev/loop0 grsec.gentoo-rootfs

Now download the hardened gentoo stage3. Follow the chapters 5 to 10, of the handbook keeping in mind the following set of instructions (gentoo x86_64 handbook):

  • Select the profile “hardened/linux/amd64”
  • For networking, choose the DHCP method. We’ll discuss how to create custom rules for ssh.
  • When doing anything related to GRUB, see below
  • Install the kernel source: =sys-kernel/hardened-sources-2.6.38 and =sys-apps/gradm-2.2.2.201103262019 . If necessary, unmask them.
  • The extra packages that I installed are dhcp openssh eix pciutils vim gentoolkit rsyslog vixie-cron grub =sys-kernel/hardened-sources-2.6.38 =sys-apps/gradm-2.2.2.201103262019
  • Kernel config for the QEMU envionment is listed as follows.

Kernel configuration for the environment(only essentials):

-> Processor type and features
  -> Processor family
    -> Core 2/newer Xeon (set this to your host CPU)

-> Device Drivers
   -> Serial ATA and Parallel ATA drivers
     -> ATA SFF support
       -> ATA BMDMA support
         -> Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support

-> Device Drivers
  -> Network device support
    -> Ethernet (10 or 100Mbit)
      -> RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support

-> File systems
  -> The Extended 4 (ext4) filesystem
    -> Use ext4 for ext2/ext3 file systems

-> Security options
  -> Grsecurity
    -> Grsecurity
      -> Security Level
        -> Hardened Gentoo [virtualization]
    -> Filesystem Protections
      -> Restrict /proc to user only
  -> Restrict unprivileged access to the kernel syslog

That’s all that’s essential, go ahead and drop extra things that just make the kernel fat. Make sure you disable Paravirtualized guest support under Processor type and features in any case. Enabling that causes the system to not boot.

GRUB menu entry:

title gentoo hardened
root (hd0,0)
kernel /boot/vmlinuz-2.6.38-hardened root=/dev/sda1

Exit the chroot. Unmount the filesystem, and prepare it for booting. DO NOT unmount anything yet.

# losetup -v -f grsec.gentoo.img
Loop device is /dev/loop1
# echo "(hd0) /dev/loop1" > /tmp/device.map
# grub --device-map=/dev/null
    GNU GRUB  version 0.97  (640K lower / 9216K upper memory)

     [ Minimal BASH-like line editing is supported.  For the first word, TAB
       lists possible command completions.  Anywhere else TAB lists the possible
       completions of a device/filename. ]

grub> device (hd0) /dev/loop1

grub> root (hd0,0)
Filesystem type is ext2fs, partition type 0x83

grub> setup --stage2=/path/to/grsec.gentoo-rootfs/boot/grub/stage2
 Checking if "/boot/grub/stage1" exists... yes
 Checking if "/boot/grub/stage2" exists... yes
 Checking if "/boot/grub/e2fs_stage1_5" exists... yes
 Running "embed /boot/grub/e2fs_stage1_5 (hd0)"...  18 sectors are embedded.
 succeeded
 Running "install --stage2=/path/to/grsec.gentoo-rootfs/boot/grub/stage2 /boot/grub/stage1 (hd0)
  (hd0)1+18 p (hd0,0)/boot/grub/stage2 /boot/grub/menu.lst"... succeeded
 Done.

grub> quit

Now startup the virtual machine.

$ qemu-kvm -cpu qemu64 -smp 2 -m 384M -hda grsec.gentoo.img -curses \
-net user -net nic,model=rtl8139 -redir tcp:8022::22

This should bring up an ncurses based UI to the VM.

The real thing: Grsecurity

If you’ve noticed from the kernel configuration, you’ve set restrict /proc to user only. Create a user unauth login to it. top will show you only the processes owned by that user. ls /proc will confirm that. Further dmeg will tell you Operation not permitted. These are just a few basic security enhancements. You can go ahead and set the custom profile in the kernel config and setup the system as you like. For now, we’ll discuss the RBAC system of grsecurity.

Getting familiar with the RBAC system of grsecurity: gradm

gradm is a tool to enable, disable, and control the RBAC system of grsecurity. It is a very powerful tool. Let’s start from the beginning, setting passwords, and enabling the full learning process.
Use gradm -P to set the master password. This is used to disable and reload the RBAC mechanism. gradm -P to set the password of any user role defined in the policy file.

# gradm -P
Setting up grsecurity RBAC password
Password:
Re-enter Password:
Password written to /etc/grsec/pw.
# gradm -P admin
Setting up password for role admin
Password:
Re-enter Password:
Password written to /etc/grsec/pw.
# gradm -P shutdown
Setting up password for role shutdown
Password:
Re-enter Password:
Password written to /etc/grsec/pw.

Full system learning:

grsecurity has a feature called learning. In the beginning you can enable the full learning process, where grlearn will log all your actions. Any actions that you do not want other users access to, must be done by logging into the RBAC system. To enable full system learning, we do the following, create a new file /etc/local.d/gradm.start with the following contents:

/sbin/gradm -FL /grlearn.log

Make sure you make the file executable, by chmod +x /etc/local.d/gradm.start
On your next boot, it will automatically start. Add the service sshd and rsyslog to start by default and reboot:

# rc-update add sshd default
# rc-upadte add rsyslog boot
# reboot

Now you can ssh into the machine, by:

$ ssh root@localhost -p 8022

Do something, and then check the logs, ssh into the VM from another terminal and tail -f /grlearn.log
You’ll see many entries when you so some specific resource actions. Example, uptime, wget. Lots of entries are generated. System packages need only to be installed under the role of admin. So login to role admin, and install a package. Restarting the sshd service is a good idea too.

# gradm -a admin
Password:
# emerge -avuDN vim

Notice that nothing is logged in the grlearn.log file. To logout of that role, simply do a gradm -u

Generating the policy

Once the full learning process is done, or rather you’ve done everything that you don’t want access to in the user role admin, its time to generate the policy. For desktop users, you may want to run the full learning process for a day or two. First disable it, then generate the policy and append it to the default policy.

# gradm -FL /grlearn.log -O /etc/grsec/flearn.policy
Beginning full learning 1st pass...done.
Beginning full learning role reduction...done.
Beginning full learning 2nd pass...done.
Beginning full learning subject reduction for user sshd...done.
Beginning full learning subject reduction for user root...done.
Beginning full learning object reduction for subject /...done.
Beginning full learning object reduction for subject /etc/init.d...done.
Beginning full learning object reduction for subject /sbin/rc...done.
Beginning full learning object reduction for subject /usr/bin/wget...done.
Beginning full learning object reduction for subject /usr/sbin/sshd...done.
Full learning complete.
# cat /etc/grsec/flearn.policy >> /etc/grsec/policy

Fixing the errors:

If you simply do gradm -E, it wouldn’t work. Let’s look at the errors and fix them

# gradm -E
Duplicate object found for "/lib64" in role shutdown, subject /, on line 257 of /etc/grsec/policy.
"/lib64" references the same object as the following object(s):
/lib (due to symlinking/hardlinking)
/lib64 (due to symlinking/hardlinking)
specified on an earlier line.  The RBAC system will not load until this error is fixed.

Open the policy file with your favorite editor, and go to that line. Then comment that line out, as its already protected because it’s a symlink to somewhere else. Check the policy file for errors again, do gradm -C. Another error, great! Yes, just comment out all those lines, they’re the same reference. Then at last you’ll come to the good error:

# gradm -C
Duplicate role admin on line 463 of /etc/grsec/policy.
The RBAC system will not be allowed to be enabled until this error is fixed.

This duplicate is because the default policy which is put in place by installing gradm, contains an admin role already. So go to those lines and comment them.

#role admin sA
#subject / rvka
#       / rwcdmlxi

If you see an error like the following, then you have to add the variable $grsec_denied to that particular role.

# gradm -C
Viewing access is allowed by role root to /proc/kcore [...]

Reading access is allowed by role root to /proc/slabinfo [...]

Reading access is allowed by role root to /proc/modules [...]

Reading access is allowed by role root to /proc/kallsyms [...]

There were 4 holes found in your RBAC configuration.  These must be fixed before the RBAC system will b
e allowed to be enabled.

I’ll explain roles, subjects, objects and modes later further down in this tutorial. For now, search for the string “role root” in the policy file, and follow downwards from there, untill you come to -CAP_ALL, add $grsec_denied just before that.
Now the grsecurity RBAC system is ready to be loaded, once gradm -C reports no errors with the policy file. Enable it then, and see if it’s working

# gradm -E

Now in the syslog you should see this:
2011-05-21T05:11:15.536086+00:00 localhost kernel: [ 3070.796712] grsec: From 10.0.2.2: (root:U:/sbin/gradm) grsecurity 2.2.2 RBAC system loaded by /sbin/gradm[gradm:1767] uid/euid:0/0 gid/egid:0/0, parent /bin/bash[bash:1542] uid/euid:0/0 gid/egid:0/0

# ls /etc/grsec
ls: cannot access /etc/grsec: No such file or directory

Viola! The RBAC system is running flawlessly!
Now if you ssh into the system, it will fail. Take a look at the logs(/var/log/messages):

2011-05-24T03:15:08.836286+00:00 localhost kernel: [ 2011.183591] grsec: From 10.0.2.2: (root:U:/) denied open of /proc/1677/oom_score_adj for writing by /usr/sbin/sshd[sshd:1677] uid/euid:0/0 gid/egid:0/0, parent /usr/sbin/sshd[sshd:1527] uid/euid:0/0 gid/egid:0/0
2011-05-24T03:15:08.836320+00:00 localhost kernel: [ 2011.183822] grsec: From 10.0.2.2: (root:U:/) denied access to hidden file /usr/sbin/sshd by /usr/sbin/sshd[sshd:1677] uid/euid:0/0 gid/egid:0/0, parent /usr/sbin/sshd[sshd:1527] uid/euid:0/0 gid/egid:0/0
2011-05-24T03:15:08.837263+00:00 localhost kernel: [ 2011.184485] grsec: From 10.0.2.2: (root:U:/) denied connect() to the unix domain socket /dev/log by /usr/sbin/sshd[sshd:1677] uid/euid:0/0 gid/egid:0/0, parent /usr/sbin/sshd[sshd:1527] uid/euid:0/0 gid/egid:0/0
2011-05-24T03:15:08.857339+00:00 localhost kernel: [ 2011.204857] grsec: From 10.0.2.2: (root:U:/) denied connect() to the unix domain socket /dev/log by /usr/sbin/sshd[sshd:1677] uid/euid:0/0 gid/egid:0/0, parent /usr/sbin/sshd[sshd:1527] uid/euid:0/0 gid/egid:0/0
2011-05-24T03:15:08.860352+00:00 localhost kernel: [ 2011.207771] grsec: From 10.0.2.2: (root:U:/) use of CAP_SYS_CHROOT denied for /usr/sbin/sshd[sshd:1678] uid/euid:0/0 gid/egid:0/0, parent /usr/sbin/sshd[sshd:1677] uid/euid:0/0 gid/egid:0/0

The text in bold indicates that that particular user is denying access to that particular resource. Login to the admin role(gradm -a admin), and search for the string “role root”, then “subject /usr/sbin/sshd”. Add the following entries in the right places(stick to the alphabetical order, its easier to read):

        /proc/*/oom_score_adj      rw
        /usr/sbin/sshd                  rx
        /var/empty                      r

Reload the RBAC system, you should be able to ssh now. There are still a few errors in the logs. You can simply add the two following lines to fix them.

        /var/log/tallylog           rw
        /proc/*/loginuid           rw

This should fix everything that ssh needs access to.

Roles, subjects and objects

The structure takes the following pattern:

role <user> u
<user attributes>

subject <app/binary> o
    <object>                <mode>

subject <app/binary> <mode(s)>
    <object>                <mode>

The letter ‘u’ follows the username mentioned to indicate that it is a user. ‘g’ can be used for groups. Attributes include transitions, ip_allow, etc. A complete detail of this is found on the grsecurity wikibook.

Subjects have members called objects to define what access does the subject in question have. There are various modes here too. The ‘o’ in the first subject is to make sure inheritance is not followed from the default policy or user policy.

The include directive

Once your familiar with the policy file, reinstall the default one, and use the include directive in the main policy file to include a certain directory containing policies for different users/subjects etc.

A reasonable structure would be to have:

/etc/grsec
/etc/grsec/policy.d
/etc/grsec/policy.d/user1
/etc/grsec/policy.d/user1/logs
/etc/grsec/policy.d/user1/policy

To learn the actions of a new user, you can have the following in the main policy file(at the end of it):

role jude ul

Then start the learn process with gradm -L /etc/grsec/policy.d/jude/learning.logs -E. Generate the policy from the logs, and place the policy as basic.policy in the policy directory. Once your done with that, delete the line you’ve added for the learn and replace it with:

include </etc/grsec/policy.d/user1/policy>

 

Best Practices for /etc/grsec/policy

  • Make the policy as restrictive as possible, there are many features that haven’t been touched in this tutorial, read the grsecurity wikibook for a complete hands on grsecurity.
  • Keep things simple, keep to the alphabetic order.
  • Create a policy and directory structure the way your comfortable with.
  • In the beginning of the policy file, there are lot of details about the present RBAC system, read them.

Filtering grsecurity logs with rsyslog

If your using rsyslog, you may want to filter out the grsecurity messages. Append the following lines to /etc/rsyslog.conf, and restart rsyslog

# grsec logs
:msg, contains, "grsec" /var/log/grsecurity.log
:msg, contains, "grsec" ~

If you encounter any problems whilst following this tutorial, feel free to comment


Comments

6 responses to “playing with grsecurity | a brief tutorial”

  1. Its a little out-dated but still helpful
    Thanks for such a good article…

    1. Hey Alex,
      I’ve not kept in touch with the grsecuriry project for a while, so it could be a little out of date. However, the basics should still remain the same.

      Thank you.

  2. How we can test that Grsecurity preventing attacks…? I think major attacks done through network, Can Grsecurity achieve the security to prevent them………..? I was tried smurf attack (DoS ATTACK) on Grsecurity compiled kernel and it does not prevent that attack……….? and thanks for your article………It helps lot….

    1. Hello,
      Please refer to http://grsecurity.net/ for such information.

  3. Good article, no other post anywhere that mentions how to get grsecurity working well.