zondag 15 december 2013

finding file context files that do not end with a newline

file context files not ending with a newline cause annoying situations.

 #!/bin/bash --  
 #  
 # This script looks for file context files  
 # that do not end with a newline  
 #  
 REF_PATH="/home/dominick/Git/refpolicy"  
 for i in $(/bin/find $(printf "%s" "$REF_PATH") -type f -name "*.fc") ; do  
     [[ "$(/bin/tail -c 1 $i | /bin/tr -dc '\n' | /bin/wc -c)" -ne 1 ]] && printf "%s\n" "Fix me: $i"  
 done  
 exit $?  
 #EOF  

maandag 9 december 2013

Another idea

We have the sepolicy tool that has functionality that aims to make policy development easier. One great benefit is the single point of failure aspect it provides. By using the tool for policy development you reduce risk of typo's and syntax errors. If you have to type everything yourself manually then much can go wrong.

The tool also has it's drawback because you are bound to the functionality the tool provides but nothing stops you from manually editing the generated policy, and so that is pretty much a non-issue.

For some reason typo's and syntax errors are a pretty common thing for many policy developers, and so from that perspective it is probably a good idea to use the tool more often.

Anyhow, The reference policy provides a api "mechanism", and api's make life easier. The issue is that these api's are not checked until they are actually called or until a tool like sepolgen-ifgen is run on them. So if one writes api's manually then those api's might not work due to some stupid typos, but the typos are often not identified until some one calls the api's.

Back earlier we had this policy of not adding api's unless they are actually used. However the point was made that audit2allow cannot suggest an api to use if its not available and so we agreed that it is probably better to add various api's even if they are not used.

So adding api's that aren't used, and that might be written manually thus contain typos and syntax errors. That means that api's that have typo's in them might not work and we don't know about it because we do not use them.

He/She who fits the shoes wears them. I make typos in unused api's often. Just a few days ago i fixed two typos in admin interfaces that i made myself, and it annoys me. Because i am the type of person that likes to manually write his policy rather than depend on a tool (even though i know the tools purpose and i appreciate the issues it solves) I guess i am just stubborn sometimes.

To keep a long story short: It might be a good idea to create an api test script. Again not an all-inclusive test but just to determine whether it can be called or not. The sepolgen-ifgen tool might be able to help identifying issues as well.

Basically a script that just calls interfaces, templates, patterns etc to see if they build.

Api's are our calling cards. It's how callers see us. If we provide broken interfaces then that leaves a bad impression. That is why i think they deserve more attention because they are not there just for us but also for others.

quick script to check for unsupported device nodes by SELinux

 #!/bin/bash --  
 #  
 # This script checks for device nodes that are unsupported by SELinux  
 # Unsupported device nodes fall back to the device_t generic type identifier for content in /dev   
 # The script just finds all chars and blocks, then looks if any of them as associated with the device_t type identifier  
 # If any device node is associated with device_t sid then the script uses matchpathcon to determine if SELinux is aware of the device node  
 # If matchpathcon thinks the device node should be associated with the device_t type then the device node is unsupported by SELinux one way or another  
 #  
 IFS=$'\n'  
 recurse_char() {  
  for i in "$1"/*;do  
   if [ -d "$i" ];then  
     recurse_char "$i"  
   elif [ -c "$i" -a ! -L "$i" ]; then  
     echo "$(ls -alZ "$i")"  
   fi  
  done  
 }  
 recurse_block() {  
  for i in "$1"/*;do  
   if [ -d "$i" ];then  
     recurse_block "$i"  
   elif [ -b "$i" -a ! -L "$i" ]; then  
     echo "$(ls -alZ "$i")"  
   fi  
  done  
 }  
 for s in $(recurse_char /dev); do  
      if [ "$(echo $s | /usr/bin/awk -F " " '{ print $4 }' | /usr/bin/awk -F ":" '{ print $3 }')" == "device_t" ] ; then  
           IFS=" "  
           read -r bits owner group context char <<< "$s"  
           mpc=$(/usr/sbin/matchpathcon "$char")  
           if [ "$(echo $mpc | /usr/bin/awk -F " " '{ print $2 }' | /usr/bin/awk -F ":" '{ print $3 }')" == "device_t" ] ; then  
                echo "unsupported char device: $char"  
           fi  
      fi  
 done  
 for s in $(recurse_block /dev); do  
      if [ "$(echo $s | /usr/bin/awk -F " " '{ print $4 }' | /usr/bin/awk -F ":" '{ print $3 }')" == "device_t" ] ; then  
           IFS=" "  
           read -r bits owner group context block <<< "$s"  
           mpc=$(/usr/sbin/matchpathcon "$block")  
           if [ "$(echo $mpc | /usr/bin/awk -F " " '{ print $2 }' | /usr/bin/awk -F ":" '{ print $3 }')" == "device_t" ] ; then  
                echo "unsupported block device: $block"  
           fi  
      fi  
 done  
 exit 0;  
 #EOF  

donderdag 5 december 2013

How I think distribution maintainers can enhance quality assurance

Here is a list with things distribution maintainers can do to enhance quality assurance

1. Do proof reading.

This enhancement applies to some distributions more than others. Lets define those "active" distribution and "passive" distributions.

An active distribution is one that is constantly changing. Whereas a passive distribution is mostly "stale", and changes less frequent.

A property of active distributions is their activity. Fast development where Security policy must constantly be adapted to support these fast developments.

Maintaining policy for such scenarios is just hard work often. Things must be "fixed" quick and often. This is a recipe for human error.

Because often in the rush one tends to make assumptions, plain types and syntax errors, or other relatively simple mistakes.

Proof reading commits, and a fresh pair of eyes can save time here. By just spending a little day each day reviewing new commits such errors can be identified and fixed quickly.

Some of this proof reading requires humans for example identifying mistakes due to assumptions. Other proof reading can be automated, for example typos and syntax errors.

These human mistakes are often relatively harmless but sometimes they are harmful. The point i am trying to make is that this can be easily prevented.

For the record, i am not suggesting that this proof reading is for identifying complex issues. Because that is a but more complicated and probably takes a little more time

No instead i am suggesting that this method can filter out obvious errors. I can tell you from experience that this pay's off. Besides how hard is it to spend a little time regularly running a couple scripts on new commits to spot typos, syntax errors, and to spend five minutes a day reviewing yesterdays commits.

2. Test you policy for all common scenarios.

Policy can be built with various options. Distributions often do not use all these options. Problems can arise when you do not test building the policy with all options. This might be irrelevant in the short term because i head distribution maintainers think, if it works for us then why bother?

There are two reasons for that:

A. Your priorities might not align with the priorities of upstream, and for your own sake it is better to work with upstream. The more you divert the harder it gets to maintain your project. Merging new upstream releases becomes harder and take more time. By just making sure things work for all scenarios you increase chances of your changes being applied upstream. If you policy only works with a subset of options than upstream has little choice than to refuse the patch. To waste your time, upstreams time. its inefficient.


B. Besides. We know what SELinux is right. What defines SELinux. Its the flexibility and configurability. That's why i use SELinux as opposed to any of the other LSM-Based MAC systems. So as a distro maintainer i would actually advertise these properties. One obvious and easy way to do that is to make sure you project builds and installs in all common scenarios.

Sure there are limits to what you can support. Lets just use the same limits are upstream since we depend on eachother.

So, every once in a while. build your policy with different sets op options, to make sure that it builds. Also You might want to every onces in a while install it with various options that way you can identify bugs in the user space component.

Because this is not only an issue with policy, its also an issue with user space. User space must support all common policy and all its options.

3. Make sure that what you target at least works in common configurations.

If you target a daemon then it might be good to write a simple test for some of the common configurations. I am not suggesting all-inclusive tests. Just some default test to make sure the most obvious functionality works. It obviously requires some investments, at least initially but it might just mean the difference between a good or a bad impression.

4. Test your security goals.

Good, the processes you target can function and you have a way to verify that. But what about security? thats what we do all this for. Simple changes to the policy can have huge effects. By defining your security goals, and crucial properties of your security identifiers, you make it possible to verify that they meet your requirements over time. Run simple tests. We have great tools for that.
This can be automated perfectly

5. Other processes and SELinux

In essence SELinux is transparent to the user space. However user space components can be made aware of SELinux or can even be expected to manage parts of SELinux. For example setting security contexts on files. These programs are often written by parties that might not understand SELinux principles and concepts as well as some of us do.

This can affect the SELinux experience as a whole so its in our interest that these processes make the right decisions. One common mistakes is processes hardcoding security identifiers. Generally harmless but it harms experience and it can easily be prevented by loading a bare (dummy) policy and then checking dmesg or whatever to see if some processes are trying to use identifiers that do not exist. There are more conceivable tests imaginable.

These are just some ways distribution maintained can enhance quality assurance. Many of these point apply to both the security policy component as well as the user space component

Can SELinux be made simpler?

Disclaimer: this is just my opinion

This must be a trick question. There is no easy answer for this.

First we should define SELinux to be able to put the question into a context

SELinux has three components: The LSM-Based system in the kernel, the tools and libraries, and lastly security policy

We also need to determine what defines SELinux in compared to other LSM-Based systems in the kernel

The answer to the latter question is Flexibility and configurability. Thats what defines SELinux. It a main property of SELinux. There are other LSM-Based system with other properties for example SMAC (simple mandatory access control) That system is defined by simplicity (but needless to say it lacks flexibility/configurability, at least compared to SELinux)

It is easy to translate flexibility to complexity but the end result does not always have to be relatively complex

Another thing to consider are constraints, with that i mean that for example SELinux must be optional, additional. It must be an add-on to the existing Linux DAC framework

This prerequisite brings some more "complexity", There 3 more of those prerequisites (one of them is not optional for SELinux to work). To enforce mandatory integrity processes must be able to change type (role base access control).

The other two prerequisites are optional (must be able to compartmentalise, must be able to enforce confidentiality) (multi category security/multi level security)

Back to the question. We now have most considerations briefly explained.

I Believe The core of SELinux (the LSM-Based System) cannot be made simpler. It is already as simple as can be considering all the requirrments.
Can the tools and libraries make the experience simpler? Maybe a bit, but the main concepts and principles will still apply there is little one can do about that.

The last component is what most people experience: the security policy

So Lets look at the state of that. The policy can be build with the minimal set of requirements (e.g. only enforce integrity optionally/additionally e.g. by complementing traditional DAC)

So we already can exclude some complexity and we do. We have different policy models for different requirements. For example if you have confidentiality requirements, which adds complexity, then you need the mls policy model.

Lets look at a operating system: Fedora currently is a single distro that can basically considered general purpose. You can use it as a workstation, server, or your use case can be even more specific.
But a vendor does not know beforehand how you are going to use it, and so every scenario must be supported.

Here is the dilemma: security is never general. If you want to implement mandatory integrity/confidentiality in a flexible/configurable way by complementing traditional DAC on a general purpose system then you have a complex challenge on your hand which requires complex policy.

So compromises were made: Lets not enforce mandatory integrity on the whole system, but only a part of it. Its give and take. Fine now things are a bit simpler but its not cheap. Now user sessions by default are not contained. To me this is already a great compromise because it basically says, were leaving workstation scenarios out in the cold with regard to mandatory integrity in the user space

fortunately some level of mandatory integrity in the user space is still optionally available, but its a compromise and it does not get the attention that i think it deserves

So its all about compromises. We have some ability to make things "simpler" and we already apply it.

So how to make things (a bit) simpler and actually achieve security goals?

We could create "profiles". For example Fedora webs erver edition. is a profile for a web server. web servers have (relatively) specific properties. So that from a security perspective enables us to implement a relatively specific security policy for that profile. We just target the web server. This makes the policy "simpler"

Fedora Desktop edition has a policy that targets the user space.

Does this solve anything? Not really if you still end up focussing on specific cases. it might help a bit but its still a compromise. Unless of course you really commit to all the profules you defined.

There are more (less obvious) options but its all give and take, and its all with regard to the security policy implemented. The core of SELinux cannot be simplified ( with any significance) without SELinux losing its identity.

So what about setroubleshoot? That is a great success story when it comes to simplifying SELinux?! Not really. Its just a buffed audit2why with a lot of bloat. (no offence) Is still a program that cannot make security decisions for you. All it can do is parse. reference and make it easy to report issues. It does not know when to transition or not.

That is not because its a bad piece of software. its just that security policy is not something that is fixed so you cant hard-code solutions. and to put things into context and determine the security requirements and act on it requires a huge base of logic. Is it even worth trying to create that?

Think about it from a security perspective: do you easily trust a third party with security decisions that affect your lively hood? Do you trust some code to make security decisions for you?

And even if you do, youll miss out on the good still: configurability/flexibility.

Why not instead focus on learning the core principles/concepts, and enable people to implement mandatory integrity that is tailored to their specific requirement?

So how do you do that? CIL is a abstraction language/ compiler that aims to make this easier. Its is relatively simple and it can be used as a layer between a policy management program and the SElinux policy language. It makes things less pain full but still wont change the core principles and concepts.

What it does do is optimise. Optimization can, i guess, in some ways be translated to making things more pleasurable and there by perceivably simpler.

You ask me the question can SELinux be made simpler. my answer is no. but things can be improved and optimized. compromises can also be made

But it does not change anything to the core principles and concepts.

If you want (relatively) simple: look into Simple mandatory access control. You want "flexibility/configurability" embrace selinux

For example on the one hand we make things "simpler" by by default not targeting user sessions, But on the other hand we enable an optional security model that adds a layer of complexity to achieve compartmentalization.

Its all a matter of priorities

zaterdag 1 december 2012

Anatomy of a SELinux policy module: Dropbox

I was asked to write a SELinux policy module for Dropbox. For obvious reasons i do not use this user application myself but i was willing to make an exception for the sake of writing a SELinux policy configuration for Dropbox.

The module was designed for and developed on a Fedora 18 (Beta) system.

Before i start designing and writing a policy configuration for some application i usually do my home work first. That means reading up on the application as much as i can so that i have an idea what to expect.

In this case i already had a rough idea about the applications functionality. I was interested in seeing what is installed where and when.

And so i downloaded and extracted two packages from this location:

https://www.dropbox.com/install

I focussed on this package:

https://dl-web.dropbox.com/u/17/dropbox-lnx.x86_64-1.6.2.tar.gz

and also had a quick look at this:

https://www.dropbox.com/download?dl=packages/fedora/nautilus-dropbox-1.4.0-1.fedora.x86_64.rpm

Basically i downloaded both packages and extracted it to see what was in them.

The dropbox-lnx.x86_64-1.6.2.tar.gz package is expected to be downloaded to "~"  and to be extracted there. It extracts a directory called ".dropbox-dist" with various files in it.

The installation guide suggests that one runs the "dropboxd" file that is location in the extracted "~/.dropbox-dist"  location.

And so i decided to just try it out.

As it turns out the dropboxd programs runs another file in that location called "dropbox". Another file in that directory called "library.zip" turned out to be a "hard link" to " dropbox". I was also able to identify plenty library files by their ".so" extensions.

Anyways; A graphical window popped up and presented me with a series of questions. I followed the directions and when i was done the window exited and the process installed two more directories in my home directories called "~/.dropbox" and "~/Dropbox"  respectively.

The " ~/.dropbox"  directory has various files that seem to be configuration files of some sorts and the "~/Dropbox" directory is the location that gets synchronized.

Now i' ve had a rough idea of the locations and the nature of the files that were installed.

The next step was to think about design.

Were using the common security models available to us: Role based access control and Type enforcement. The aim is to improve integrity of our processes and files.

We must also do our best to support as much of the applications functionality as we possibly can.

We need to maintain a sub-tile balance between usability and security.

Designing policy configuration for applications that sit on top of a Desktop environment is more complicated than a text application that you can for example run from a console because they usually interact with components on the Desktop environment and operate on files maintained by the these components.

In a stock Fedora SELinux policy configuration most of the Desktop enviroment is not targeted. The result of this design decision is that components of the Desktop enviroment run with the same attributes and permissions as the user running them.

For us that means that we either target each Desktop environment component and each file they maintain that Dropbox interacts with, or we allow our targeted Dropbox application to interact with the components operating, and operate on files they maintain, with the attributes and permissions of the user.

I decided to go with the latter for simplicity.

With that in mind i set out some humble security goals to achieve:

1. Protect user application configuration, data and cache files as much as possible.
2. Protect and contain the Dropbox application and process as much as possible.

What follows now is my current SELinux policy configuration for Dropbox. The nautilus plugin (nautilus-dropbox-1.4.0-1.fedora.x86_64.rpm) is NOT supported. At least not currently.

This because i refuse to install it because it depends on libgnome which in turn depends on Orbit and Bonobo and i will do just about anything to not have that installed.

Here is the configuration. Below the configuration i will touch on its properties in detail:

1. The ~/mydopbox/mydropbox.te Type enforcement source policy file:

policy_module(mydropbox, 1.0.0)

attribute dropbox_domain;

type dropbox_exec_t;

type dropbox_home_t;
userdom_user_home_content(dropbox_home_t)

type dropbox_tmp_t;
userdom_user_tmp_content(dropbox_tmp_t)

type dropbox_tmpfs_t;
userdom_user_tmpfs_content(dropbox_tmpfs_t)

type dropbox_port_t;
corenet_port(dropbox_port_t)

allow dropbox_domain self:capability dac_override; # mount
allow dropbox_domain self:netlink_route_socket r_netlink_socket_perms;
allow dropbox_domain self:process { execmem signal };
allow dropbox_domain self:shm create_shm_perms;
allow dropbox_domain self:tcp_socket create_stream_socket_perms;
allow dropbox_domain self:udp_socket create_socket_perms;

allow dropbox_domain dropbox_home_t:dir manage_dir_perms;
allow dropbox_domain dropbox_home_t:file manage_file_perms;
allow dropbox_domain dropbox_home_t:sock_file manage_sock_file_perms;
userdom_user_home_dir_filetrans(dropbox_domain, dropbox_home_t, dir, ".dropbox")

allow dropbox_domain dropbox_tmp_t:file { manage_file_perms mmap_file_perms };
files_tmp_filetrans(dropbox_domain, dropbox_tmp_t, file)

can_exec(dropbox_domain, dropbox_exec_t)

kernel_getattr_core_if(dropbox_domain)

corecmd_exec_shell(dropbox_domain)

corenet_tcp_bind_generic_node(dropbox_domain)
corenet_tcp_sendrecv_generic_if(dropbox_domain)
corenet_tcp_sendrecv_generic_node(dropbox_domain)
corenet_udp_bind_generic_node(dropbox_domain)
corenet_udp_sendrecv_generic_if(dropbox_domain)
corenet_udp_sendrecv_generic_node(dropbox_domain)

corenet_sendrecv_http_client_packets(dropbox_domain)
corenet_tcp_connect_http_port(dropbox_domain)
corenet_tcp_sendrecv_http_port(dropbox_domain)

allow dropbox_domain dropbox_port_t:{ tcp_socket udp_socket } name_bind; # temporary workaround: 17500

dev_list_sysfs(dropbox_domain)
dev_read_sysfs(dropbox_domain)
dev_read_urand(dropbox_domain)

dev_dontaudit_getattr_all_blk_files(dropbox_domain) # panic
dev_dontaudit_getattr_all_chr_files(dropbox_domain) # panic

fs_getattr_tmpfs(dropbox_domain)
fs_getattr_xattr_fs(dropbox_domain)
fs_rw_inherited_tmpfs_files(dropbox_domain) # this is that xserver shm thing

auth_read_passwd(dropbox_domain)

init_getattr_initctl(dropbox_domain)

libs_exec_ldconfig(dropbox_domain)

mount_exec(dropbox_domain)
mount_manage_pid_files(dropbox_domain) # mount: read/write /run/mount/utab

sysnet_exec_ifconfig(dropbox_domain)
sysnet_read_config(dropbox_domain)

userdom_manage_user_home_content_dirs(dropbox_domain)
userdom_manage_user_home_content_files(dropbox_domain)
userdom_mmap_user_home_content_files(dropbox_domain) # libraries in ~/.dropbox-dist
userdom_user_home_dir_filetrans_user_home_content(dropbox_domain, dir) # cannot use named file transition due to random names
userdom_use_user_terminals(dropbox_domain)

optional_policy(`
 dbus_session_bus_client(dropbox_domain) # probably not actually optional
 dbus_connect_session_bus(dropbox_domain) # probably not actually optional
')

optional_policy(`
 gnome_read_generic_data_home_dirs(dropbox_domain) # searching ~/.local/share
 gnome_read_home_config(dropbox_domain) # ibus, might not be optional

 # hack
 gen_require(`
  type config_home_t;
 ')

 allow dropbox_domain config_home_t:dir setattr_dir_perms;
')
 2. The ~/mydopbox/mydropbox.if Interface source policy file:


Blogspot does not format this content properly: View/Get it here instead:

http://pastebin.com/zcfSK2n3


## Dropbox is a free service that lets you bring all your photos, docs, and videos anywhere.

#######################################
## 
## The role template for the dropbox module.
## 
## 
## 
## This template creates a derived domains which are used
## for dropbox applications.
## 


## 
## 
## 
## The prefix of the user domain (e.g., user
## is the prefix for user_t).
## 
## 
## 
## 
## The role associated with the user domain.
## 
## 
## 
## 
## The type of the user domain.
## 
## 
#
template(`dropbox_role_template',`
 gen_require(`
  attribute dropbox_domain;
  type dropbox_exec_t, dropbox_home_t, dropbox_tmpfs_t;
 ')

 ########################################
 #
 # Declarations
 #

 type $1_dropbox_t, dropbox_domain;
 userdom_user_application_domain($1_dropbox_t, dropbox_exec_t)
 role $2 types $1_dropbox_t;

 ########################################
 #
 # Policy
 #

 domtrans_pattern($3, dropbox_exec_t, $1_dropbox_t)

 ps_process_pattern($3, $1_dropbox_t)
 allow $3 $1_dropbox_t:process { ptrace signal_perms };

 allow $1_dropbox_t $3:process signull;
 allow $1_dropbox_t $3:unix_stream_socket connectto;

 allow $3 dropbox_exec_t:file { manage_file_perms relabel_file_perms };
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "dropbox")
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "dropboxd")
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "library.zip")

 allow $3 dropbox_home_t:dir { manage_dir_perms relabel_dir_perms };
 allow $3 dropbox_home_t:file { manage_file_perms relabel_file_perms };
 allow $3 dropbox_home_t:sock_file { manage_sock_file_perms relabel_sock_file_perms };
 userdom_user_home_dir_filetrans($3, dropbox_home_t, dir, ".dropbox")

 kernel_read_system_state($1_dropbox_t)

 corecmd_bin_domtrans($1_dropbox_t, $3)

 corenet_all_recvfrom_unlabeled($1_dropbox_t)
 corenet_all_recvfrom_netlabel($1_dropbox_t)

 logging_send_syslog_msg($1_dropbox_t) # might want to make this conditional if possible

 optional_policy(`
  dropbox_dbus_chat($1, $3) # probably not actually optional
 ')

 optional_policy(`
  xserver_user_x_domain_template($1_dropbox, $1_dropbox_t, dropbox_tmpfs_t) # might not be optional
 ')
')

########################################
## 
## Send and receive messages from
## dropbox over dbus.
## 
## 
## 
## The prefix of the user domain (e.g., user
## is the prefix for user_t).
## 
## 
## 
## 
## Domain allowed access.
## 
## 
#
interface(`dropbox_dbus_chat',`
 gen_require(`
  type $1_dropbox_t;
  class dbus send_msg;
 ')

 allow $2 $1_dropbox_t:dbus send_msg;
 allow $1_dropbox_t $2:dbus send_msg;
')

 
 3. The ~/mydopbox/mydropbox.fc File contexts source policy file:


HOME_DIR/\.dropbox(/.*)? gen_context(system_u:object_r:dropbox_home_t,s0)
HOME_DIR/\.dropbox-dist/dropbox(d)? -- gen_context(system_u:object_r:dropbox_exec_t,s0)
HOME_DIR/\.dropbox-dist/library\.zip -- gen_context(system_u:object_r:dropbox_exec_t,s0)
Declaring types, classifying them and making sure that SELinux knows what to label what

Note that the policy above is the current result. Many of the properties of Dropbox where discovered after studying the contents of the package by trial and error.

type dropbox_exec_t;
This is the declaration of the type of the dropbox executable files. Since "library.zip" is a hard link of "dropbox", we need to make sure that both are labeled identical. The file "dropboxd" is also a Dropbox user application executable file.

HOME_DIR/\.dropbox-dist/dropbox(d)? -- gen_context(system_u:object_r:dropbox_exec_t,s0)
HOME_DIR/\.dropbox-dist/library\.zip -- gen_context(system_u:object_r:dropbox_exec_t,s0)
Above is how we instruct SELinux about where these Dropbox application executable files are located and how they should be labeled.


type dropbox_home_t;
userdom_user_home_content(dropbox_home_t)
This is the declaration of the Dropbox user configuration content located in "~/.dropbox" as well as the interface call that classifies the type as " user home content".

HOME_DIR/\.dropbox(/.*)? gen_context(system_u:object_r:dropbox_home_t,s0)
Here we tell SELinux that the ~/.dropbox directory and everything in it should be labeled with type "dropbox_home_t" which is the Dropbox user home content type.

type dropbox_tmp_t;
userdom_user_tmp_content(dropbox_tmp_t)
Dropbox maintains a file in " $TMP". Here we declare a type "dropbox_tmp_t" for this file and we classify this file "user tmp content" by calling the "userdom_user_tmp_content() interface with the "dropbox_tmp_t" file type parameter.

SELinux does not have to be aware of the location of the file in "$TMP" since for reason that i will not touch on in this article it should not maintain any contexts in "$TMP". Hence there is no entry for this in the "~/mydropbox/mydropbox.fc"  file.

type dropbox_tmpfs_t;
userdom_user_tmpfs_content(dropbox_tmpfs_t)
Dropbox opens a GTK window when you first run it to guide you through the installation process. Dropbox also has i icon in the taskbar that opens a settings window if you select it. The result is that Dropbox interacts with X server and operates on content maintained by X server.

For this we have to declare a type for Dropbox shared memory in "/dev/shm". We classify this type "user tmpfs content".

There is no need to specificy a file context for this content as SELinux should not maintain file contexts in this locations for the same reasons as it should not maintain them in "$TMP".


type dropbox_port_t;
corenet_port(dropbox_port_t)
Dropbox listens on the UDP and TCP network for connections on port 17500. We Declare a type for this port object and classify the type "corenet_port". This will allow us to tell SELinux that Dropbox may only bind TCP and UDP sockets to ports that are classified "dropbox_port_t".

Ports are not files and thus their contexts should not be specified in the file context file (~/mydropbox/mydropbox.fc).

Instead we need to , after we installed the policy module package, manually label the 17500 UDP and TCP ports type "dropbox_port_t"

This is done by issuing the following command:

semanage port -a -t dropbox_port_t -p tcp 17500
semanage port -a -t dropbox_port_t -p udp 17500
You may have noticed that we have not yet classified our " dropbox_exec_t" user application executable file type.

You may also have notices that we have not yet declared and classified a type for the Dropbox process.

This is because of the properties of this application and it is also related to my design decision.

Dropbox runs Nautilus and Firefox on your behalf to open your "~/Dropbox"  location and to direct you to the "www.dropbox.com"  website respectively.

These two applications are currently not targeted in Fedora and i have decided to not do that either.

How can we tell SELinux that if Dropbox runs Nautilus or Firefox that it does that on behalf of the user and that SELinux thus should run these two applications with the attributes and permissions of the user rather than the attributes and permission of Dropbox?

This requires that we create a template because not all SELinux users are created equal. We need to use the "user role prefix" to declare a derived Dropbox process type. This will allow use to create rules that specify with which attributes and permissions Dropbox should run Nautilus and Firefox.

This is done in a template called "dropbox_role_template" that i have created in the "~/mydropbox/mydropbox.if"  interface file.

 type $1_dropbox_t, dropbox_domain;
 userdom_user_application_domain($1_dropbox_t, dropbox_exec_t)
 role $2 types $1_dropbox_t;
 
The above declares a derived dropbox process type "$1_dropbox_t" where "$1"  is the "user role prefix". It then goes on to classify this process "dropbox_domain"  This is done by assigning it a "type attribute"  that we i declared in the "~/mydropbox/mydropbox.te"  type enforcement file. You can find it on top, right below the policy module declaration.

Next we classify both the Dropbox process type as well as the Dropbox user application executable file type "user application domain". This interface has all the permissions needed to classify our process type "user application process" and our application executable file "user application executable file".

The last rule is a "Role based access control"  rule that allows the "calling" role access to the prefixed Dropbox type.

 Policy.

domtrans_pattern($3, dropbox_exec_t, $1_dropbox_t)

This rule is a domain transition rule, or if you like "process type transition rule". It tells SELinux that the "calling" user process type should transition to the derived Dropbox process type when it runs the Dropbox user application executable file.


 ps_process_pattern($3, $1_dropbox_t)
 allow $3 $1_dropbox_t:process { ptrace signal_perms };

The above rules allow the calling user process type to "ps" processes labeled with the derived Dropbox process type as well as ptrace it and send all signals to it.
logging_send_syslog_msg($1_dropbox_t) 

This will allow Dropbox to for example show up in "top", " ps x"  and it allows you to "strace", kill etc. the Dropbox process.

 allow $1_dropbox_t $3:process signull;
 allow $1_dropbox_t $3:unix_stream_socket connectto;

Here are some interesting rules. The first allows the derived Dropbox process type to send null signals to the calling user process type and the second one allows the derived Dropbox process type to connect to the calling user process type with a unix domain stream socket.

The processes here labeled with the "calling user process types"  aren' t actually the calling user. These are for example Nautilus or Firefox. Since we decided not to target them they are labeled with the " calling user process type".

In this case Dropbox probably wants to see if Nautilus is already running, and Dropbox probably wants to communicate with Nautilus using a unix domain stream socket.

These rules are problematic because they are coarse. You can't tell by just looking at these rules who "$3" or if you will the process labeled with the "calling user process type" really is. Is it Nautilus or is it Firefox? Maybe it another process that currently is not targeted.

Basically it allows Dropbox to send null signals and talk using a unix domain stream socket to any application currently not targeted labeled with the "calling user process type".

 allow $3 dropbox_exec_t:file { manage_file_perms relabel_file_perms };
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "dropbox")
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "dropboxd")
 userdom_user_home_content_filetrans($3, dropbox_exec_t, file, "library.zip")

These rules allow processes labeled with the " calling user process type" to "manage and relabel"  files labeled with the dropbox use application executable type " dropbox_exec_t".

Users need to be able to manage and relabel content in their home directory as they own it.

The other three rules are interesting as well. They use a pretty new feature called "named file type transitions",

These rules tell SELinux that if a process labeled with the " calling user process type" create files with named "dropbox, dropboxd and library.zip"  in directories that are labeled with the user home content type "user_home_t" that the files should be created with the dropbox user application executable file type "dropbox_exec_t".

This is a important rule because proper labelling of files is of vital importance to the integrity of SELinux policy enforcement.

When you extract the  "dropbox-lnx.x86_64-1.6.2.tar.gz"  into you home directory, this rule ensure that the Dropbox executable files automatically get the right security context.

The file context specification for these files that we added to " ~/mydropbox/mydropbox.fc"  ensure that if restorecon gets run on any and all of these files that they will stay labeled properly.


 allow $3 dropbox_home_t:dir { manage_dir_perms relabel_dir_perms };
 allow $3 dropbox_home_t:file { manage_file_perms relabel_file_perms };
 allow $3 dropbox_home_t:sock_file { manage_sock_file_perms relabel_sock_file_perms };
 userdom_user_home_dir_filetrans($3, dropbox_home_t, dir, ".dropbox") 

The same applies to the above except that this applies to Dropbox user home content and it applies to files, directories and sock files.

The named file transtion rule dictates that SELinux should make sure that processes with the calling user process type create directories with the name ".dropbox" in directories with type "user_home_dir_t" (~) with type "dropbox_home_t".

Note: I should probably allow allow processes with the calling process type to manage and relabel files with type dropbox_tmp_t as well dropbox_tmpfs_t.


 kernel_read_system_state($1_dropbox_t)

This rule allows the derived Dropbox process type to read generic system state files in "/proc", like for example "/proc/meminfo".

We added this rule (and some other rules that would normally go into the type enforcement file) here because it uses type attributes and were also using our "dropbox_domain" type attribute in our type enforcement file to write rules.

One can only assign type attribute to types. You cannot assign a type attribute to a type attribute and thus we decided to deal with this in this manner.

corecmd_bin_domtrans($1_dropbox_t, $3)

This is the rule that caused me to implement the "dropbox_role_template" template.

It is what enables us to tell SELinux that dropbox should run application that are not targeted with the "calling user process type".

Basically it dictates that when the derived Dropbox process type runs a file with the generic "bin_t"  "core command executable type" that the process type should transition from "$1_dropbox_t" (the derived Dropbox process type) to "$3" ( the calling user process type)

 corenet_all_recvfrom_unlabeled($1_dropbox_t)
 corenet_all_recvfrom_netlabel($1_dropbox_t)

These rules allow the derived Dropbox process type to recv from all unlabeled and netlabel network connections.

It is basically a rule that effectivily disabled SELinux network controls enforcement.

These rules are here because again they use type attributes and one cannot assign type attributes to type attributes. That means we cannot use our "dropbox_domain"  attribute to call these in our ~/mydropbox/mydropbox.te" file.


logging_send_syslog_msg($1_dropbox_t) 

This rule allows the prefixed Dropbox process type to send messages to syslog. Same as above it uses type attributes and so i had to add it here instead of in the type enforcement file.


 optional_policy(`
  dropbox_dbus_chat($1, $3) # probably not actually optional
 ')
This allows the derived dropbox process type to communicate using DBUS with processes that are labeled with the "calling user process type". Probably Nautilus or some Gnome Desktop environment compoment like GVFS.

Since None of them are targeted we are forced to allow the prefixed dropbox process type to communicate using DBUS with any process as long as its labeled with the "calling user process type".

We could have used raw policy to write these rules here but since DBUS is a "object manager" and also since its good to have a " dropbox_dbus_chat" interface we decide to create one (you can find it below the "dropbox_role_template" template in "~/mydropbox/mydropbox.if" and to call it in our own module.

The "optional_policy" block indicates that this module does not actually depend on the rule in the block. I was assuming that Dropbox does not depend on the presence of DBUS but i may well be mistaken.

 optional_policy(`
  xserver_user_x_domain_template($1_dropbox, $1_dropbox_t, dropbox_tmpfs_t) # might not be optional
 ')

This rule allows the derived Dropbox process type to interact with X server and to operate on files maintained by X server. It also makes our "dropbox_tmpfs_t" "user tmpfs content" available for use with X server.

I was under the impression that Dropbox does not depend on X server since on their website they claim that Dropbox works on "any Linux server" but again i may be mistaken.

allow dropbox_domain self:capability dac_override; # mount
allow dropbox_domain self:netlink_route_socket r_netlink_socket_perms;
allow dropbox_domain self:process { execmem signal };
allow dropbox_domain self:shm create_shm_perms;
allow dropbox_domain self:tcp_socket create_stream_socket_perms;
allow dropbox_domain self:udp_socket create_socket_perms;

These are what i call " self-rules". Basically rules where a source process labeled with a process type interacts with or operates on itself.

The first rule allow any Dropbox process type the "dac_override"  capability. This capability is needed to override discretionary access controls.

Dropbox runs the mount command with the derived Dropbox process type (rather than with a process type transition) which is a setuid command.

When the command is run your shell sessions current "pwd" is probably "~/.dropbox-dist"  since thats where you run dropboxd from. The root Linux user does (or might not) have access to that location as " $HOME"  might have the "0700" attibutes. The "dac_override"  access vector permission allow the process type to access it anyway from a SELinux perspective.

The second rule is probably to read the routing table. Dropbox is a network application and so i am not surprised that it needs these permissions.

The third rule allows all Dropbox process types to "execute anonymous memory", Basically memory that is world writable. It is usually a sign of bad programming practices but there are also legitimate use cases such as "just in time compiling". This rule also allows Dropbox process types to send generic signals to itself.

The fourth rule allows Dropbox processes to create shared memory. This is for X server interaction and is related to the " dropbox_tmpfs_t"  "user_tmpfs_content"  type.

The fifth and the sixth rule allows dropbox and any other process labeled with any dropbox process type to create tcp stream sockets and udp sockets. This is needed because Dropbox is listening on the network for connections (port udp/tcp 17500 dropbox_port_t)

allow dropbox_domain dropbox_home_t:dir manage_dir_perms;
allow dropbox_domain dropbox_home_t:file manage_file_perms;
allow dropbox_domain dropbox_home_t:sock_file manage_sock_file_perms;
userdom_user_home_dir_filetrans(dropbox_domain, dropbox_home_t, dir, ".dropbox")

These rules allow all Dropbox process types to "manage"  directories, files and sock files that are labeled with the "dropbox_home_t" " user home content type". This is configuration content amongst other things. Stuff that could use protecting to ensure optimal integrity.

The fourth rule is another named file type transition rule. It dictates that if any dropbox process type creates a directory with name ".dropbox"  in directories with type " user_home_dir_t"  which is "~"  that the directory be created with the "dropbox_home_t" type. Thus file transitioning from "user_home_dir_t" to "dropbox_home_t".


allow dropbox_domain dropbox_tmp_t:file { manage_file_perms mmap_file_perms };
files_tmp_filetrans(dropbox_domain, dropbox_tmp_t, file)

Dropbox maintains a file in "$TMP" with a random name. It also "mmaps" that file. The second rule dictates that if any Dropbox process type creates a file in a directory with type " tmp_t" that the file is created with the " dropbox_tmp_t"  " user_tmp_content" type. Since this file has a random name i have to use a regular file type transition and i cannot use a named file type transition.

can_exec(dropbox_domain, dropbox_exec_t)

The dropboxd process executes the dropbox "user application executable file"  Both dropboxd as well as dropbox are labeled with the " dropbox_exec_t"  type. This rule allows all Dropbox process types to execute files with the dropbox_exec_t type without a process type transition.


kernel_getattr_core_if(dropbox_domain)

I am not sure why but Dropbox wants to get attribute of the core if file in "/proc". Fine.


corecmd_exec_shell(dropbox_domain)

This rule allows all Dropbox process types to run a shell without a process type transition.


corenet_tcp_bind_generic_node(dropbox_domain)
corenet_tcp_sendrecv_generic_if(dropbox_domain)
corenet_tcp_sendrecv_generic_node(dropbox_domain)
corenet_udp_bind_generic_node(dropbox_domain)
corenet_udp_sendrecv_generic_if(dropbox_domain)
corenet_udp_sendrecv_generic_node(dropbox_domain)

corenet_sendrecv_http_client_packets(dropbox_domain)
corenet_tcp_connect_http_port(dropbox_domain)
corenet_tcp_sendrecv_http_port(dropbox_domain)

allow dropbox_domain dropbox_port_t:{ tcp_socket udp_socket } name_bind; # temporary workaround: 17500

Network related rules. The first block of rules are "generic" in the sense that it basically does not support the use of the SELinux network controls. Or it supports them in the most generic way.

The second block allows all dropbox process types to connect to TCP ports that are labeled with the "httpd_port_t"  port type. Dropbox connects to "tcp:443" (their Dropbox web application). It allow Dropbox to send and receive client packets that are labeled with the httpd packet type and it allows Dropbox to send and receive traffic from http classified ports.

The last rule of the bunch allows all dropbox process types to bind TCP and UDP sockets to ports that are labeled with the "dropbox_port_t"  port type. We labeled UDP/TCP 17500 with that type.

dev_list_sysfs(dropbox_domain)
dev_read_sysfs(dropbox_domain)
dev_read_urand(dropbox_domain)

Above allows all Dropbox process types to list directories with the generic "sysfs_t" type. This is generic content in "/sys". The second rule allow Dropbox to actually read files with this type.

The third rule allows all Dropbox process types to read character device nodes with "urandom_device_t" device node type. E.g. /dev/urandom.

dev_dontaudit_getattr_all_blk_files(dropbox_domain) # panic
dev_dontaudit_getattr_all_chr_files(dropbox_domain) # panic

"Dontaudit" is a access vector that tells SELinux to silently block a specified interaction or operation.

In the above case we silently deny any Dropbox process type to get attributes of all block and character files that are classified "device_node".

To expose " hidden denials" one needs to issue the "semodule -DB"  command which will build the policy database without any " dontaudit" rules. To reinsert the "dontaudit" rules simply issue 'semodule -B".

fs_getattr_tmpfs(dropbox_domain)
fs_getattr_xattr_fs(dropbox_domain)
fs_rw_inherited_tmpfs_files(dropbox_domain) # this is that xserver shm thing 

This allow all Dropbox process types to get attributes of filesystems with the "tmpfs_t"  filesystem type. This a common access vector for processes that maintain content in the " /dev/shm"  location.

The second rule allow any Dropbox process type to get attribute of any filesystem that supports extended attributes. E.g. types that are classified "filesystem type" as well as "Extended attribute file system". This is to allow Dropbox to stat "/"  which is a common thing to do.

The Third rule is related to X server interaction. I am not sure why it is the way it is but it has been this way for as long as i can remember. Inherited means that it doesnt actually opens the "generic tmpfs" file but it still reads and writes it. That means that either Dropbox got passed a open file or that there is a leaked file descriptor. Since, if i remember correctly , things will break if you do not allow this, i assume that X server or whatever passed the open file to Dropbox and dropbox reads and write it.

Note that the file is not labeled with the "dropbox_tmpfs_t"  "user tmpfs content" file type either. Instead it is labeled with a generic type for content in "/dev/shm".


auth_read_passwd(dropbox_domain)

Allow all Dropbox process types to read files with the passwd_file_t file type. E.g. "/etc/passwd" amongst others.

This could simply be a side effect from Dropbox running a bash shell. The shell needs to read the password file in order to get the information needed for the shell prompt (user name etc.)


init_getattr_initctl(dropbox_domain)

Get attributes of initctl (named pipe i believe it was)

libs_exec_ldconfig(dropbox_domain)

Execute ldconfig program without a process type transition. It probably runs ldconfig on that file it maintains in "$TMP"  that it also mmaps.

mount_exec(dropbox_domain)
mount_manage_pid_files(dropbox_domain) # mount: read/write /run/mount/utab
Execute the mount command without a process type transition. Not sure what it does with mount.

Mount reads and write /run/mount/utab which is labeled with the mount pid file type.

sysnet_exec_ifconfig(dropbox_domain)
sysnet_read_config(dropbox_domain)

Executes ifconfig command without a process type transition and read files that are classified network configuration files (net_conf_t) This is probably "/etc/resolve.conf"

userdom_manage_user_home_content_dirs(dropbox_domain)
userdom_manage_user_home_content_files(dropbox_domain)
userdom_mmap_user_home_content_files(dropbox_domain) # libraries in ~/.dropbox-dist
userdom_user_home_dir_filetrans_user_home_content(dropbox_domain, dir) # cannot use named file transition due to random names
userdom_use_user_terminals(dropbox_domain)

These are interesting. These rules allow all dropbox process types to operate on content maintained by processes labeled with the user process type.

In some cases this is bad news but in our case we will have to embrace it.

Here is why

The first two rules allow all Dropbox process types to manage directories and files that are labeled with the generic user home content type (user_home_t)

I decided to keep "~/Dropbox" location generic. The idea of Dropbox is that users can "drag and drop"  content in there to synchronise with the Dropbox. Usually that is program Photos (~/Pictures), documents (~/Documents), maybe tunes (~/Audio or ~/Music). These locations should be generic since they are not related to any single user application.

"Drag and dropping"  equals "moving" if done on a single partition. When you move a file you also move its context and so we want "~/Dropbox" to have the same type as the content that is expected to be dropped in there.

If a user is stupid enough to drop his " ~/.gnupg" or "~/.ssh" directory into the "~/Dropbox" then the dropbox process type will not be able to access that content. E.g. it wont be able to synchronize your sensitive files.

Unless ofcourse if you really want it to. In that case you would first manually relabel the content to the generic user home content type (user_home_t) with the "chcon" command and them drop it into your Dropbox.

So leaving "~/Dropbox" type "user_home_t"  and allowing Dropbox to manage files and directories with the "user_home_t"  seems to me the sensible thing to do here.

The third rule is a bit more controversial. The  Dropbox archive copies library files into ~/.dropbox-dist. I decided to only give "dropboxd, dropbox and library.zip"  in there a private type for simplicitly but the side effect is the now all dropbox process types need to mmap generic user home content files (the libraries).

The fourth rule is a file type transition rule. The Dropbox installed creates "~/Dropbox" which we want to have type "user_home_t". But this location has a fixed name so we could have used a named file transition rather than a normal file transition. However during installation Dropbox also create a directory in "~"  with a random name andso we could not use a named file type transition for that anyways, and so it was decided to use this rule

Basically it dictates that if any Dropbox process type creates a directory in a directory with type "user_home_dir_t"  (~) that the directory should be created with the "user_home_t" generic user home content type.

The fifth rule allows any dropbox process type to "use"  user terminals. This will allow Dropbox to print any messages to the terminal when you run "./dropboxd"

optional_policy(`
 dbus_session_bus_client(dropbox_domain) # probably not actually optional
 dbus_connect_session_bus(dropbox_domain) # probably not actually optional
')

This will allow anydropbox domain to become a DBUS session bus client and to aquire service on the session bus. Since i was under the assumption that DBUS is not a requirement for Dropbox i wrapped these rules in a "optional_policy"  block that basically tells the policy compiler that these rules are optional. E.g. if they are not available for use then do not sweat it and proceed.


optional_policy(`
 gnome_read_generic_data_home_dirs(dropbox_domain) # searching ~/.local/share
 gnome_read_home_config(dropbox_domain) # ibus, might not be optional

 # hack
 gen_require(`
  type config_home_t;
 ')

 allow dropbox_domain config_home_t:dir setattr_dir_perms;
')

These rules are related to content in X desktop (XDG) standard locations. Basically all Dropbox process types need to be able to read IBUS files in "~/.config" These IBUS files are labeled with the generic "config_home_t"  user home content type.

Dropbox is probably using some Gnome library that does this on behalf of Dropbox. It also wants to set attributes of generic "config_home_t"  directories and search generic "data_home_t"  directories (~/.local/share).

Okay... I think i touched on everything now, except...

How to actually implement this policy

Create a working directory and change directory into it:

mkdir ~/mydropbox; cd ~/mydropbox;
Create three "mydropbox"  source policy files:

touch mydropbox.{te,if,fc}
Copy the policy above in their respective files

Next, create another file:

touch myunconfineduser.te

and paste the following in that file:

policy_module(myunconfineduser, 1.0.0)

gen_require(`
 type unconfined_t;
 role unconfined_r;
')

dropbox_role_template(unconfined, unconfined_r, unconfined_t)

This is what actually calls or if you will activates the "dropbox_role_template()"  that i have created in the "~/mydropbox/mydropbox.if"  interface file.

Now build the two policy packages. You may or may not need to install the "selinux-policy-devel"  package for this:

Make -f /usr/share/selinux/devel/Makefile

Next install the policy packages that were created in "~/mydropbox":

sudo semodule -i mydropbox.pp myunconfineduser.pp

If you have already installed Dropbox then make sure to restore the context of the "~/.dropbox" directories and the "dropboxd, dropbox and library.zip"  files in "~/.dropbox-dist":

restorecon -R -v -F ~
If you have not yet installed Dropbox:

cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -
~/.dropbox-dist/dropboxd

Disclaimer:

I do not encourage nor endorse the use of Dropbox. Security means taking responsibility. Do not trust your content to third parties.

maandag 8 oktober 2012

Easy ways to help improve refpolicy contrib

Here is what you can do to help improve refpolicy contrib for your distro and everyone else:

1. See if the file context specification from the various modules in refpolicy contrib match the locations of the corresponding packages that your distribution uses.

Here is how i do that on Fedora:

I basically check each modules file context files.

Find which package installs the executable file, either with the full path or if my package manager cannot find that using a wild card:

yum whatprovides /usr/sbin/someapp
or if it cannot find that:
yum whatprovides *\someapp

Then you should figure out which (applicable) locations that package installs.

Applicable locations are among others:

/etc/someapp /etc/sysconfig/someapp /etc/default/someapp /var/lib/someapp /var/log/someapp /var/spool/someapp /etc/init.d/someapp /etc/rc.d/init.d/someapp /var/run/someapp /var/cache

In Fedora i use the handy repoquery tool for that. This tool allows me to list the files that a specificied package installs without me actually having to install the package

Example:

repoquery -ql someapp | less

 Labeling files properly is very important for SELinux operation and so you can improve your distributions SELinux experience by making use applicable files and locations are labeled correctly by fixing or adding the appropriate file context specification.

2. Somewhat related to (1): label service etc files with a declared private type for etc files and allow the service to read files it owns with the private type, then also allow the "service"_admin() to find and manage content with that type.

In the past we only use to label service etc files with a private"files config file" private type if the file has sensitive information.

Later we came up with an idea to confine root using "service"_admin interfaces that give the caller access to manage a particular service and its files.

However we do not want to give the "service"_admin access to manage generic etc_t files since that will allow the process to manage things it shouldnt, instead of just the configuration files for the service that the caller is allowed to manage.

So we need to find each config file a confined service owns label that with a declared "files_config_file" file type, allow the owning service to read applicable content with that type and allow the service admin to get to and manage content with that type.

You can use the method of (1) to find which etc files a package installs where

Then if needed declare a new files_config_file type

type someapp_conf_t;
files_config_file(someapp_conf_t)

Then make sure the file or directory is labeled correctly in the file context file. Some examples:

Single configuration file:

/etc/someapp\.conf -- gen_context(system_u:object_r:someapp_conf_t,s0)

A configuration directory and all its contents:

/etc/someapp(/.*)? gen_context(system_u:object_r:someapp_conf_t,s0)

Then allow the service domain type to read the content:

in case of a single file:

allow someapp_t someapp_conf_t:file read_file_perms;

in case of a directories and its contents:

read_files_pattern(someapp_t, someapp_conf_t, someapp_conf_t)

If your service domain type is not already allowed to read generic etc_t files (e.g. if it does not have a rule similar to for example: files_read_etc_files(someapp_t) then you will also need to allow the service domain type to traverse etc_t directories so that it can actually get to there:

files_search_etc(someapp_t)

If the module has a service admin interface, for example someapp_admin in the someapp.if interface file, then add the rules that will allow the caller to get to and manage content with the new type:

a. Import the type by adding for example;

type someapp_conf_t; 

to the existing "gen_require(`')" block on top of the interface.

b. Add the rules to allow caller to get to and manage the content with the new type , for example:

files_search_etc($1)
admin_pattern($1, someapp_conf_t)

Note: also consider environment files in /etc/sysconfig. We would want the service administrator to be able to manage those as well.

If you are unsure about some specifics then look into existing source policy modules. Much efford goes into writing these modules as consistently as possible.

This allows you to see patterns easily and will help you read the policy.

zondag 30 september 2012

Determine whether Cron can execute jobs on behalf of the user with login user SELinux permissions

Cron would run jobs on behalf of users in a "cronjob" domain. This domain is reasonable restricted compared to the domain in which most users operate.

Fedora changed this behaviour to allow Cron to execute these jobs in the default login user domain of the user that owns the job.

Recently i added a boolean to Reference policy that enables one to tune the policy to allow Cron to run user cronjobs in the default login user domain conditionaly.

By default Cron will still execute the jobs in the Cron job domain but if you toggle the cron_userdomain_transition boolean to true then Cron will run the jobs in the default login user domain of the user owning the job.

This allows Cron to run jobs with the SE-Linux permissions that the owner of the job has.

Cron is SELinux aware. It queries the policy to see to which domain it should transition when running a job.

It does not do a automatic domain transition because it does not actually execute the Cron job. Instead if uses "setexec" to domain transition.

It looks to see to which domains the Cron job file is a entrypoint. Then it needs to be able to process transition to that domain and then it checks the default login user domain of a user and with this information it determines in which domain to execute the job

By default:

allow cronjob_t user_cron_spool_t:file entrypoint;
allow crond_t cronjob_t:process transition;

Then there is a default context of for staff this is for example:

system_r:crond_t:s0        staff_r:cronjob_t:s0

But when you tune the policy with cron_userdomain_transition then these rules will be replaced by:

allow $1 user_cron_spool_t:file entrypoint;
allow crond_t $1:process transition;

Where $1 is the calling login user domain, and then it will look up the default login user domain and role, for staff this is for example:

# semanage user -l | grep staff_u
staff_u         user       SystemLow  SystemLow-SystemHigh           staff_r sysadm_r system_r unconfined_r
That means:

"staff_r:staff_t"

Then Cron daemon has permission to run the job in the staff domain with the staff role.

The benefits of running jobs in the login user domain are that now your Cron job can interact with your processes and operate on your files as if it were you interacting with your processes and operating on your files.

Needless to say that other SE-Linux rules that apply to you now also apply to your Cron jobs.

The policy may still have some rough edges but it was tested on Gentoo and is said to work. I did make some changes after that but hopefully i have not introduced regression.

Currently Redhat distributions do not have this cron_userdomain_transition boolean and i am not sure if she will adopt it.

woensdag 27 juni 2012

Hard coded types create hard dependencies on selinux policy

Long time no see. I believe that applications like sandbox (sandbox_web_t) and sshd (chroot_user_t) hard code types. I do not like that but my personal opinion aside; This creates hard dependencies on SELinux policy. If you do not have a policy that provides these types then you will end up with broken functionality. I believe one example is that sandbox does not work in Debian because Debian selinux-policy does not provide the types that sandbox requires. That is all folks.

dinsdag 23 augustus 2011

Git daemon and SELinux with RHEL6

RHEL6 does not ship with a manual page for configuring Git daemon SELinux policy, and so decided to publish a demonstration on youtube:

Part 1. Git system daemon, shared repositories.

http://www.youtube.com/watch?v=vgm89P5nbBQ

Part 2. Git session daemon, personal repositories.

http://www.youtube.com/watch?v=XHEPj80217o

By the way you can look at the manual page (source) here:

http://git.fedorahosted.org/git/?p=selinux-policy.git;a=blob;f=man/man8/git_selinux.8;h=e9c43b190c394f8ea7e68d9dd29f45c831340bf5;hb=ccadbe7d6ae709cdfd3b06d496477e069a2f13ee

dinsdag 8 februari 2011

selinux q&a

23:15 < someone> What's the difference between httpd_sys_rw_content_t and
httpd_sys_content_rw_t?
23:19 < dgrift> none
23:19 < dgrift> their aliased
23:19 < dgrift> theyre

zondag 6 februari 2011

frequently asked questions: selinux booleans in detail.

Q: "btw, anyone know if each of the selinux booleans are documented in detail somewhere?"

A: two levels of detail here:

1. semanage boolean -l | grep httpd_enable_homedirs
A written description (usually not very detailed) for the "httpd_enable_homedirs" boolean.

2. sesearch --allow -SC -T | grep httpd_enable_homedirs
All the "allow" type statement rules and type transition rules related to the "httpd_enable_homedirs" boolean. Very detailed but hard to interpret.

common issues -- part 1

22:13 < _Tassadar> hi
22:14 < _Tassadar> http://fedoraproject.org/wiki/SELinux/samba <- i'm reading this document, on how to
configure selinux to allow samba to share a certain directory
22:14 < _Tassadar> now i'd like to share /data/files so i issued chcon -t samba_share_t /data/files
22:14 < _Tassadar> it worked, according to ls -Z
22:14 < _Tassadar> but access is still denied
22:15 < _Tassadar> should i recursively set that label to every file in the share as well?
22:16 < SwifT> _Tassadar: (without reading the file) check your AVC denials on what is actually denied, but I
would say "yes, you'll probably want to recursively set the type"
22:17 < _Tassadar> SwifT: what is the best way to check my AVC denials?
22:17 < _Tassadar> it's a server, i don't have any gui tools
22:20 < dgrift> _Tassadar: try Fedora manage confined services
22:20 < _Tassadar> hm no new entries appear in /var/log/audit/audit.log
22:20 < SwifT> _Tassadar: depends on your system log configuration; try tail -f /var/log/messages or
/var/log/audit.log
22:20 < _Tassadar> some stuff from cron appears every five mins, but nothing from smb
22:20 < dgrift> _Tassadar this is a common issue
22:20 < dgrift> its this:
22:21 < dgrift> youve created a new mountpoint called /data
22:21 < dgrift> selinux doesnt know that location
22:21 < dgrift> and so it labels it with a type: default_t
22:21 < dgrift> this is a type for locations unknown to selinux
22:21 < dgrift> and selinux silently denies access to type default_t
22:22 < dgrift> because it should not happen
22:22 < dgrift> all locations should be labelled properly
22:22 < _Tassadar> ah
22:22 < _Tassadar> i see
22:22 < dgrift> so how to fix it?:
22:22 < _Tassadar> with restorecon probably
22:22 < dgrift> well you should start by labelling /data
22:22 < dgrift> what type to label it, that depends on your requirements for /data
22:23 < _Tassadar> well it's all user data
22:23 < dgrift> var_t should probably do
22:23 < dgrift> i see
22:23 < _Tassadar> no binaries, no devices
22:23 < _Tassadar> lots of mp3's :)
22:23 < dgrift> whats in /data?
22:23 < dgrift> only dirs?
22:23 < _Tassadar> yes
22:23 < _Tassadar> /data/home/user1 /data/home/user2
22:24 < _Tassadar> /data/home/public_area
22:24 < _Tassadar> /data/public_area i mean
22:24 < dgrift> whats your distro?
22:24 < _Tassadar> Fedora 14
22:24 < dgrift> ok heres my suggestion
22:24 < dgrift> what is /data/home/user1 labelled?
22:24 < _Tassadar> nothing yet
22:25 < dgrift> but thats a user home dir?
22:25 < _Tassadar> drwx------. joe users unconfined_u:object_r:samba_share_t:s0 joe
22:25 < _Tassadar> well
22:25 < _Tassadar> i labelled it samba_share_t
22:25 < dgrift> ok
22:25 < _Tassadar> that's what the docs told me to do :)
22:26 < dgrift> what do you want?
22:26 < _Tassadar> well it doesn't work yet
22:26 < dgrift> what do you want with those dirs?
22:26 < _Tassadar> i would like the user to be able to mount his directory from a windows workstation
22:26 < dgrift> what is your requirement
22:26 < dgrift> i see
22:26 < _Tassadar> users are allowed read/write access to their own directories
22:26 < dgrift> and not use it locally?
22:26 < _Tassadar> and also in the public_area
22:26 < _Tassadar> no
22:26 < dgrift> ok
22:26 < _Tassadar> no shell access
22:27 < _Tassadar> no local processes are to be started from /data
22:27 < dgrift> so label /data root_t and the other dirs in there samba_share_t
22:27 < _Tassadar> recursively?
22:27 < dgrift> semanage -a -t root_t -f -d /data
22:28 < dgrift> semanage -a -t samba_share_t "/data/home(/.*)?"
22:28 < dgrift> restorecon -R -v /data
22:28 < dgrift> that will label the data dir root_t
22:28 < _Tassadar> nice
22:28 < _Tassadar> what does root_t mean?
22:28 < dgrift> and /data/home and all below it samba_share_t
22:29 < dgrift> it means it the type for filesystem roots
22:29 < dgrift> basically its accessable by all
22:29 < _Tassadar> oh okay, that makes sense in this case
22:29 < dgrift> see if it work
22:29 < _Tassadar> what would the -a option do?
22:29 < _Tassadar> my system doesn't know -a
22:29 < _Tassadar> oh
22:29 < _Tassadar> it does
22:29 < dgrift> oops
22:30 < _Tassadar> something else is wrong
22:30 < dgrift> non i made a booboo
22:30 < _Tassadar> okay
22:30 < dgrift> semanage fcontext -a -t root_t -f -d /data
22:30 < dgrift> semanage fcontext -a -t samba_share_t "/data/home(/.*)?"
22:30 < dgrift> restorecon -R -v /data
22:31 < _Tassadar> lol okay that could take a while
22:31 < _Tassadar> i'll run it without -v
22:31 < dgrift> hopefully it works for you
22:31 < dgrift> yes ok
22:31 < _Tassadar> it's a 11TB mount ;)
22:31 < dgrift> ouch....
22:31 < dgrift> all data on it?
22:31 < _Tassadar> yeah, no worries though, i'm not in a hurry
22:32 < _Tassadar> it's 60% used ;)
22:32 < dgrift> geez
22:32 < dgrift> i hope we get this right first time...
22:32 < dgrift> might want to test first
22:32 < dgrift> with a small dir
22:32 < _Tassadar> heh
22:32 < _Tassadar> i suppose so
22:32 < _Tassadar> ....
22:33 < dgrift> chcon -R -t samba_share_t /data/home/smalluserdir
22:33 < dgrift> chcon -t root_t /data
22:34 < _Tassadar> okay i'll try that
22:34 < dgrift> errr
22:34 < dgrift> its like this:
22:34 < dgrift> chcon -t root_t /data
22:34 < dgrift> chcon -t /data/home
22:34 < dgrift> err
22:34 < _Tassadar> ?
22:34 < _Tassadar> lol
22:34 < dgrift> chcon -t samba_share_t /data/home
22:34 < dgrift> chcon -R -t samba_share_t /data/home/smalluserdir
22:35 < dgrift> so three lines
22:35 < _Tassadar> yeah i understand, but restorecon is already running so /data and /data/home are already done
;)
22:35 < dgrift> because theres 3 dirs
22:35 < _Tassadar> i just tried with a small userdir and it works great !
22:35 < dgrift> ok
22:35 < _Tassadar> but, how do i keep everything neat
22:35 < _Tassadar> does restorecond do that?
22:35 < _Tassadar> i mean every time someone adds a file
22:36 < _Tassadar> it should get the right label immediately
22:36 < dgrift> it inherites the type of the parent dir
22:36 < dgrift> so should be fine
22:36 < _Tassadar> ah i see
22:36 < _Tassadar> so what does restorecond do then?
22:36 < dgrift> try it
22:36 < dgrift> well it watches directories for mislabelled files
22:36 < dgrift> but in your case its not applicable
22:37 < dgrift> because theres only one type
22:37 < _Tassadar> -rw-rw----. joe users unconfined_u:object_r:samba_share_t:s0 zzzzz.txt
22:37 < _Tassadar> yeah that works
22:37 < dgrift> samba_share_t
22:37 < _Tassadar> ah mislabelled, so not unlabelled
22:37 < _Tassadar> i understand
22:37 < _Tassadar> real 5m32.340s
22:37 < dgrift> well and unlabelled aswell
22:37 < _Tassadar> done :)
22:37 < dgrift> fast system
22:37 < _Tassadar> yeah :)
22:38 < dgrift> i should blog about this issue
22:38 < dgrift> its very common
22:38 < _Tassadar> definately
22:39 < dgrift> and people wonder why its not logging denials
22:39 < _Tassadar> yeah and the fact that audit.log doesn't show anything makes it hard to track for newbies like
me
22:39 < _Tassadar> exactly :)
22:39 < dgrift> can i use this chat log?
22:39 < dgrift> to publish?
22:39 < _Tassadar> errrr :)
22:39 < _Tassadar> i suppose

maandag 24 januari 2011

Yet another step by step introduction to policy development.

Due to several requests for guides to writing SELinux policy i have decided to create another screen cast detailing how to create a policy for a user application, and some of the things that may help one get familiar with policy writing.

As per usual by now, it is just a amateur production for amateurs. These recordings are pretty boring and long. I do advise that you view the whole thing in the proper order. Because things may not be explained well all the time, but most of it should become more clear in the course of the series.

Sometimes i make mistakes that i later notice. By the end of the series everything is pretty much sorted out (except atleast one pretty minor issue that i consider as an exercise to the watcher to troubleshoot and solve).

Also note that i encountered a conflict with restorecond -u (run in a gnome-session) with regard to labelling a file in the user home directory. I worked around that issue, but it will work fine when one logs out and back in, when it occurs.

part 1. Setting up an optimal environment for policy writing and in the mean time i explain my view on policy writing and every aspect of it.

http://www.youtube.com/watch?v=s4EyoW_7riQ

part 2. Do it yourself: create a simple script and write raw policy for it. Introduction to type transition, allow, dontaudit and other type statements. A start at translating raw policy that SELinux understands into policy that is maintainable and readable by humans and that is scalable in a modular environment.

http://www.youtube.com/watch?v=G5gUt1-ttGg

part 3. Proceed with translation of raw policy to m4 macro language powered policy. Merge our loadable policy module into upstream tresys reference policy.

http://www.youtube.com/watch?v=nbFnchVAgYs

part 4. troubleshoot remaining issues and fix them.

http://www.youtube.com/watch?v=rUGBgzTr92A

If you have specific question with regard to the series above feel free to ask for clarification.

donderdag 16 december 2010

Note to self: all the stuff a pulseaudio client needs.

basically i figured out about three scenarios so far:

1: The basics.
Pulseaudio is running normally, and the pulseaudio client needs to make some sound i guess

# manage a pulse-shm file in /dev/shm
manage_files_pattern($1, $2_tmpfs_t, $2_tmpfs_t)
fs_tmpfs_filetrans($1_t, $2_tmpfs_t, file)
fs_getattr_tmpfs($1_t)

# allow the user of the app to manage and relabel that file as well
allow $3 $2_tmpfs_t:file { relabel_file_perms manage_file_perms };

# 1. This add an attribute to the pulse client process so that i can allow each pulse client progress to signull any other pulse client process
# 2, This also adds an attribute to the pulse client tmpfs file so that i can allow each pulse client to read write and delete any others pulse client tmpfs file.
gnome_pulseaudio_client($1, $2)
# read write pulseaudio files in ~/pulse (a directory that is actually owned by gnome settings daemon)
gnome_rw_gsettingsd_pulseaudio_files($1)
# read gnome settings daemon home content for example some symlink in ~/.pulse to a pulseaudio sock file
gnome_read_gsettingsd_home_content($1)
# connect to pulseaudio with a unix stream socket
gnome_stream_connect_gsettingsd_pulseaudio($1, $2)
# search /tmp/pulse-*
gnome_search_gsettingsd_tmp_dirs($1)
# set attributes of ~/.pulse directory
gnome_setattr_gsettingsd_home_dirs($1)

# manage /.cache sound-event-cache files.
xdg_manage_generic_user_cache_files($1)

2: The not so basics.
These pulse client seem to be required to be able to (re) start the main pulseaudio process as well in some particular cases)

# domain transition to the gnome settingsd daemon pulseaudio domain when pulseaudio is executed.
gnome_spec_domtrans_gsettingsd_pulseaudio($1, $2)


3: When pulseaudio is not running.
When you kill pulseaudio and run a pulseaudio client app. It, i guess, expects some pulse audio network functionality because pulse is not running on the local system.

# the pulse client is trying to find pulseaudio on the network i guess...
allow $1 self:netlink_route_socket r_netlink_socket_perms;
allow $1 self:tcp_socket create_socket_perms;
allow $1 self:unix_dgram_socket sendto;

corenet_all_recvfrom_netlabel($1_t)
corenet_all_recvfrom_unlabeled($1_t)
corenet_tcp_bind_generic_node($1_t)
corenet_tcp_sendrecv_generic_if($1_t)
corenet_tcp_sendrecv_generic_node($1_t)
corenet_tcp_connect_pulseaudio_port($1_t)
corenet_tcp_sendrecv_pulseaudio_port($1_t)
corenet_sendrecv_pulseaudio_client_packets($1_t)

# if that isnt enough, the pulseaudio client wants to be a dbus system bus client. Dont ask me why but
its probably looking for pulseaudio run as a dbus system domain or init daemon.
dbus_system_bus_client($1)

..Heck it may even need more like maybe sysnet_read_config, i have not been able to confirm this yet.

The amount of access(policy) a simple gui application needs to be able to spit out a sound with pulseaudio is simply amazing.

maandag 29 november 2010

My Fedora 14 policy for the adventurous.

My Fedora 14 policy for the adventurous.

I have been working on a policy for Fedora 14. Three different policies actually. One for a minimal fedora installation (--nobase), one for a minimal fedora installation with libvirt and a policy for a minimal gnome desktop system.

The minimal policy for Fedora 14 gnome desktops is the interesting one. It aims to confine the gnome desktop on workstations. That means it supports almost none system services, excepts the base essentials. It does not have policy for any mail servers, it does have policy for ssh and even httpd. Http policy because gnome-user-share relies on it (dav)

What it lacks in system services it makes up for in application domains. That is to say it supports some gnome apps, and the user apps that do not have policy should be able to make to work by toggling the gnome_$1_targeted boolean where $1 is your user role prefix. Caution though that this hasnt been tested yet because my sole priority lies with a confined gnome, and this is enough work as is.

There are atleast some things to do if one decides to give it a spin.

One should add the following directories to /etc/skel:
.config
.config/enchant
.config/gtk-2.0
.cache
.local
.local/share
.gnome2
.gnome2/accels

One should also modify /usr/share/dracut/modules.d/98selinux/selinux-loadpolicy.sh

comment out:

mount --bind /dev "$NEWROOT/dev"
chroot "$NEWROOT" /sbin/restorecon -R /dev

..and then use dracut to build a new initramfs for your current kernel.

Also fix /root:

semanage fcontext -a -e /home/joe /root
restorecon -R -v /root

Typically you would:

setenforce 0
rpm -ev selinux-policy selinux-policy-targeted
rpm -Uvh selinux-policy-2.20100524-1.fc14.noarch.rpm selinux-policy-bare_gui-2.20100524-1.fc14.noarch.rpm
edit /etc/selinux/config and set selinux back to enforcing and point to bare_gui instead of targeted
relabel the file system
best to add a new user (make it staff_u as its user_u by default (sorry no unconfined_u in this policy by default)
make sure to add the user to sudo:
echo "joe ALL=(ALL) ROLE=sysadm_r TYPE=sysadm_t ALL" > /etc/sudoers.d/joe
chmod 0440 /etc/sudoers.d/joe
reboot

This policy confines all domains. also kernel_t and rpm_t. installation of packages and updting of packages should probably be done in permissive mode for now because the rpm domain needs some more loving. (common packages will work but dont try to install a kernel in enforcing mode or some service that gets restarted in the post-install script.

As said, this only works with gnome if it works at all (dont worry i am using it on my desktops) but only try this if youre a bit familar with selinux, are feeling adventurous and if you dont panic quickly.

By default the minimal gnome environment is confined. Gnome apps by default arent allowed to interact with users and often arent allowed to run generic applications. For example the printer applet currently is not confined (i dont like printing its a waste of paper and ink), thus gnome will not be able to run the printer applet until a policy for it is implemented.

The idea is that gnome can easily be allowed to interact with these generic apps and be allowed to communicate with users by toggling the gnome_$1_targeted boolean. However this is still untested.

Youll notice that youll have to unlock youre gnome keyring on each login. I am not sure why but gnome keyring daemon or whatever runs it (probably dbus, maybe xdm?) tries to manipulate selinux into running in the user domain which i forcefully prevent so that it can be made to run confined.

If something is confined then youll be able to run it in a confined environment with gnome_$1_targeted boolean set to off, Else you wont be able to run it untill some policy for it gets implemented.

The apps you are able to run may not be confined perfectly yet for all use cases (its a lot of work).

Stuff that works for me:

a lot of default gnome apps/applets/session services

totem
rhythmbox
evince
compiz
gedit
terminator
screen
mutt
irssi
firefox
thunderbird
eclipse
vinagre
empathy/telepathy
gpg
metacity
nautilus
gnome schedule
seahorse

Stuff that is not supported (atleast):

hal
mlocate

So one should be able to do some of the basics.

Why confining the desktop? Not so much to protect generic user content. I use to think this is important but as my policy evolved i discovered that the important thing here is the integrity of gnome and user apps.

For example: protect access to your keyring, gpg data, ssh data, firefox data etc.

Not protecting access to your generic ~/.porn directory

So how would you get started?

We you can get a tar ball of a recent snapshot here:

http://217.19.30.59/~dgrift/stuff/

Just put the tarball in your ~/rpmbuild/SOURCES directory. Extract the support/selinux-policy.spec from the tarball and put that into ~/rpmbuild/SPECS/
then just rpmbuild -ba ~/rpmbuild/SPECS/selinux-policy.spec
it will spit out 3 packages by default (bare_gui and its docs package) which you can install. You do not require the docs rpm but installing it doesnt hurt either.

If you want to try the bare or bare_virt model you can do so by editing the selinux-policy.spec and set the %define for that model to 1. it will build an rpm for that aswell.

Remember, expect plenty boogs i would love to receive some feedback or even help in improving the policy. It is a lot of work but the concept is very powerful. By confining the layer between the user and the system (the desktop) we achieve a lot more flexibility. We can then define what each user domain can and cannot do by simply implementing a boolean.

The idea about the bare and bare_virt models is that its strict, the unconfined module is install but not used. Another important property of bare and bare_virt is small footprint. It only installs the bare minimum modules which keeps the policy small. if one decides to run a service that is not currently supported in bare or bare_virt then one can use loadable module to implement it. The policy is focussed on advanced administrators that value small foot print and want total control over have gets installed and what not.

Questions comments? domg472 at gmail dot com

Some background information:

the policy is based off of recent refpolicy. refpolicy aims the be a base for basically any kind of model. Unfortunately i had to edit refpolicy atleast to remove unconfined_domains ( i think refpolicy probably shouldnt have unconfined domains as its easier to add and unconfined domain than to remove one) also i had to remove and/or redo most of refpolicies user application policies. I think it may be better for refpolicy to ignore user application policies or atleast prefix them all. domains like ssh_t arent helpful in a confined user space, as a confined user space relies heavily on user role prefixes.

Why not base it on fedora policy?

All of the above discussed issues apply, plus. Fedora tends to avoid issues by adding modules to base. This causes problems. My policy only has modules in the kernel layer in base all other modules can be disabled in theory. Fedora focusses on usability. little things like easily allowing access to all user content makes it hard to confine the user space.

zaterdag 7 augustus 2010

user home directory contexts

Some where in this commit: 0bf4290c235b514c39ed9c8d3f3f2fbb95f60cfa ( in one of the file context specifications there ) is something that makes and breaks whatever creates the per user home directory contexts.

Without it, semodule (what use to be genhomedircon?) only creates contexts for the "__default__" login.

It took me almost a day to narrow it down to this. I would like to know which file context specification exactly is causing it and why

donderdag 5 augustus 2010

The advantages and disadvantages of domain prefixes.

I am trying to merge restricted xwindows users and common users. The idea is to make them both use the same policy and be able to lock down what we know as user_t to a restricted user that we know as xguest by toggling booleans. That will make it easier to adept user environments to meet your requirement. You do not have to write custom policy. Simply enable/disable the functionality that you need with booleans and go.

To achieve this i use the good old per_role_templates. We used to use them for role based separation, But once user based separation was introduced there seemed to be not much use to these templates any more. However the domain prefixes used in the per role templates can play an important role in enabling and disabling functionality for different users using the same policy. We can use the domain prefix to define tunable policy.

user joe is allowed to access the network via his web browser. User jane can only access the network with her favourite game. Both use the same policy but have different booleans toggled.

But consider this: joe is allowed to use the browser. The browser can use stuff like java, flash, a video player, email client etc. Its not joe directly run those its the browser running it for joe. So how is it achieved that when it is allowed that joe can use the web browser, that joe can also watch a video clip via his web browser. Or that joe is not allowed to watch video via his browser but some other user is permitted that.

This, i believe can be achieved by called per_role_templates in per_role_templates.

I tried this before in more than one ways and always stumbled on duplicate declarations or out of scope issues. Today i tried a different approach. To avoid duplicate declarations i decided to try and split the per_role_templates into templates for policy and for declarations. The declaration per role templates should only be called by user domains. Whilst the policy per role templates can additionally be called by other policy per role templates. This way booleans, types and attributes are declared once but can be used more than once. For example user X can connect to a streaming port if he runs totem, but he can also connect to a streaming port if he runs totem via his browser. The same can be done for things like java, gpg, flash, web browsers, you name it

Another thing i have to deal with is xserver duplicated declarations, and so i also split those declarations for the policy and added the declaration interface to the per role declaration template for the various applications and the policy to the per role policy template.

This stuff becomes important if you truly want to confine the user space. Take for example nautilus. If you click on a video file in nautilus. How does the SELinux know who did it and thus who's policy to apply? All it knows is that nautilus ran the video file and nautilus is not a user its an application. There are may more such examples. Domain prefixes can help here.

There are also issues with calling per role templates from per role templates. Consider this. You can click on a web url in an E-mail message and you can also use the E-mail client from the web browser. So you called the E-mail per role template from the browser per role template, and you call the browser per role template from the E-mail per role template. This will get you into a loop that never ends. You can wait until you way less than a ounce and policy will still not finish compiling. So that is a issue to consider.

Just to show you what a per role declaration template for a GUI app would look like:


########################################
##
## Role access for mozilla declarations.
##

##
##
## Prefix to be used
##

##
##
##
## Role allowed access
##

##
#
interface(`mozilla_declarations_role',`
gen_require(`
attribute mozilla_domain;
type mozilla_exec_t;
')

##
##


## Allow Mozilla to execute anonymous memory (execmem))
## files.
##


##

gen_tunable(mozilla_$1_execmem, false)

##
##


## Allow Mozilla to read all user home.
## files.
##


##

gen_tunable(mozilla_$1_read_content, false)

##
##


## Network access for mozilla.
## files.
##


##

gen_tunable(mozilla_$1_network_connect, false)

type $1_mozilla_t, mozilla_domain;
application_domain($1_mozilla_t, mozilla_exec_t)
ubac_constrained($1_mozilla_t)

role $2 types $1_mozilla_t;

xserver_object_types_template($1_mozilla)
')


I am aware that this is a pretty dirty hack, and i am not even sure if this indeed works out the way it appears, but i am just glad and hopeful that it does.