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.