Quantcast
Channel: Dan Walsh's Blog
Viewing all 181 articles
Browse latest View live

10 things you probably did not know about SELinux.. #3

$
0
0
SELInux versus nsswitch.conf

Many confined domains call getpwnam, getpwuid, getpwent functions.  Traditionally these function calls just read the the /etc/passwd file.  In a modern Linux system the glibc has added nsswitch.

man nssswitch.conf
...
NAME
       nsswitch.conf - System Databases and Name Service Switch configuration file

DESCRIPTION
       Various functions in the C Library need to be configured to work correctly in the local environment.  Tra‐
       ditionally, this was done by using files (e.g., /etc/passwd), but other  nameservices  (like  the  Network
       Information  Service  (NIS)  and the Domain Name Service (DNS)) became popular, and were hacked
       into the C library, usually with a fixed search order.
...


nsswitch functionality allows multiple back-ends for the getpw*. These back-ends can change the access required by a process, and SELinux has to allow for these different back-ends.

If you have setup your system with your passwd data in ldap, SELinux is forced to allow all confined domains that call getpw* to connect to the ldap_port_t ports in order to get passwd data.

# semanage  port -l | grep ldap
ldap_port_t                    tcp      389, 636, 3268
ldap_port_t                    udp      389, 636


Also since the confined application needs to resolve the hostname of the ldap server, the confined application needs to be able to connect to dns_port_t.

# semanage  port -l | grep dns
dns_port_t                     tcp      53
dns_port_t                     udp      53


Even worse if you are using NIS all of these applications have to be able to connect all ports and bind to all ports.

We have had a boolean allow_ypbind since RHEL5, luckily this is turned off by default and eliminates a lot of access.  You only need to turn it on if you are using NIS.

sssd (System Security Services Daemon) to the rescue.

sssd provides a new back end for nsswitch.  This backend causes all callers of getpw* functions to used a named socket, /var/lib/sss/nss.  The beauty of the sssd backend is the sssd daemon does all of the ldap communications for the confined applications, rather then the confined applications needing to connect directly to the ldap server/port.

In Fedora 15 we added a new boolean authlogin_nsswitch_use_ldap that allows you to turn off this access. 

NOTE:  You can turn off this boolean even if you are using ldap for passwd entry resolution if you are using sssd.

How many rules does this eliminate?

Using sesearch to look for rules tat allow a domain to connect to the ldap_port_t.

# sesearch -A -t ldap_port_t -p name_connect -C | wc -l
717


If we eliminate the allow_ypbind boolean

# sesearch -A -t ldap_port_t -p name_connect -C | grep -v allow_ypbind | wc  -l
386


Now if we further eliminate authlogin_nsswitch_use_ldap

# sesearch -A -t ldap_port_t -p name_connect -C | grep -v allow_ypbind | grep -v authlogin_nsswitch_use_ldap | wc -l
112

Meaning we have eliminate over 600 rules that allow confined domains to connect to the ldap_port_t.

You can turn off both booleans by executing.

# setsebool -P allow_ypbind=0 authlogin_nsswitch_use_ldap=0

I plan on turning both booleans off by default in Fedora 16.  

10 things you probably did not know about SELinux.. #4

$
0
0
#4 How do I tell whether a domain is confined on an SELinux System?

On SELinux targeted systems, we have confined domains and unconfined domains, and as of RHEL6 and all supported Fedoras we also have permissive domains.  SELinux does not block access on processes running in these domains, for the most part.

Unconfined Domains

An unconfined domain is supposed to be a process that has the same rights as it would if SELinux was disabled.  There are a few caveats to this though. 

Process Transitions

A process transition says when process running as label a_t executes a file labeled b_exec_t it should execute the process as b_t  An example of this would be service httpd start.  In this case we have unconfined_t running an init script labeled initrc_exec_t and SELinux starts the process as initrc_t. 

# sesearch -T -s unconfined_t -t initrc_exec_t
Found 1 semantic te rules:
   type_transition unconfined_t initrc_exec_t : process initrc_t;


Then the init script has a rule that says initrc_t executing httpd_exec_t will transition to httpd_t

# sesearch -T -s initrc_t -t httpd_exec_t
Found 1 semantic te rules:
   type_transition initrc_t httpd_exec_t : process httpd_t;


This means that even though the process that started another process was unconfined, the new process can be confined.  We tend to discourage transitions from the unconfined_t user domain, since this can surprise the user.  "I thought I was unconfined, why when I start XYZ does SELinux block it?"

Other then transitioning to initrc_t there are currently 55 executables that transition out of the unconfined_t domain.

#  sesearch -T -s unconfined_t -c process -C| grep -v initrc_t| grep -v ^D | wc -l
55

A lot of these domains are also unconfined.  unconfined_java_t for example is the same as unconfined_t except it has execstack and execmem privilege always.

Minor Denials

In some cases I have been convinced to add minor confinement to even unconfined domains.  The most seen one of these was the executable memory checks.  execmem, execmod, execheap and execstack.  There are booleans to turn on and off the checks for the unconfined domains.

Listing unconfined domains

You can use seinfo to list the unconfined domains.

# seinfo -aunconfined_domain_type -x | wc -l
54


Disabling unconfined domains

You can easily disable lots of domains unconfined domains to make your machine more locked down.  In RHEL6 and Fedora their are two policy modules unconfined and unconfineduser.  If you disable unconfined it will lock down most of system space.

# semodule -d unconfined
# seinfo -aunconfined_domain_type -x | wc -l
14


This is how I usually run.  In this mode, it will require you to have policy for all apps launched out of init system or xinetd.

You can also disable the unconfined user, by executing the following commands.

# semanage login -m -s staff_u root
# semanage login -m -s staff_u __default__
# semanage user -d unconfined_u
# semanage user -m -R "staff_r system_r sysadm_r" staff_u

# semodule -d unconfineduser


As long as unconfined is not defined in either the semanage user or semanage login database this should work and you pretty much get back to what used to be strict policy.

I tend to leave unconfineduser enabled, but setup all my users as confined, and allow staff_t to transition to unconfined_t through sudo.

Adding unconfined domains to when building policy modules

If you were building your own policy module and you wanted to build an unconfined domain, you would write code like:

type mydomian_t;
domain_type(mydomain_t)

optional_policy(`
          unconfined_domain(mydomain_t)

')

Permissive Domains

The other type of domain that SELinux does not block is the permissive domain.    These are usually domains under construction.  SELinux allows these domains to do any thing but reports AVC;s on them when they do something not allowed in policy.  When we develop policy for Fedora, we define all new domains as permissive and allow them to run permissive through an entire run of a release.  Then in the next release we turn them to enforcing.  One difference between F15 and F16 policy is we just removed the permissive flag from all domains in F15.

Listing Permissive Domains

You can see the permissive domains in two ways.

# seinfo  --permissive  | wc -l
18


Or you can use the semanage command to list them

# semanage permissive -l

Builtin Permissive Types

staff_gkeyringd_t
staff_gkeyringd_t
mock_t
keyboardd_t
matahari_serviced_t
firewalld_t
colord_t
systemd_notify_t
systemd_passwd_agent_t
mozilla_plugin_t
matahari_hostd_t
matahari_netd_t
passenger_t
systemd_tmpfiles_t
foghorn_t
namespace_init_t

Customized Permissive Types

qpidd_t


Adding Permissive Domains

Notice that the semanage command differentiates between customized permissive domains and built-ins.  With the semanage command, the administrator can choose to make a domain permissive, by executing

# semanage permissive -a httpd_t
# seinfo  --permissive  |grep http
   httpd_t


Removing Permissive Domains

You can remove a customized permissive domain by executing:

# semanage permissive -d httpd_t


You can not currently remove permissive domains if they are the built-in into policy.

Adding permissive domains to when building policy modules

If you were building your own policy module and you wanted to build a permissive domain, you would write code like:

type mydomian_t;
domain_type(mydomain_t)

permissive mydomain_t;

 

I will be presenting SELinux at Boston Securty Meetup Tonight.

10 things you probably did not know about SELinux.. #5

$
0
0
#5 How do I add new file systems/disks to an SELinux machine?

Lets examine three use cases:

1: You just got back from Best Buy with a brand new 100 Gig Disk that you want to mount on /home and store your homedirs.  You add the disk mount to /etc/fstab, mount it untar your entire backed up directory to the disk.  Now you attempt to login with a confined user.  Login fails, and the audit logs fill up with AVC messages concerning file_t.  Even without confined logins, applications like sshd can't read the ~/.ssh directory and Apache can no longer read the ~/public_html directory.

SELinux reporting errors with the type file_t indicates that the file/dir has no label.  SELinux has no idea what content is stored in a file without a label, therfore the kernel denies confined applications access to these files.  Ordinarily when I have seen random files all over the disk labelled file_t, I have told the user to relabel the entire machine.  touch /.autorelabel; reboot  In this case we know the user just added a disk, so all he needs to do is run restorecon on the disk.  restorecon -R -v /home.  The restorecon command will put the default labels on the entire disk.  This  also works on disks that you moved from one machine to another, especially important if the machine had SELinux disabled.

2. You add a new lvm mount that you want to store all of your postgresql database directory on.  You create a new directory tree /data/postgresqldb and mount the disk here and mount the directory on /data/pgsql.    You are an advanced SELinux user so you know you need to put labels down,  you run "restorecon -R -v /data/pgsql".   Now you service postgresql start, and POW it blows up.  The setroubleshoot star shows up and you read the analysys.  The analysys tells you that postgresql is trying to access a file in a directory labeled default_t.  Newly created directories in / are labelled default_t.  Just like file_t, the SELinux kernel does not know what content is stored in a file/directory labeled default_t, so all confined applications are blocked from reading default_t files/directories.  The setroubleshoot analysis also tells you you need to put a label on the directory, and choose from a list of labels including postgresql_db_t.  You figure that looks good and you follow the instructions,

# semanage fcontext -a -t postgresql_db_t '/data/pgsql(/.*)?'
# restorecon -R -v /data/pgsql


The semanage command tells the SELinux system what the default label for this directory will be going forward.  The restorecon command actually puts the labels on the disk.

Now you service postgresql start, and POW it blows up again.   At this point you are real unhappy with SELinux.  This time the AVC's indicate that postgresql_t is not able to search through the /data directory which is labelled default_t.  Your labelling was added at a directory a level below what you needed.

# semanage fcontext -d '/data/pgsql(/.*)?'
# semanage fcontext -a -t postgresql_db_t '/data(/.*)?'
# restorecon -R -v /data


I am sorry we blew it on this, but hopefully this example will help you understand a little of what SELinux is doing.

# service postgresql start

It works!!!

Now you can take the pins out of the voodoo doll of me.


NOTE:  If you were to store the postgresql database in a subdirectory of a normal file system directory, DO NOT change the label of that directory.
For example /home/postgesql. 

# semanage fcontext -a -t postgresql_db_t '/home(/.*)?'
# restorecon -R -v /home

Would thoroughly screw up your machine.  In this case it is better to do

# semanage fcontext -a -t postgresql_db_t '/home/pgsql(/.*)?'
# restorecon -R -v /home
/pgsql
Then add allow rules for posqgresql_t to search through home_root_t using

#grep postgresql_t /var/log/audit/audit.log | audit2allow -M mypostgresql
# semodule -i mypostgresql.pp
3. You want to share Apache data on an NFS share using multiple httpd hosts.   You mount the remove nfs directory at /var/www/.

# service httpd start
It blows up permission denied.  This time setroubleshoot is complaining about httpd_t trying to read nfs_t.  The analysis tells you that you can allow httpd_t to read all nfs_t by setting a couple of different booleans.

httpd_use_nfs or use_nfs_home_dirs

Since you are not using nfs for your  home directories, it would be a bad idea from a security point of view to turn this boolean on.  The use_nfs_home_dirs boolean allows any confined domains that need access to  home directory content to get access to all files labeled nfs_t.

Turning on httpd_use_nfs will solve your problem. 
But what if you had other nfs shares mounted which you did not want to grant access to Apache?

The third option would be to use a mount option. 

# mount -o context="system_u:object_r:httpd_sys_content_t:s0" REMOTEHOST:/var/www /var/www

This command tells the SELinux kernel to treat all content in this file system as httpd_sys_content_t.  httpd_t will be allowed to access the content  mounted as httpd_sys_content_t,  but the kernel will still deny httpd_t access to other NFS file systems mounted on the system.

10 things you probably did not know about SELinux.. #6

$
0
0
#6 How did those SELinux labels get there?

SELinux labels are placed on disk during the installation by a combination of Anaconda and rpm.  Anaconda actually includes the latest /etc/selinux/targeted/files/file_context and /etc/selinux/targeted/policy/policy.26 in its initrd.  When anaconda starts rpm, rpm reads this file and proceeds to place the labels on disk.  RPM has SELinux awareness built into it and asks the kernel to place the default label on the disk for every object that it creates from its payload.  If an rpm post install script runs during the install, the labels are created using the standard process labelling described below.   Any file system objects created by Anaconda  before loading the policy into the kernel will be relabelled by Anaconda using restorecon.

Any file system objects created by the post install scripts, or during boot, or by any process from then moving forward will create the file via one of the following three rules.
  • The object will get the label of the parent directory.
    • Files/Directories created in /etc, which is labelled etc_t, will get labelled etc_t by default.
  • File transition rules can be written into policy.  File transition rules take into account the label of the process creating the file as well as the parent directory.  For example I can write a rule that says if NetworkManager_t creates a file in a directory labelled etc_t then this file will be labelled net_conf_t
    •  filetrans_pattern(NetworkManager_t, etc_t, net_conf_t, file)
    • When NetworkManager creates the /etc/resolv.conf file it gets labelled net_conf_f rather then etc_t.
    • Since you can only have one combination of ProcessLabel/DirectoryLabel/ObjectClass, you can not currently write a rule for a process to create two different labels within the same directory.
  • The last way is to build SELinux awareness within an application. 
    • Applications can be programmed to ask the kernel to create a file system object with a particular label.
      • rpm, udev, passwd are examples of applications that request the kernel to label the object at creation time.
    • Applications can attempt to change a label from one label to another.
      • restorecon, udev, restorecond, chcon are examples of applications that modify labels.
In Fedora 16 we are introducing a new concept which we are calling File Name Transitions.   These will allow policy writers to take into account the actual file name (Not path) at file creation time,  giving us the ability to clear up some common bugs users have seen with SELinux.

Read about it here and if you are running Fedora 16/Rawhide try it out...

https://fedoraproject.org/wiki/Features/SELinuxFileNameTransition

SELinux Policy RPM in Rawhide/F16 includes prebuilt policy file.

$
0
0
The selinux-policy-TYPE packages has always rebuilt the policy in their post install.  We do this in order to merge any customizations to the policy that an administrator might have made.  The selinux policy rpm package also needs to rebuild the policy if any policies were installed by other rpms or  by the administrator.

Over time as the size of policy has grown and gotten more complex, the installation procedure has required more memory and more time.  We have seen stats stating during installations, one of the biggest memory hogs was the selinux-policy-targeted package.

Over the last couple of weeks,  I decided to re-examine the situation.  

The selinux-policy-TYPE packages will now ship with a pre-built policy package and will only rebuild the policy iff the existing policy has been customized.  

The following test shows a 4 times speedup on installing the package 48 Seconds -> 12 Seconds.  And max Memory Usage from 38 M to 6 Meg.

Modified:
# time -v rpm -Uhv /home/devel/dwalsh/sources/RPMS/noarch/selinux-policy-targeted-3.9.16-29.1.fc16.noarch.rpm --force
Preparing...                ########################################### [100%]
   1:selinux-policy-targeted########################################### [100%]
    Command being timed: "rpm -Uhv /home/devel/dwalsh/sources/RPMS/noarch/selinux-policy-targeted-3.9.16-29.1.fc16.noarch.rpm --force"
<snip>
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:48.11
<snip>
    Maximum resident set size (kbytes): 377608
<snip>  

Unmodified:
# time -v rpm -Uhv /home/devel/dwalsh/sources/RPMS/noarch/selinux-policy-targeted-3.9.16-29.1.fc16.noarch.rpm --force
Preparing...                ########################################### [100%]
   1:selinux-policy-targeted########################################### [100%]
    Command being timed: "rpm -Uhv /home/devel/dwalsh/sources/RPMS/noarch/selinux-policy-targeted-3.9.16-29.1.fc16.noarch.rpm --force"
<snip>
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:12.32
<snip>
    Maximum resident set size (kbytes): 60112
<snip>


You will only see this improvement on a fresh install.  And should continue to see it on all updates, although updates can still do a partial relabel after install. 

If you are doing an update and would like to see the improvement, you can do the following.

# setenforce 0
# rm -rf /etc/selinux/targeted
# yum -y reinstall selinux-policy selinux-policy-targeted
# restorecon -R -v /etc/selinux/targeted
# setenforce 1


Then you would be seen as a fresh install.

Try it out.

10 things you probably did not know about SELinux.. #7

$
0
0
#7 Does an SELinux Audit Log message always mean something was blocked?  NO

First off lets get rid of a misconception.  An SELinux AVC message consist of a single message in the audit log. 

This is false.   

SELinux messages in the Audit log usually consist of more then one record, and they don't even need to contain an AVC record.

SELinux is all about preventing syscalls, so if something gets denied you will usually see an SELinux message describing the AVC, as well as the SYSCALL.  If you have full auditing turned on, or the kernel has gathered path information, you could also get a PATH record as part of the overall audit record.

The way to view all the records within an AVC message is to use the ausearch -m avc command.

If you look at the SYSCALL record you will see a Name/Value pair with the name "success".  This field indicates whether they SYSCALL record actually succeeded or failed. "success=yes" indicates the syscall was successful.


I can think of 4 different situations where a SELinux message is generated and the SYSCALL record returns success=yes.
  1. The system is in permissive, meaning AVC's are recorded but not enforced.
  2.    > getenforce
    Permissive

  3. The process that caused the domain is a permissive domain (Latest Fedoras/RHEL6 only).  The AVC for this process type is not enforced. 
  4. > seinfo --permissive |grep SOURCETYPE

  5. An AVC was generated but the syscall still succeeded by going down a different code path within the kernel. This is not that common.
  6. An auditallow record was added to the policy. auditallow says to the kernel, generate an audit SYSCALL message any time this access is granted. Currently we do this with load_policy and setting booleans, setenforce.
type=SYSCALL msg=audit(06/23/2011 13:33:58.044:280) : arch=x86_64 syscall=write success=yes exit=1 a0=3 a1=7fff406c5ce0 a2=1 a3=0 items=0 ppid=4408 pid=4546 auid=dwalsh uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts0 ses=4 comm=setenforce exe=/usr/sbin/setenforce subj=staff_u:sysadm_r:sysadm_t:s0-s0:c0.c1023 key=(null) type=MAC_STATUS msg=audit(06/23/2011 13:33:58.044:280) : enforcing=1 old_enforcing=0 auid=dwalsh ses=4
 
 

Follow up to #7 Does an SELinux Audit Log message always mean something was blocked?

$
0
0
In my previous blog

10 things you probably did not know about SELinux.. #7

I stated that one of the times you can get a syscall to succeed even though AVC's were generated was:

3. An AVC was generated but the syscall still succeeded by going down a different code path within the kernel. This is not that common.

Eric Paris pointed out to me in an email and example of this:

(People have a) " fundemental misconception is the belief that there is a 1-1 mapping between a syscall and an selinux permissions check. SELinux is NOT a syscall filter. We check the security state between objects (aka between a task and a file, or a task and a socket, or a task and task) and the result of that check may or may not cause the intended purpose of the request syscall which triggered this check to fail.

A great example of a syscall which is likely to generate AVCs but still give success=yes is execve(). On execve SELinux will check the permissions between the new task and any file descriptors passed from the parent to the child. Notice the check is not about the syscall, execve(), but between the new task and the file descriptors. If the new task is not allowed to access one of the passed file descriptors we will generate an AVC, and will close the fd and open /dev/null in it's place. This is an example of an alternate code path. The syscall is still going to succeed since we will have resolved the security violation that caused the AVC. It's not common, but other such places exist in the kernel, place where we are able to resolve the security issue by doing some other operation and thus the syscall does not need to fail."

Fun with sVirt.

$
0
0
I have been in Washington DC for the last few days talking about SELinux and sVirt, Secure Virtualization. 


sVirt is the combining of SELinux with kvm/qemu virtualization.  The libvirt daemon launches virtual guests in Red Hat operating systems.  Before an virtual machine  is started libvirt picks a random MCS label with two categories, like s0:c1,c2 and then labels all of the virtual machines content as svirt_image_t:s0:c1,c2.  Then it executes qemu with the label svirt_t:c0:c1,c2.   

One of the questions on sVirt I have been asked is how can I test out the sVirt policy, to make sure it works?

I thought about it and I came up with an easy way that someone can play with it. 

One of the major goals of a hacker is to get a root shell on the host, lets see what you can do with the root shell running as svirt_t.

Note: the unconfined_t user type is allowed to transition to svirt_t in Fedora 14-16 and RHEL6 I believe. 

In order to test the svirt_t, we need a program to run, I copied /bin/sh to /bin/svirt.  

# cp /bin/sh /bin/svirt

The policy requires that the entry point for svirt_t must be labeled qemu_exec_t.

# chcon -t qemu_exec_t /bin/svirt

Now I use the runcon command to force a transition from unconfined_t to svirt and pick out an MCS label s0:c1,c2 to run with the svirt shell.

# runcon -t svirt_t -l s0:c1,c2 /bin/svirt
svirt: /root/.bashrc: Permission denied
# id
svirt: child setpgid (6962 to 6962): Permission denied
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=unconfined_u:unconfined_r:svirt_t:s0:c1,c2

First the shell tried to read /root/.bashrc and was denied. because svirt_t is not allowed to read the admin_home_t label.  The shell attempts to setpgid for every command that is executed which SELinux denies svirt_t and prints an error to the screen.  I have removed these errors from the blog just for clarity.
# ping 4.2.2.2
svirt: ping: command not found
# cat /etc/shadow
cat: /etc/shadow: Permission denied

# touch /tmp/svirt
# ls -lZ /tmp/svirt
-rw-r--r--. root root unconfined_u:object_r:svirt_tmp_t:s0:c1,c2 /tmp/svirt

Note Notice the touch succeeded, allowing me to create a file in the /tmp directory labeled svirt_tmp_t:s0:c0,c2
# ^D

Now I exit this shell and start another svirt shell with a slightly different MCS label s0:c1,c3

# runcon -t svirt_t -l s0:c1,c3 /bin/svirt
svirt: /root/.bashrc: Permission denied
# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=unconfined_u:unconfined_r:svirt_t:s0:c1,c3
# touch /tmp/svirt
touch: cannot touch `/tmp/svirt': Permission denied


Note: This svirt shell is denied the ability to use the previously created /tmp/svirt file since this file has a label s0:c1,c2 but this svirt shell is running as s0:c1,c3. This would simulate one svirt guest process attacking another svirt_t process.

Have fun with this and see what svirt can do.  If you find what you believe to be a vulnerability please report it in bugzilla.  If you build a test script with this, we would love to use it.

You will fill your /var/log/audit/audit.log file with audit messages and setroubleshoot will not be happy, but it is pretty good test.

New Kiosk OS posted for Fedora 15

$
0
0
Thanks to Miroslav Grepl, he has put together a working Kiosk OS for Fedora 15.

http://people.fedoraproject.org/~dwalsh/SELinux/kiosk/
 
Name                    Last modified      Size  
Parent Directory                             -   
kiosk.iso               12-Jul-2011 19:51  1.2G  
kiosk.ks                12-Jul-2011 19:46   11K  
As you can see the ISO is quite large since we added LibreOffice.

The Kiosk OS was originally written for Fedora 13 and explained in my Blog

http://danwalsh.livejournal.com/35761.html?thread=231345

If you want to make this into a uninterruptable boot you should create the USB or DVD with the


livecd-iso-to-disk  --totaltimeout 1 myiso /dev/sdb

man livecd-iso-to-disk

       --totaltimeout
           Adds a bootloader totaltimeout, which indicates how long to wait
           before booting automatically.  This is used to force an automatic
           boot.  This timeout cannot be canceled by the user.  Units are 1/10s.

Meaning the livedvd or liveusb will boot automatically in .1 seconds and can not be stopped.

A new short video starring yours truly available to RHEL subscribers.

Fedora 16 is about to go to Alpha release, some SELinux changes.

$
0
0
First with the move to systemd, we were asked to move the /selinux file system to a more standard location.

From this point forward the selinuxfs will be mounted under /sys/fs/selinux.

This seems to be the new location for kernel interface file systems, like cgroup

# ls /sys/fs/
cgroup    ext4  fuse  selinux

libselinux has been modified to mount the selinuxfs file system on the /sys/fs/selinux directory if it exists, otherwise libselinux will fall back to mounting on the /selinux directory if it exists.

One problem I foresee and we are beginning to fix is any application that hard coded "/selinux" in to the application.  So far we have had to fix anaconda, livecd-tools, policycoreutils, and dracut.  In most cases you should use the command line tools like setenforce or selinuxenabeled, or use the python bindings

python
>>> import selinux
>>> print (selinux.is_selinux_enabled())
1

And not hard code the path.

Another option is to grep /proc/self/mountinfo

# grep selinuxfs /proc/self/mountinfo  | head -1 | awk '{ print $5 }'
/sys/fs/selinux


If you know of any applications that hard code /selinux into them, please let me know and I can work with the maintainer or developer to fix the code.

sVirt to the Rescue

$
0
0
At the recent Black Hat conference Nelson Elhage presented:

Virtualization Under Attack: Breaking out of KVM

The exploit, CVE-2011-1751, would allow a cracker to execute code in qemu-kvm process on the host.

Note: Red Hat fixed this problem back in May 2011 prior to the publication of the paper and exploit. Customers who applied our security updates are not affected by this issue. So 0 days of exposure.

In the presentation there is this bullet point:



  • qemu-kvm is often sandboxed using SELinux or similar, meaning that
    successful exploitation will often require a second privesc within the
    host.
    (Fortunately, Linux never has any of those)


This means that SELinux/sVirt on Red Hat Enterprise Linux and Fedora confines this outbreak!

In a previous blog, Fun with sVirt., I showed how you can simulate this vulnerability to see what access was available. Not much...

Nelson mentioned SELinux sandboxing could be bypassed by a theoretical second "privesc" vulnerability, meaning a bug in the kernel. SELinux or any kind of Mandatory Access Control is enforced by the Kernel.  Bugs in that Kernel, that a process is allowed to access, can subvirt SELinux. But SELinux is putting up a significant second barrier to the cracker.

Security is all about Layers, making each layer as secure as possible and then fixing vulnerabilities as quickly as you know about them.

This presentation exposes the risk associated with virtualization, but also shows the secondary security controls Linux KVM is using  to minimize the risk and giving us time to fix problems as soon as we know about them.

Bottom line, this is why you leave SELinux enabled in enforcing mode. :^)

Fedora 16 Alpha available part II, New SELinux Feature/File Name Transitions

$
0
0
Fedora 16 Alpha was just released:

The announcement include the following:
  • SELinux Enhancements. SELinux policy package now includes a pre-built policy that will only rebuild policy if any customizations have been made. A sample test run shows 4 times speedup on installing the package from 48 Seconds to 12 Seconds and max memory usage from 38M to 6M. In addition to that, SELinux file name transition allows better policy management. For instance, policy writers can take advantage of this and write a policy rule that states, if a SELinux unconfined process creates a file named resolv.conf in a directory labelled etc_t, the file should get labeled appropriately. This results is less chances of mislabeled files. Also, from this release onwards, selinuxfs is mounted at /sys/fs/selinux instead of in /selinux. All the affected components including anaconda, dracut, livecd-tools and policycoreutils have been modified to work with this change.

Named File Transitions Feature


This feature was added to F16 to make labelling files easier for users and administrators. 

The goal is to prevent accidental mislabelling of file objects.

Accidental mislabelling

Users or administrators often create files or directories that do not have the same label as the parent directory, and then forget to fix the label. An example of this would be the administrator going into the /root directory and creating the .ssh directory.

In previous versions of Fedora, the directory would get created admin_home_t, even though the policy requires it to be labelled ssh_home_t.   Later when he tries to use the content of the .ssh directory to login without a password, sshd (sshd_t) fails to read the directories contents because sshd is not allowed to read files labelled admin_home_t.

Another example would be a user creating the public_html directory in his home directory.  The default label for content in the home directory is user_home_t, but SELinux requires the public_html directory to be labelled http_user_content_t or the apache process (httpd_t) will not be allowed to read it.

File Transitions Policy

Policy writers have always be able to write a file transition rule that includes the type of the processes creating the file object (NetworkManger_t), the type of the directory that will contain the file object (etc_t) and the class of the file object (file).  Then specify the type of the created object (net_conf_t).

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t)

This policy line says that a process running as NetworkManager_t creating any file in a directory labelled etc_t will create it with the label net_conf_t.

Named File Transitions Policy

Eric Paris added a cool feature to the kernel that allows the kernel to label a file based on 4 characteristics instead of just three.  He added the base file name.  (Not the path).

Now we can write policy rules that state:

  • If the unconfined_t user process creates the ".ssh" directory in a directory labelled admin_home_t, then it will get created with the label ssh_home_t.

    filetrans_pattern(unconfined_t, admin_home_t, dir, ssh_home_t, ".ssh")
  • If the staff_t user process creates a directory named public_html in a directory labeled user_home_dir_t it will get labeled http_user_content_t.

    filetrans_pattern(staff_t, user_home_dir_t, dir, http_user_content_t, "public_html")
Additionally we have added rules to make sure if the kernel creates content in /dev it will label it correctly rather then waiting for udev to fix the label.   
           filetrans_pattern(kernel_t, device_t, chr_file, wireless_device_t, "rfkill")

Bottom line. 

There should be less occurrences of accidental mislabels by users and hopefully a more secure and better running SELinux system.

Fedora 16 Alpha available, New SELinux Feature/Prebuilt Policy.

$
0
0
Fedora 16 Alpha was just released: The announcement include the following:

  • SELinux Enhancements.
    SELinux policy package now includes a pre-built policy that will only rebuild policy if any customizations have been made. A sample test run shows 4 times speedup on installing the package from 48 Seconds to 12 Seconds and max memory usage from 38M to 6M. In addition to that, SELinux file name transition allows better policy management. For instance, policy writers can take advantage of this and write a policy rule that states, if a SELinux unconfined process creates a file named resolv.conf in a directory labelled etc_t, the file should get labeled appropriately. This results is less chances of mislabeled files. Also, from this release onwards, selinuxfs is mounted at /sys/fs/selinux instead of in /selinux. All the affected components including anaconda, dracut, livecd-tools and policycoreutils have been modified to work with this change.


Pre-Built Policy

We made major changes to the selinux-policy-TYPE rpm. (selinux-policy-targeted-3.10.0-21.fc16)

The rpm now includes a pre-built /etc/selinux/targeted/policy/policy.26.  This policy file can be loaded right away in a fresh install.  In all previous versions of SELinux for RHEL and Fedora, we rebuilt this file in the post install.  The reason for this is we  need to recompile in local customizations that the user/administrator might have made on your system.  Additionally if any package shipped  with a policy we would need to recompile in those policy packages.  But as the size of policy grew we were seeing Anaconda installation times  grow and memory requirements grow because of selinux-policy package.  We were even seeing virtual machine installations blow up on selinux-policy package installs because of limited memory.  When we looked at the problem, we realized that on initial install of policy, no user would have made local customizations and very few packages are shipping with their own policy.  

I reworked the tools to include the policy packages within the payload and now the package will check in the pre-install if there was any local customizations, if yes, the post install will recompile the policy, but if not the policy will just install.

We also used to have to ship all of the policy modules, over 300, in the directory /usr/share/selinux/targeted and these would be copied into /etc/selinux/targeted/modules/active/, were we would never touch the files in /usr/share/selinux/targeted again.  Now we install directly into /etc/selinux/targeted/modules/active/.

What you should see is faster initial installs and faster selinux-package updates.  In Fedora 15 a policy-package update would take around 45-50 seconds, in Fedora 16 on an unmodified selinux-policy system it should take < 15 seconds.  If you are updating from Fedora 15 the first time, it will still take a long time, but the next update should go quick.  If you have modified the SELinux system by adding pp
files you will still see the recompile times that you always have.  :^(

Fedora 16 Alpha available part II, New SELinux Feature/File Name Transitions

$
0
0
Fedora 16 Alpha was just released: The announcement include the following:
  • SELinux Enhancements. SELinux policy package now includes a pre-built policy that will only rebuild policy if any customizations have been made. A sample test run shows 4 times speedup on installing the package from 48 Seconds to 12 Seconds and max memory usage from 38M to 6M. In addition to that, SELinux file name transition allows better policy management. For instance, policy writers can take advantage of this and write a policy rule that states, if a SELinux unconfined process creates a file named resolv.conf in a directory labelled etc_t, the file should get labeled appropriately. This results is less chances of mislabeled files. Also, from this release onwards, selinuxfs is mounted at /sys/fs/selinux instead of in /selinux. All the affected components including anaconda, dracut, livecd-tools and policycoreutils have been modified to work with this change.

Named File Transitions Feature

This feature was added to F16 to make labelling files easier for users and administrators.  The goal is to prevent accidental mislabelling of file objects.

Accidental mislabelling

Users or administrators often create files or directories that do not have the same label as the parent directory, and then forget to fix the label. An example of this would be the administrator going into the /root directory and creating the .ssh directory. In previous versions of Fedora, the directory would get created admin_home_t, even though the policy requires it to be labelled ssh_home_t.   Later when he tries to use the content of the .ssh directory to login without a password, sshd (sshd_t) fails to read the directories contents because sshd is not allowed to read files labelled admin_home_t.

Another example would be a user creating the public_html directory in his home directory.  The default label for content in the home directory is user_home_t, but SELinux requires the public_html directory to be labelled http_user_content_t or the apache process (httpd_t) will not be allowed to read it.

File Transitions Policy

Policy writers have always be able to write a file transition rule that includes the type of the processes creating the file object (NetworkManger_t), the type of the directory that will contain the file object (etc_t) and the class of the file object (file).  Then specify the type of the created object (net_conf_t).

filetrans_pattern(NetworkManager_t, etc_t, file, net_conf_t)

This policy line says that a process running as NetworkManager_t creating any file in a directory labelled etc_t will create it with the label net_conf_t.

Named File Transitions Policy

Eric Paris added a cool feature to the kernel that allows the kernel to label a file based on 4 characteristics instead of just three.  He added the base file name.  (Not the path).

Now we can write policy rules that state:

  • If the unconfined_t user process creates the ".ssh" directory in a directory labelled admin_home_t, then it will get created with the label ssh_home_t.

    filetrans_pattern(unconfined_t, admin_home_t, dir, ssh_home_t, ".ssh")
  • If the staff_t user process creates a directory named public_html in a directory labeled user_home_dir_t it will get labeled

    http_user_content_t. filetrans_pattern(staff_t, user_home_dir_t, dir, http_user_content_t, "public_html")
Additionally we have added rules to make sure if the kernel creates content in /dev it will label it correctly rather then waiting for udev to fix the label.              

filetrans_pattern(kernel_t, device_t, chr_file, wireless_device_t, "rfkill")

Bottom line. 

There should be less occurrences of accidental mislabels by users and hopefully a more secure and better running SELinux system.

Fedora 16 New SELinux Feature part III - permissivedomains module

$
0
0
As has been stated in previous blogs we have three types of unconfined processes on Fedora. 
  1. We have unconfined_domain() system processes.  initrc_t, init_t, kernel_t, ...
  2. We have unconfined_domain() user processes. unconfined_t,
  3. We have permissivedomains
Up until now you can remove unoconfined system processes by disabling the unconfined.pp module.

semodule -d unconfined

You can disable the unconfined users by removing unconfined user mappings and then disabling unconfineduser.pp

# semanage login -m -a staff_u __default__
# semanage login -m -a staff_u root
You might need to log out and back in now as sysadm_t and make sure there are no unconfined_u/unconfined_t processes running. Also make sure that you do not have any entries in /etc/sudoers for unconfined_t or files left over in /tmp or /var/db/sudo.
# semanage user -d unconfined_u
# semode -d unconfineduser

But you could not get rid of permissive domains, since the permissive flag was in individual policy modules.  In F16 we re-factored all of the permissive domain declarations into a new module called permissivedomains.pp.  If you want to remove all permissive domains from your system
you can execute

semodule -d permissivedomains

# semanage permissive -l
Builtin Permissive Types

Customized Permissive Types



This will give you a fully locked down machine.

Fedora 16 New SELinux Feature part IV - Shrinking policy

$
0
0
Back in July the systemd team was trying to decrease the boot time on early versions of Fedora 16.  They found that with a Solid State disk, SELinux policy load and relabel was quickly becoming the biggest pig as far as boot time.  So they added some log messages that showed how long it was taking to just read the selinux policy off of disk and load it into the kernel.

Lennart Poettering announced systemd 32 with the following message.

Primarily bugfixes, and one really cool improvement: we can now load the SELinux policy without having to reexecute ourselves. This is much
prettier and saves up to 70ms or so. I also added some basic profiling output for SELinux which unfortunately shows that SELinux costs around
5s on every boot on f16 (and that on my really fast machine!). Sad. 

Look for output like this:

[   10.727004] systemd[1]: Successfully loaded SELinux policy in 3s 270ms 896us.
[   10.769204] systemd[1]: Successfully loaded SELinux database in 41ms 700us, size on heap is 460K.
[   11.943903] systemd[1]: Relabelled /dev and /run in 1s 125ms 738us.

He even added these lines to every boot, so everyone would know how much time SELinux was costing them on boot. 

Nothing like public embarrassment to make you take action. 

Shame is a great motivator. :^(

I decided to take a look at the policy using the sesearch tools.  I wanted to figure out where all the rules were coming from, and whether we had some duplicates we could remove.  The first thing I noticed was there were thousands of rules related to network ports.  To me there seemed to be way to many.  I began to investigate and found that M4 macro expansion was the problem.

SELinux policy is written using m4.  Over the years we have written lots of macros which policy writers take advantage.   We call these macros interfaces.  Another feature of SELinux policy is the use of attributes.  Attrinbutes are a way of grouping lots of types (init_t, httpd_t) together.  You can create a new user type say staff_t and add an attribute say usertype.  Now you write rules regarding the usertype that affect all users.

allow usertype etc_t:file read;

SELinux also defines network port attributes like port_type and reserved_port_type.  All network ports get the attribute port_type and all ports < 1024 get the attribute reserved port type.  Well M4 has a cool feature "negation".   SELinux policy was using negation in many places including defineing unreserved_ports.  For example in Fedora 15 we have an interface that says.

interface(`corenet_tcp_bind_all_unreserved_ports',`
    gen_require(`
        attribute port_type, reserved_port_type;
    ')

    allow $1 { port_type -reserved_port_type }:tcp_socket name_bind;
')



All types that need to bind to ports > 1023 would then using this interface.

/usr/bin/ssh (ssh_t) needs to be able to setup alternate ports to allow a tunnel connection between a remote sshd service and the local machine, so we allow it to bind to any port > 1023 using the following line:

corenet_tcp_bind_all_unreserved_ports(ssh_t)

Seems like a simple rule to add, until you understand how m4 works with negation.  M4 expands out all the attributes into their types and then writes a rule for each type that matches.  A rule like this could end up adding 100s of allow rules.  For every type that is a port_type and not a reserved_port_type, a rule would be written allowing ssh_t to bind to the port.

allow ssh_t amqp_port_t:tcp_socket name_bind;
allow ssh_t asterisk_port_t:tcp_socket name_bind;
...

I found that if I defined a new attribute "unreserved_port_type", and rewrote the interface to something like.

interface(`corenet_tcp_bind_all_unreserved_ports',`
    gen_require(`
        attribute port_type, reserved_port_type;
    ')

    allow $1 unreserved_port_type:tcp_socket name_bind;
')


I ended up with only one rule generated by

corenet_tcp_bind_all_unreserved_ports(ssh_t)

allow ssh_t unreserved_port_type:tcp_socket name_bind;

Turns out we had lots and lots of interfaces where we used the negation.

    dontaudit $1 { port_type -port_t }:dccp_socket name_bind;
    files_read_all_dirs_except($1, $2 -shadow_t)

I went through the entire policy and switched to using only attributes like unreserved_port_type attributes and shrunk the size of policy by about 80 %.

What is really nice, you can check the size of policy using seinfo.
----------------------------
As time went on F15 machine:
$ seinfo
Statistics for policy file: /etc/selinux/targeted/policy/policy.24
Policy Version & Type: v.24 (binary, mls)
Allow:          282444
Dontaudit:      184516


and on F16 machine:

$ seinfo
Statistics for policy file: /etc/selinux/targeted/policy/policy.26
Policy Version & Type: v.26 (binary, mls)
Allow:           88242
Dontaudit:       11302


Tools used to load the policy run about 3 times as fast.

Conclusion:

Tom London looked at the change on his machine and found

And comparing 'old vs. new' boot times, first the old:

Jul 28 06:39:29 tlondon systemd[1]: Startup finished in 3s 336ms 755us (kernel) + 11s 625ms 240us (initrd) + 28s 189ms 914us (userspace) = 43s 151ms 909us.

And now the 'new':

Jul 29 06:00:41 tlondon systemd[1]: Startup finished in 1s 844ms 542us (kernel) + 4s 999ms 977us (initrd) + 29s 239ms 766us (userspace) = 36s 84ms 285us.

6.5 seconds less in initrd.


A second feature of this change is we are now taking up probably 80% less kernel memory...

RHEL 6
# du -s /etc/selinux/targeted/policy/policy.24
6004    /etc/selinux/targeted/policy/policy.24

Fedora 16:

# du -s /etc/selinux/targeted/policy/policy.26
2156    /etc/selinux/targeted/policy/policy.26

And Fedora 16 has more domains, types and rules...

At some point I should probably back port these changes to RHEL6.

setrans is a handy little tool to analyze policy transitions

$
0
0
For several years we have had a SELinux tool set called setools that allows you to analyse policy.  I use sesearch and seinfo all the time for looking at policy.  setools includes a tcl/tk interface, called apol,  that allows you to ask really complicated questions in policy about whether one process and read/write a file, even through process transitions.  The problem is the GUI is a little clunky, and I don't like GUIs.

A few years ago I added python bindings for sesearch and seinfo to the setools/apol libraries.  These python interfaces are used within some of the semanage tool chain.  

I often see an AVC about one domain not being able to write to another domains files.  Usually these types of avc's are caused by passing an open file descriptor, like stdout, from one process to another process.    Sometimes I am puzzled by the relationship between the two domains.  I recently got an AVC about ldconfig_t not being able to write to a chr_file labeled mock_var_lib_t.   How does the ldconfig program even know about a chr_file labeled mock_var_lib_t?  How did did mock transition to the ldconfig domain? 

Well I wrote a tool, setrans, that helps answer these question.  The tool takes two domain/process types and attempts to see if the first
type can transition to the second type, and then print all of the intermediary types that it used to get from one domain to the other.

./setrans init_t httpd_t
init_t --> httpd_t

./setrans mock_t ldconfig_t
mock_t --> mount_t --> insmod_t --> initrc_t --> ldconfig_t

./setrans mock_t user_t
mock_t --> mount_t --> insmod_t --> initrc_t --> stunnel_t --> rlogind_t --> remote_login_t --> unpriv_userdomain --> user_t
mock_t --> mount_t --> insmod_t --> initrc_t --> crond_t --> user_t
mock_t --> mount_t --> insmod_t --> initrc_t --> getty_t --> local_login_t --> userdomain --> user_t
mock_t --> mount_t --> insmod_t --> initrc_t --> xdm_t --> gkeyringd_domain --> user_t

I know that it is not complete and will not show all paths, but it is pretty useful for quick analyses of the policy.

Making a domain "unconfined"

$
0
0
In a couple of previous blogs I talked about permissive and unconfined domains.

http://danwalsh.livejournal.com/24537.html?thread=176857
http://danwalsh.livejournal.com/42394.html

Today we had a question about how to I disable_trans on pam_console_t in Red Hat Enterprise Linux 6.
If you have used RHEL5 or have read one of the blogs above you will realize in RHEL5 we had a lot of booleans DOMAIN_disable_trans.  The idea was to run these domains without SELinux protection.  We quickly figured out that this was a bad idea.  Other confined domains would start failing because the process they were supposed to communicate with would be running with a different label.  Or files created by the disabled_trans DOMAIN would now get created with the wrong labels.  

In RHEL6 we introduced permissive domains, so that you could run the entire system locked down but pick a few process domains to run in permissive mode.  The nice thing about this is we can figure out what the domain wants to do and improve the policy.

Miroslav Grepl came up with a third solution to the problem today.  Basically if a administrator wants to just allow a domain to do what it wants, he can add a policy module that turns the domain into an unconfined domain.  This will work on all Fedora releases and RHEL5 as well as RHEL6.  And is a much better solution then the disable_trans boolean.

If you wanted to run pam_console_t as an unconfined domain, you would first create a file call mypam.te.

# cat mypam.te
policy_module(mypam, 1.0)
gen_requires(`
           type pam_console_t;
')
unconfined_domain(pam_console_t)
# make -f /usr/share/selinux/devel/Makefile
# semodule -i mypam.pp


Now pam_console_t will be an unconfined domain, but any confined domain that needs to interact with it will still work.  All of the file transition rules will still happen, so the system should stay labelled properly.  And no AVC messages will be generated about this domain.

Viewing all 181 articles
Browse latest View live