Since the earliest days there has been a command named audit2allow that takes audit messages of operations that SE Linux denied and produces policy that will permit those operations. A lesser known option for this program is the “-R” option to use the interfaces from the Reference Policy (the newer version of the policy that was introduced a few years ago). I have updated my SE Linux repository for Lenny [1] with new packages of policy and python-sepolgen that fix some bugs that stopped this from being usable.
To use the -R option you have to install the selinux-policy-dev package and then run the command sepolgen-ifgen to generate the list of interfaces (for Squeeze I will probably make the postinst script of selinux-policy-dev do this). Doing this on Lenny requires selinux-policy-default version 0.0.20080702-20 or better and doing this on Debian/Unstable now requires selinux-policy-default version 0.2.20100524-2 (which is now in Testing) or better.
Would it be useful if I maintained my own repository of SE Linux packages from Debian/Unstable that can be used with Debian/Testing? You can use preferences to get a few packages from Unstable with the majority from Testing, but that’s inconvenient and anyone who wants to test the latest SE Linux stuff would need to include all SE Linux related packages to avoid missing an important update. If I was to use my own repository I would only include packages that provide a significant difference and let the trivial changes migrate through Testing in the normal way.
The new Lenny policy includes a back-port of the new Milter policy from Unstable, this makes it a lot easier to write policy for milters. Here is an example of the basic policy for two milters, it allows the milters (with domains foo_milter_t and bar_milter_t) to start, to receive connections from mail servers, and to create PID files and Unix domain sockets.
policy_module(localmilter,1.0.0)
milter_template(foo)
files_pid_filetrans(foo_milter_t, foo_milter_data_t, { sock_file file })
milter_template(bar)
files_pid_filetrans(bar_milter_t, bar_milter_data_t, { sock_file file })
allow bar_milter_t self:process signull;
type bar_milter_tmp_t;
files_tmp_file(bar_milter_tmp_t)
files_tmp_filetrans(bar_milter_t, bar_milter_tmp_t, file)
manage_files_pattern(bar_milter_t, tmp_t, bar_milter_tmp_t)
After generating that policy I ran a test system in permissive mode and sent a test message. I ran audit2allow on the resulting AVC messages from /var/log/audit/audit.log and got the following output:
#============= bar_milter_t ==============
allow bar_milter_t bin_t:dir search;
allow bar_milter_t bin_t:file getattr;
allow bar_milter_t home_root_t:dir search;
allow bar_milter_t ld_so_cache_t:file { read getattr };
allow bar_milter_t lib_t:file execute;
allow bar_milter_t mysqld_port_t:tcp_socket name_connect;
allow bar_milter_t net_conf_t:file { read getattr ioctl };
allow bar_milter_t self:process signal;
allow bar_milter_t self:tcp_socket { read write create connect setopt };
allow bar_milter_t unlabeled_t:association { recvfrom sendto };
allow bar_milter_t unlabeled_t:packet { recv send };
allow bar_milter_t urandom_device_t:chr_file read;
allow bar_milter_t usr_t:file { read getattr ioctl };
allow bar_milter_t usr_t:lnk_file read;
#============= foo_milter_t ==============
allow foo_milter_t ld_so_cache_t:file { read getattr };
allow foo_milter_t lib_t:file execute;
allow foo_milter_t mysqld_port_t:tcp_socket name_connect;
allow foo_milter_t net_conf_t:file { read getattr };
allow foo_milter_t self:capability { setuid setgid };
allow foo_milter_t self:tcp_socket { write setopt shutdown read create connect };
allow foo_milter_t unlabeled_t:association { recvfrom sendto };
allow foo_milter_t unlabeled_t:packet { recv send };
Running the audit2allow command with the “-R” option gives the following output, it includes the require section that is needed for generating policy modules:
require {
type sshd_t;
type ld_so_cache_t;
type bar_milter_t;
type foo_milter_t;
class process signal;
class tcp_socket { setopt read create write connect shutdown };
class capability { setuid setgid };
class fd use;
class file { read getattr };
}
#============= bar_milter_t ==============
allow bar_milter_t ld_so_cache_t:file { read getattr };
allow bar_milter_t self:process signal;
allow bar_milter_t self:tcp_socket { read write create connect setopt };
corecmd_getattr_sbin_files(bar_milter_t)
corecmd_search_sbin(bar_milter_t)
corenet_sendrecv_unlabeled_packets(bar_milter_t)
corenet_tcp_connect_mysqld_port(bar_milter_t)
dev_read_urand(bar_milter_t)
files_read_usr_files(bar_milter_t)
files_read_usr_symlinks(bar_milter_t)
files_search_home(bar_milter_t)
kernel_sendrecv_unlabeled_association(bar_milter_t)
libs_exec_lib_files(bar_milter_t)
sysnet_read_config(bar_milter_t)
#============= foo_milter_t ==============
allow foo_milter_t ld_so_cache_t:file { read getattr };
allow foo_milter_t self:capability { setuid setgid };
allow foo_milter_t self:tcp_socket { write setopt shutdown read create connect };
corenet_sendrecv_unlabeled_packets(foo_milter_t)
corenet_tcp_connect_mysqld_port(foo_milter_t)
kernel_sendrecv_unlabeled_association(foo_milter_t)
libs_exec_lib_files(foo_milter_t)
sysnet_read_config(foo_milter_t)
To get this working I removed the require lines for foo_milter_t and bar_milter_t as it’s not permitted to both define a type and require it in the same module. Then I replaced the set of tcp_socket operations { write setopt shutdown read create connect } with create_socket_perms as it’s easiest to allow all the operations in that set and doesn’t give any security risks.
Finally I replaced the mysql lines such as corenet_tcp_connect_mysqld_port(foo_milter_t) with sections such as the following:
mysql_tcp_connect(foo_milter_t)
optional_policy(`
mysql_stream_connect(foo_milter_t)
‘)
This gives it all the access it needs and additionally the optional policy will allow Unix domain socket connections for the case where the mysqld is running on localhost.