woensdag 21 oktober 2009

Git daemon, SELinux and Fedora 12 Beta.

Recently i decided to redo my Git daemon domain and reinstall a Git daemon server.

This article will explain the issues i had to consider.

SELinux can be used to confined the Git daemon and Git Shell. I have not used SELinux in a optimal way here but i decided to implement a mix of MAC, DAC and Git ACL.

As for SELinux i have installed the following module:

gitd.te:

[code]

policy_module(gitd, 1.0.0)

########################################
#
# Git daemon global private declarations.
#

attribute gitd_type;
attribute gitd_content_type;

type gitd_exec_t;

# FIXME
type gitd_port_t;
corenet_port(gitd_port_t)

########################################
#
# Git daemon system private declarations.
#

##
##


## Allow Git-shell to modify and execute public files
## used for public file transfer services. Directories/Files must
## be labeled public_content_rw_t.
##


##
# gen_tunable(gitd_allow_anon_write, false)

##
##


## Allow Git daemon system to search home directories.
##


##
gen_tunable(gitd_system_enable_homedirs, false)

##
##


## Allow Git daemon system to access cifs file systems.
##


##
gen_tunable(gitd_system_use_cifs, false)

##
##


## Allow Git daemon system to access nfs file systems.
##


##
gen_tunable(gitd_system_use_nfs, false)

type gitd_system_t, gitd_type;
inetd_service_domain(gitd_system_t, gitd_exec_t)
role system_r types gitd_system_t;

type gitd_shared_t, gitd_content_type;
files_type(gitd_shared_t)

# permissive gitd_system_t;

########################################
#
# Git shell private declarations.
#

gen_require(`
attribute unpriv_userdomain, userdomain;
class context contains;
')

attribute gits_file_type;
attribute gits_usertype;

type gits_t, userdomain, gits_usertype, unpriv_userdomain;
domain_type(gits_t)

role gits_r types gits_t;
allow system_r gits_r;

corecmd_shell_entry_type(gits_t)
corecmd_bin_entry_type(gits_t)

domain_interactive_fd(gits_t)
domain_user_exemption_target(gits_t)

# permissive gits_t;

########################################
#
# Git daemon session session private declarations.
#

##
##


## Allow Git daemon session to bind
## tcp sockets to all unreserved ports.
##


##
gen_tunable(gitd_session_bind_all_unreserved_ports, false)

type gitd_session_t, gitd_type;
application_domain(gitd_session_t, gitd_exec_t)
ubac_constrained(gitd_session_t)

type gitd_personal_t, gitd_content_type;
userdom_user_home_content(gitd_personal_t)

# permissive gitd_session_t;

########################################
#
# Git daemon global private policy.
#

allow gitd_type self:fifo_file rw_fifo_file_perms;
allow gitd_type self:netlink_route_socket { create_socket_perms nlmsg_read };
allow gitd_type self:tcp_socket create_socket_perms;
allow gitd_type self:udp_socket create_socket_perms;
allow gitd_type self:unix_dgram_socket create_socket_perms;

# FIXME
allow gitd_type gitd_port_t:tcp_socket name_bind;

corenet_all_recvfrom_netlabel(gitd_type)
corenet_all_recvfrom_unlabeled(gitd_type)

corenet_tcp_sendrecv_all_if(gitd_type)
corenet_tcp_sendrecv_all_nodes(gitd_type)
corenet_tcp_sendrecv_all_ports(gitd_type)

corenet_tcp_bind_all_nodes(gitd_type)

corecmd_exec_bin(gitd_type)

files_read_etc_files(gitd_type)
files_read_usr_files(gitd_type)

fs_search_auto_mountpoints(gitd_type)

kernel_read_system_state(gitd_type)

logging_send_syslog_msg(gitd_type)

miscfiles_read_localization(gitd_type)

sysnet_read_config(gitd_type)

optional_policy(`
nis_use_ypbind(gitd_type)
')

optional_policy(`
nscd_read_pid(gitd_type)
')

########################################
#
# Git daemon system repository private policy.
#

list_dirs_pattern(gitd_system_t, gitd_content_type, gitd_content_type)
read_files_pattern(gitd_system_t, gitd_content_type, gitd_content_type)
files_search_var(gitd_system_t)

# This will not work since git-shell needs to execute gitd content thus public content files.
# There is currently no clean way to execute public content files.
# miscfiles_read_public_files(gitd_system_t)

tunable_policy(`gitd_system_enable_homedirs', `
userdom_search_user_home_dirs(gitd_system_t)
')

tunable_policy(`gitd_system_enable_homedirs && use_nfs_home_dirs', `
fs_list_nfs(gitd_system_t)
fs_read_nfs_files(gitd_system_t)
')

tunable_policy(`gitd_system_enable_homedirs && use_samba_home_dirs', `
fs_list_cifs(gitd_system_t)
fs_read_cifs_files(gitd_system_t)
')

tunable_policy(`gitd_system_use_cifs', `
fs_list_cifs(gitd_system_t)
fs_read_cifs_files(gitd_system_t)
')

tunable_policy(`gitd_system_use_nfs', `
fs_list_nfs(gitd_system_t)
fs_read_nfs_files(gitd_system_t)
')

########################################
#
# Git shell private policy.
#

allow gits_t self:context contains;
allow gits_t self:fifo_file rw_fifo_file_perms;

corecmd_exec_bin(gits_t)

kernel_read_system_state(gits_t)

files_read_etc_files(gits_t)

files_search_home(gits_t)

gitd_execute_shared_files(gits_t)
gitd_manage_shared_content(gits_t)

miscfiles_read_localization(gits_t)
# miscfiles_read_public_files(gits_t)

ssh_rw_stream_sockets(gits_t)

# FIXME
# This will not work since git-shell needs to execute gitd content thus public content files.
# There is currently no clean way to execute public content files.
# tunable_policy(`gitd_allow_anon_write', `
# miscfiles_exec_public_files(gits_t)
# miscfiles_manage_public_files(gits_t)
# ')

tunable_policy(`gitd_system_enable_homedirs && use_nfs_home_dirs', `
fs_exec_nfs_files(gits_t)
fs_manage_nfs_dirs(gits_t)
fs_manage_nfs_files(gits_t)
')

tunable_policy(`gitd_system_enable_homedirs && use_samba_home_dirs', `
fs_exec_cifs_files(gits_t)
fs_manage_cifs_dirs(gits_t)
fs_manage_cifs_files(gits_t)
')

tunable_policy(`gitd_system_use_cifs', `
fs_exec_cifs_files(gits_t)
fs_manage_cifs_dirs(gits_t)
fs_manage_cifs_files(gits_t)
')

tunable_policy(`gitd_system_use_nfs', `
fs_exec_nfs_files(gits_t)
fs_manage_nfs_dirs(gits_t)
fs_manage_nfs_files(gits_t)
')

optional_policy(`
nscd_read_pid(gits_t)
')

########################################
#
# Git daemon session repository private policy.
#

list_dirs_pattern(gitd_session_t, gitd_personal_t, gitd_personal_t)
read_files_pattern(gitd_session_t, gitd_personal_t, gitd_personal_t)
userdom_search_user_home_dirs(gitd_session_t)

userdom_use_user_terminals(gitd_session_t)

tunable_policy(`gitd_session_bind_all_unreserved_ports', `
corenet_tcp_bind_all_unreserved_ports(gitd_session_t)
')

tunable_policy(`use_nfs_home_dirs', `
fs_list_nfs(gitd_session_t)
fs_read_nfs_files(gitd_session_t)
')

tunable_policy(`use_samba_home_dirs', `
fs_list_cifs(gitd_session_t)
fs_read_cifs_files(gitd_session_t)
')
[/code]

gitd.if
[code]
## Git daemon is a really simple server for Git repositories.
##
##


## A really simple TCP git daemon that normally listens on
## port DEFAULT_GIT_PORT aka 9418. It waits for a
## connection asking for a service, and will serve that
## service if it is enabled.
##


##


## It verifies that the directory has the magic file
## git-daemon-export-ok, and it will refuse to export any
## git directory that has not explicitly been marked for
## export this way (unless the --export-all parameter is
## specified). If you pass some directory paths as
## git-daemon arguments, you can further restrict the
## offers to a whitelist comprising of those.
##


##


## By default, only upload-pack service is enabled, which
## serves git-fetch-pack and git-ls-remote clients, which
## are invoked from git-fetch, git-pull, and git-clone.
##


##


## This is ideally suited for read-only updates, i.e.,
## pulling from git repositories.
##


##


## An upload-archive also exists to serve git-archive.
##


##

#######################################
##
## Role access for Git daemon session.
##

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

##
##
##
## User domain for the role.
##

##
#
interface(`gitd_session_role', `
gen_require(`
type gitd_session_t, gitd_exec_t, gitd_personal_t;
')

########################################
#
# Git daemon session shared declarations.
#

##
##


## Allow transitions to the Git daemon
## session domain.
##


##
gen_tunable(gitd_session_transition, false)

role $1 types gitd_session_t;

########################################
#
# Git daemon session shared policy.
#

tunable_policy(`gitd_session_transition', `
domtrans_pattern($2, gitd_exec_t, gitd_session_t)
', `
can_exec($2, gitd_exec_t)
')

allow $2 gitd_session_t:process { ptrace signal_perms };
ps_process_pattern($2, gitd_session_t)

exec_files_pattern($2, gitd_personal_t, gitd_personal_t)
manage_dirs_pattern($2, gitd_personal_t, gitd_personal_t)
manage_files_pattern($2, gitd_personal_t, gitd_personal_t)

relabel_dirs_pattern($2, gitd_personal_t, gitd_personal_t)
relabel_files_pattern($2, gitd_personal_t, gitd_personal_t)
')

########################################
##
## Allow the specified domain to execute
## Git daemon shared files.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_execute_shared_files', `
gen_require(`
type gitd_shared_t;
')

exec_files_pattern($1, gitd_shared_t, gitd_shared_t)
files_search_var($1)
')

########################################
##
## Allow the specified domain to manage
## Git daemon shared content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_manage_shared_content', `
gen_require(`
type gitd_shared_t;
')

manage_dirs_pattern($1, gitd_shared_t, gitd_shared_t)
manage_files_pattern($1, gitd_shared_t, gitd_shared_t)
files_search_var($1)
')

########################################
##
## Allow the specified domain to manage
## Git daemon personal content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_manage_personal_content', `
gen_require(`
type gitd_personal_t;
')

manage_dirs_pattern($1, gitd_personal_t, gitd_personal_t)
manage_files_pattern($1, gitd_personal_t, gitd_personal_t)
files_search_home($1)
')

########################################
##
## Allow the specified domain to read
## Git daemon personal content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_read_personal_content', `
gen_require(`
type gitd_personal_t;
')

list_dirs_pattern($1, gitd_personal_t, gitd_personal_t)
read_files_pattern($1, gitd_personal_t, gitd_personal_t)
files_search_home($1)
')

########################################
##
## Allow the specified domain to read
## Git daemon shared content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_read_shared_content', `
gen_require(`
type gitd_shared_t;
')

list_dirs_pattern($1, gitd_shared_t, gitd_shared_t)
read_files_pattern($1, gitd_shared_t, gitd_shared_t)
files_search_var($1)
')

########################################
##
## Allow the specified domain to relabel
## Git daemon shared content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_relabel_shared_content', `
gen_require(`
type gitd_shared_t;
')

relabel_dirs_pattern($1, gitd_shared_t, gitd_shared_t)
relabel_files_pattern($1, gitd_shared_t, gitd_shared_t)
files_search_var($1)
')

########################################
##
## Allow the specified domain to relabel
## Git daemon personal content.
##

##
##
## Domain allowed access.
##

##
##
#
interface(`gitd_relabel_personal_content', `
gen_require(`
type gitd_personal_t;
')

relabel_dirs_pattern($1, gitd_personal_t, gitd_personal_t)
relabel_files_pattern($1, gitd_personal_t, gitd_personal_t)
files_search_home($1)
')

########################################
##
## All of the rules required to administrate an
## Git daemon system environment
##

##
##
## Prefix of the domain. Example, user would be
## the prefix for the user_t domain.
##

##
##
##
## Domain allowed access.
##

##
##
##
## The role to be allowed to manage the Git daemon domain.
##

##
##
#
interface(`gitd_system_admin', `
gen_require(`
type gitd_system_t, gitd_exec_t;
')

allow $1 gitd_system_t:process { getattr ptrace signal_perms };

kernel_search_proc($1)
allow $1 git_system_t:dir list_dir_perms;
read_files_pattern($1, gitd_system_t, gitd_system_t)
read_lnk_files_pattern($1, gitd_system_t, gitd_system_t)

manage_files_pattern($1, gitd_exec_t, gitd_exec_t)

# This will not work since git-shell needs to execute gitd content thus public content files.
# There is currently no clean way to execute public content files.
# miscfiles_manage_public_files($1)

gitd_manage_shared_content($1)
gitd_relabel_shared_content($1)

seutil_domtrans_setfiles($1)
')
[/code]

gitd.fc
[code]HOME_DIR/public_git(/.*)? gen_context(system_u:object_r:gitd_personal_t, s0)
HOME_DIR/\.gitconfig -- gen_context(system_u:object_r:gitd_personal_t, s0)

/srv/git(/.*)? gen_context(system_u:object_r:gitd_shared_t, s0)

/usr/libexec/git-core/git-daemon -- gen_context(system_u:object_r:gitd_exec_t, s0)

# Conflict with Fedora cgit fc spec.
# /var/lib/git(/.*)? gen_context(system_u:object_r:gitd_shared_t, s0)
[/code]

I manually labelled tcp:9418 gitd_port_t
[code]
semanage port -a -t gitd_port_t -p tcp 9418
[/code]

I also manually added a SELinux user mapping:

semanage user -a -L s0 -r s0 -R "gits_r" -P gits_u

echo "system_r:sshd_t:s0 gits_r:gits_t:s0" > /etc/selinux/targeted/contexts/users/gits_u

I edited /etc/xinetd.d/git:
[code]
# default: off
# description: The git dæmon allows git repositories to be exported using \
# the git:// protocol.

service git
{
disable = no
socket_type = stream
type = UNLISTED
port = 9418
wait = no
user = nobody
# server = /usr/bin/git
# server_args = daemon --base-path=/srv/git --export-all
--user-path=public_git --syslog --inetd --verbose
server = /usr/libexec/git-core/git-daemon
server_args = --base-path=/srv/git --export-all
--user-path=public_git --syslog --inetd --verbose
log_on_failure += USERID
# xinetd doesn't do this by default. bug #195265
flags = IPv6
}
[/code]

Basically the selinux policy has 3 parts. one part is for the gitd system inetd server. the second part is for running gitd as a unprivileged user, and the third part is policy for the system wide git-shell environment.
So we secure the system wide gitd process, gitd process that users run and the git-shell process that is used to push pull to shared repositories.

When you compile git-daemon, configured it like above and install the selinux module, restore the contexts of the paths in gitd.fc. then start xinetd: youll notice that inetd_t is not allowed to bind to gitd_port_t.
You can simply use audit2allow with the -M option to allow inetd_t to bind to gitd_port on behalf of gitd_system_t

I use DAC to give usergroups access to the particular repositories and i use git ACL to restrict access to branches, tags etc.

I used this great web site do implement this:

http://www.kernel.org/pub/software/scm/git/docs/everyday.html

I wrote two simple scripts:

1. to add new users
2. to add new repostiries

create_repository:

crepo.sh:
[code]
#!/bin/bash

# crepo.sh

groupadd $1 || exit 1;
usermod -a -G $1 badabing || exit 1;

mkdir /srv/git/$1.git || exit 1;
chmod -R +t /srv/git/$1.git || exit 1;
cd /srv/git/$1.git && git --bare init || exit 1;

cp /home/dgrift/create_repository/update /srv/git/$1.git/hooks/ || exit 1;
cp /home/dgrift/create_repository/allowed-users /srv/git/$1.git/info/ || exit 1;

chown -R nobody:$1 /srv/git/$1.git || exit 1;

chmod -R g+s /srv/git/$1.git/branches || exit 1;
chmod -R g+s /srv/git/$1.git/hooks || exit 1;
chmod -R g+s /srv/git/$1.git/info || exit 1;
chmod -R g+s /srv/git/$1.git/objects || exit 1;
chmod -R g+s /srv/git/$1.git/refs || exit 1;
chmod -R g+w /srv/git/$1.git || exit 1;

exit 0;

#EOF
[/code]

This script installs the git ACL files update and allowed-users:

update:
[code]
http://www.kernel.org/pub/software/scm/git/docs/howto/update-hook-example.txt
[/code]

allowed-users:
[code]
refs/heads/master badabing
+refs/heads/pu badabing
refs/heads/bw/.* badabing
refs/heads/tmp/.* .*
refs/tags/v[0-9].* badabing
[/code]

I also created a script to do part of what is required to add new users (i havent tested this script yet:

[code]
#!/bin/bash

# agits.sh

useradd -Z gits_u -s /usr/bin/git-shell $1 || exit 1;
usermod -a -G sshusers,$2 $1 || exit 1;

echo "Do not forget to set a password!"
echo "Manually add entries for $1 in /etc/security/namespace.conf!"
echo "You may need to edit /srv/git/$2.git/info/allowed-users!"

# TODO: usrquota

exit 0;
[/code]

By the way xinetd and selinux dont play nice so you may need to edit the xinetd init script:

[code]
https://bugzilla.redhat.com/show_bug.cgi?id=529681
[/code]

So that is basically it.
The SELinux policy for the git system service should work by default. Additionally there are some booleans to to toggle for example to allow the git system service to also host personal repositories in ~/public_git, allow git to use any unreserved port for mass git repostory hosting. enable disable transition to git_session_t which is the user daemon.
For this to work you must also enable git policy for users by creating a module:

for example if you want unconfined users to transition to git domain if they run git daemon <...>

myunconfined.te:
[code]
policy_module(myunconfined, 0.0.1)
optional_policy(`
gen_require(`
type unconfined_t;
')

git_session_role(unconfined_r, unconfined_t)
[/code]

build and install that:

make -f /usr/share/selinux/devel/Makefile
sudo semodule -i myunconfined.pp

That should work and make unconfined_t users transition to git_session_t when they run git daemon <...>

For me this setup works, but i have not thoroughly tested the git_session_t domain yet.

Would be nice to get some feedback so that i can improve this.


The git selinux policy is malformed above use the command below to pull the current gitd policy from my git repository

git clone git://
82.197.205.60/selinux-modules.git

dinsdag 6 oktober 2009

My view on domains, domain types, roles, domain transitions and more.

A domain is an environment in which a process operates. That environment is defined by the access vectors where a particular process is the sources.

Sometimes people refer to types of processes as domains. This is technically incorrect. Types of processes are domain types.

A domain is a general term for process environments. Processes can have different natures or properties. For example a user process environment can be called a domain and a process of a program can also be called a domain.

In SELinux world we like to "label" everything. So instead of calling a user process environment a domain we call it a user domain. The type of a user process is called a user domain type although technically its a domain type since user processes are processes.

Besides user domains, there are more different domains. These domains are defined by who transitioned to them. For example, init daemons are started by init scripts. The init script process sandbox is called init script domain and process environments that init script domains transition to are called init daemon domains.

Examples of init daemon domains are the environment of the httpd_t init daemon domain type, or postgresql. The main property is that these processes are started by init scripts.

Process environments of programs that user process environments transition to are called application domains, and the type of such a process is called a application domain type.

It depends on what transitions to what, that defines what domain it is. A cgi webapp that operates in its own environment is called a apache daemon domain if the httpd_t init daemon domain transitions to the process environment of a cgi webapp.

There are many more such domains and they are defined by what domain transitioned to them.

Domain transitions occur upon entrypoints. An entrypoint is a defined path to usually a executable file. Types of executable files are called executable file types. They are important in entrypoints to domains.

For example:

apache init script has a executable file type called for example httpd_initrc_exec_t.
When the init_t domain type executes the file with executable file type httpd_initrc_exec_t,
the process of that executable file type will get the initrc_t domain type and the process will operate in the init script domain (init script process environment).

The entrypoint is:
init_t -> httpd_initrc_exec_t

This entrypoint leads to the initrc_t process environment. (init script domain)

Now this starts all over again when the process that has domain type initrc_t runs the apache executable.

Assuming in this example that /usr/sbin/httpd is apaches executable file and that it has a executable file type of httpd_exec_t.

The entrypoint is:
initrc_t -> httpd_exec_t

The init script domain type runs the apache executable file type. There is a rule that says:
when initrc_t executes httpd_exec_t, then transition to the httpd_t process environment type.

initrc_t -> httpd_exec_t -> httpd_t

initrc_t is a (init script) domain type. policy where initrc_t is the source type is called a init script domain.

httpd_exec_t is a executable file type.
initrc_t -> httpd_exec_t is the entrypoint to the httpd_t domain (type)
httpd_t -> is a (init daemon) domain type. policy where httpd_t is the source type is called a init daemon domain.

There are api available that make transitioning to these types of domains easier.

For example you can simply call the init_daemon_domain() interface if your process is started by a init script. proper calling of this single interface will take care of some of the declarations that are required. it will also set up a domain transition pattern.

type myinitdaemondomaintype_t;
type myinitdaemondomaintypeexecutablefiletype_t;
init_daemon_domain(myinitdaemondomaintype_t, myinitdaemondomaintypeexecutablefiletype_t)

This will instruct SELinux to let processes that run in the initrc_t init script domain that execute files with executable file type myinitdaemondomaintypeexecutablefiletype_t, domain transition to the myinitdaemondomaintype_t process enviroment and give that process the init daemon domain type.

initrc_t -> myinitdaemondomaintypeexecutablefiletype_t -> myinitdaemondomaintype_t

This ofcourse requires that file files in question are labelled accordingly.

application domains are handled a bit differently. This is mainly because of RBAC.

Role based access control is a mechanism that allows a single user to operate in various environments (user domains)

This means that you must also define which role is allowed to use the target domain type.

user_t: user domain type
userapp_exec_t: (application) executable file type of the application to transition to.
userapp_t: application domain type

entrypoint:
user_t -> userapp_exec_t

Target of the entry point:
userapp_tRole of the user that this domain transition pattern is defined for:
user_r

type user_t;
type userapp_exec_t;
application_domain(user_t, userapp_exec_t)
role user_r types userapp_t;

domain_transition_pattern(user_t, userapp_exec_t, userapp_t)

Again same idea but its just a bit more complicated than the init daemon domain because users
(and applications started by users) can have different roles.

Applications started by init (system) can only have one role(system_r), So that makes the init daemon domains less complicated.

Explained:
When a user process that operates in the user_t user process environment runs a file with executable file type myapp_exec_t, then the process of that executable file type will run in the myapp_t application process environment (application domain).

Since users can have different roles we also define that particular role to have access to the application domain type.

We also manually define a domain transition pattern (user_t -> myapp_exec_t -> myapp_t)

Keep in mind that domains transitioned to by users also have to deal with roles, unlike domain transitioned to by system processes. processes where the role field in the context is system_r.

Your policy source has many example of the different domains. If you want to write policy for a init daemon than look up an example of a init daemon domain in the source policy, and see if that can get you started. Idem ditto for application domains, apache daemon domains, xinet service domains, dbus service domains and etcetera.

User domains are different. They arent started by other processes. instead a real person logs into the system and by running a tty or pts a new domain is initiated. These transtions are defined both in the user domain policy and selinux mappings, many of which can be defined with the semanage command.

for example:
(real human) -> tty_device_t -> user_t

I wont go into much detail here but i want to touch on the different user domains to consider. Users can have different roles. Roles are mappings to domains. and as explained domain are environments in which processes operate, defined by the policy in which a domain type is a source.

There are two different classes of user domain to consider. user domains that need a login environment, and user domains that do not need a login enviroment. i refer to them as primary and secondary user domains.

An example of a primary login user domain is staff_t. A user can login to a system in the staff_t user domain.

An example of a secundary user domain is webadm_t.

A primary user domain can be allowed to domain transition via roles (RBAC) to this secondary user domain. Thus may not be required to login and have a home directory and etcetera. Secondary user domains are often used for environments that have super user privileges. Like for example the webadm_t environment allows a user process to manage the webserver environment.

Have a look at the different defined user domain in the source policy. look at both staff domain and webadm domain and keep in mind that the first is a primary domain and the latter a secondary domain. By mapping the webadm_r and staff_r roles to a selinux user and mapping this selinux user to a linux login you can make selinux allow users that operate in the staff_t user domain to use Role based access control to domain transition to the secondary webadm_t user domain via sudo or su in conjunction with newrole.



donderdag 17 september 2009

AVC Denials: Example

SELinux logs policy violations to /var/log/audit/audit.log if audit is installed and enabled. If audit is
not installed or enabled, than SELinux sends policy violation notices to dmesg or /var/log/messages.

The policy violations that SELinux logs are called AVC denials. AVC is an abbreviation for Access Vector
Cache. Which is the SELinux cache with Access Vectors. Access vectors are the rules that govern access.

Reading AVC denials properly helps troubleshoot issues. In this article i will talk about, and highlight
some of the information you can retrieve from AVC denials. I will also touch on some of the tools that
assist in listing, parsing and translating SELinux Access Vector Cache denials.

Example of a AVC denial:

avc: denied { getattr } for pid=7604 comm="firefox" path="/usr/lib64/firefox-3.5.3/firefox" dev=dm-2 ino=1311607
scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 tcontext=system_u:object_r:mozilla_exec_t:s0 tclass=file

The line above provides much information about what has been denied:

1. What process was denied access.
2. What domain type did the source process operate in when it was denied access.
3. What object or subject was the source process denied access to.
4. What was the object/subject type of the target.
5. What permission was denied.
6. What is the class of the target.
7. What was the process identity of the source.
8. What was the inode number of the target object.
9. What happened.

Security is about managing interaction. Interaction has a source and a target. Interaction involves atleast
a subject as a source (an interacting party) and a subject or object as a target. The target of the
interaction. Subjects are interacting entities, and object non-interacting entities. Subjects can interact
with object, but subjects can also interact with other subjects.

The target class in a AVC denial tells us what the class (origin) of the target in an interaction is.
A source of a interaction is always a subject (interacting entity). Object can not interact and thus can
never be a source of an interaction.

Lets try and connect the dots and see if we can make sense of the example AVC denial above. We will try to
answer each of our 9 questions in the check list:

1. What process was denied access.

comm="firefox" shows use the name of the command that was run. The firefox program was denied access.

2. What domain type did the source
process operate in when it was denied access.

scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 shows that the source firefox was operating with the
gwibber_t domain type. The type is the third field in the security context tuple.

3. What object or subject was the source process denied access to.

path="/usr/lib64/firefox-3.5.3/firefox" Shows what the target of the source in this interaction was.

4. What was the object/subject type of the target.

tcontext=system_u:object_r:mozilla_exec_t:s0 shows the type of the target.

5. What permission was denied.

{ getattr } Shows the syscall (permission) that was denied.

6. What is the class of the target.

tclass=file shows that the class of the target in our interaction was file.

7. What was the process identity of the source.

pid=7604 shows that the process id of the source of our interaction was 7604

8. What was the inode number of the target object.

ino=131160 shows that the inode number of the target object in our interaction was 131160.

9. What happened.

denied shows that the particular Access Vector was denied.

We have all the detail that we need to established *what* happend.

1. The command /usr/bin/firefox was executed but some interacting entity.
2. This command was executed with the gwibber_t domain type.
3. The target of the source /usr/bin/firefox was /usr/lib64/firefox-3.5.3/firefox
4. The type of the target was mozilla_exec_t
5. The source /usr/bin/firefox that operated with the gwibber_t domain type was denied the "getattr"
syscall on the target /usr/lib64/firefox-3.5.3/firefox that had type mozilla_exec_t.
6. The class of the target /usr/lib64/firefox-3.5.3/firefox is a file (the target is a file object)
7. The process of /usr/bin/firefox had the process id of 7604 when this Access vector occured.
8. The inode number of the target file object is 131160
9. Access was denied.

These are the SELinux facts:

the /usr/bin/firefox command was denied to get the attributes of the /usr/lib64/firefox-3.5.3/firefox file
source domain type gwibber_t was denied get attribute of a file object with type mozilla_exec_t

What this means is that there was no rule to allow this access, thus access was denied.

From here on out things get less obvious:

We know some facts but this has raised other questions:

1. Are the types of the source and target correct?
2. We know what was denied but we dont know why.
3. Should we allow this access?
4. Does it signal intrusion?
5. If we allow it access what would be the best way to do it.
6. What are the problems if we do it the other way?

The reason that these questions are harder to answer is because it depends on the policy that is created by
the policy author. But if you see an AVC denial we can usually narrow the cause down to:

a. The source and/or the target is mislabelled (wrong type)
b. It is a bug in policy.
c. Intrusion was detected and prevented.

So let's try to answer all these questions:

1. Are the types of the source and target correct?

This is the first thing we must verify. If the types are incorrect than we must correct them first to be able to learn the real reason
about what happend. Objects sometimes get mislabelled. For example if created the object whilst you had SELinux disabled and forgot to
restore the context. Another reason might be that you have moved the file from another location as opposed to copying it, and forgot
the restore the context.

How do we determine whether the types are correct? Well the answer is that we have to dig into some of the properties of the policy.
We have to put ourselves into the shoes of the policy author.

To verify whether the type of the source (gwibber_t) is correct we have to ask ourselves which policy module owns this type?
This is a hard question to answer. Really the only way to figure this out is to grep for the gwibber_t type in the source of the
policy. In this case there is a policy module installed called gwibber.

For example:

grep -r "type gwibber_t" Modules/

We are looking for the declaration of the gwibber_t type. Types are usually declared in files with .te suffixes (type enforcement
source policy files)

So we could narrow our grep a bit:

grep -r "type gwibber_t" Modules/ | grep "\.te"

Modules/gwibber.te:type gwibber_t;
Modules/gwibber.te:type gwibber_tmpfs_t;

The type is declared in the gwibber.te source policy type enforcement file. We can now grep this file for the policy_module
declaration to figure out what the name of the module is:

grep policy_module Modules/gwibber.te
policy_module(gwibber, 0.0.1)

The policy module name is gwibber and the version number is 0.0.1, Now we can determine whether this module is installed:

sudo /usr/sbin/semodule -l | grep gwibber
gwibber 0.0.1

The module is installed, we know that the type gwibber_t is owned by the gwibber module.

Now we should figure out what the type of the firefox command is. the firefox command is located in /usr/bin/firefox.
We can use ls -alZ /usr/sbin/firefox to determine the type of this command:

-rwxr-xr-x. root root system_u:object_r:bin_t:s0 /usr/bin/firefox

The type of the firefox command is bin_t. This type has a special property that is specific to the policy model. You could look up the
properties of this type the same way that we are currently looking up the properties of type gwibber_t.

But to not overly complicate things i will explain the main property of the bin_t type.

The bin_t type is a generic type for executable files in bin and sbin directories. These commands get run with the domain type of the
subject that executed the command. So if a process that was operating with the gwibber_t domain type executed a command with the bin_t
type, than that command would run with the gwibber_t domain type.

With this in we have to figure out whether processes with the gwibber_t domain type are allowed to execute files with the bin_t type:

sudo sesearch --allow -s gwibber_t -t bin_t -c file -p execute
Found 1 semantic av rules:
allow gwibber_t bin_t : file { ioctl read getattr lock execute execute_no_trans open } ;

The sesearch command queries the policy store and looks if there is a rule which allows the source gwibber_t domain type to execute
target objects of the files class with type bin_t.

A line is returned confirming that this is allowed. This tells us that the source in our interaction is likely correclty labelled.
This is what happened. Some process that run with the gwibber_t domain type ran /usr/bin/firefox which has the bin_t type causing the
firefox command to run with the gwibber_t domain type.

Now we need to determine whether the type of our target is correct. In our interaction that fortunatly is pretty easy.
We know the path of our target: /usr/lib64/firefox-3.5.3/firefox
We can run the matchpathcon command to see what type is defined for this location and if that defined type corresponds to the target
type in our avc denial: mozilla_exec_t.

sudo /sbin/matchpathcon /usr/lib64/firefox-3.5.3/firefox
/usr/lib64/firefox-3.5.3/firefox system_u:object_r:mozilla_exec_t:s0

This confirms that the labelling in the interaction is correct for both source and target.

Sometimes however, the full path of the target is not shown in a avc denial. In that case you can use the inode number to find the
full path:

find / -inum 131160
/usr/lib64/firefox-3.5.3/firefox

2. We know what was denied but we dont know why.

This is another hard question to solve. We are no psychics. We cannot read the mind of the policy author.
We can try:

Should gwibber be able to run firefox? It should be able to run the default browser yes but in this case (the case where i am the
policy author of the gwibber policy module) it was decided to not allow this funcionality. It is obvious that the gwibber_t domain
type was not allowed the access/see (get attributes) the mozilla executable file with type mozilla_exec_t. So either that was done on
purpose or it is a bug in the policy.

3. Should we allow this access?
3. Should we allow this access?
4. Does it signal intrusion?
5. If we allow it access what would be the best way to do it.
6. What are the problems if we do it the other way?

Another tough question. if we allow gwibber_t to get attributes of files with type mozilla_exec_t it will probably want more after
that. Chances are that gwibber wants to execute the file (run firefox), since gwibber is designed to open pages in the default
browser.

If we want gwibber to be able to open the browser, do we want to allow gwibber_t to run the browser with the gwibber_t type or should
we lets gwibber_t domain transition to the mozilla_t domain type? Well my personal opinion is to domain transition where ever possible
but it depends on the situation. In this case a domain transition from gwibber_t to mozilla_t via mozilla_exec_t would likely be the
best decision. However this requires that policy is written manually to make it do what we want it to do.

But what if we just want to allow this single access vector? We could use the audit2allow tool to translate the avc denial into policy
language and to create a module. Than we could load the created policy module into the policy store with the semodule command.

echo "avc: denied { getattr } for pid=7604 comm="firefox" path="/usr/lib64/firefox-3.5.3/firefox" dev=dm-2 ino=1311607
scontext=dgrift_u:dgrift_r:gwibber_t:s0-s0:c0.c1023 tcontext=system_u:object_r:mozilla_exec_t:s0 tclass=file" | audit2allow -M
mygwibber; sudo semodule -i mygwibber.pp

Or we could do it ourselves:
echo "policy_module(mygwibber, 0.0.1)" > mygwibber.te;
echo "require { type gwibber_t, mozilla_exec_t; }" >> mygwibber.te;
echo "allow gwibber.te mozilla_exec_t:file getattr;" >> mygwibber.te;
make -f /usr/share/selinux/devel/Makefile mygwibber.pp
sudo semodule -i mygwibber.pp

So:

a. The source and/or the target is mislabelled (wrong type)

The types were correct.

b. It is a bug in policy.

It is a bug in policy because we determined that it is usually behaviour for gwibber to try to run the default browser to display
pages. Either we should allow it gwibber to run the browser (be it with the gwibber_t domain type or by domain transition with the
mozilla_t domain type) or we should make sure that no AVC denials are displayed when gwibber_t tries to access the mozilla executable
file with type mozilla_exec_t.

The rule that i am going to implement is this:

dontaudit gwibber_t mozilla_exec_t:file getattr;

Which says if domain type gwibber_t tries to get attributes of files with type mozilla_exec_t than "dontaudit" which means do not
print an avc denials (e.g. silently deny this)

That is just my personal preference. Its not something fixed. It is my security decision, whether good or bad.

c. Intrusion was detected and prevented.

No not really an intrusion since gwibber is designed to open pages in the default web browser which is firefox. So it is expected
behaviour. However i dont want to allow it. But i dont want to log the AVC denial when it happens either because its not important.

woensdag 16 september 2009

A perspective on SELinux

Many people think SELinux is complicated. SELinux is actually beautifully simple if you keep in mind that it
allows you to manage security very granular in computer systems which are very complex.

In this article i will try to explain the basics of SELinux. The things you need to know to find your
way around the SELinux environment.

SELinux can roughly be categorized in a few separate parts (ordered by importance):

1. The SELinux framework.
* 2. The tools to manage SELinux.
* 3. The policy.

In this article i will talk about The SELinux framework and the Type enforcement security model.

Knowledge of the SELinux framework is fundamental. If you are familiar with this it will enable you to
find your way around the rest.

Knowledge of the different SELinux security models is also important in this part i will talk about how
the Type enforcement security model fits into the SELinux Framework.

To learn about SELinux you have to know a bit about security and about computer systems.

What is security? Security is managing parties in an interaction. So for example if you want to secure a
human sitting on a chair. You have to manage the human and the chair. The human interacts. this is
called a subject, the chair does not interact and this is called an object. You could create policy that allows
the human to sit on the chair but not stand on it. Standing on it may cause it to break.

How do computer systems work? Computer systems are similar. processes are like humans. We call them
agents. A process therefore is a subject just like the human in my chair example. Processes interact. A
file in a computer system does not interact. The subject interacts with it. A file is a object. In a
computer system there are many classes of objects just like there are many kind of classes of object in
real life. My example was a chair but it could have been a bed or a bike etc. In a computer system a
object could be a file or a network port. Generally keep in mind that subjects interact and object get
interacted with.

So simplified:
Real life: human, chair, sit
Computer system: process, file, read

Humans can be categorized in many classes, the most obvious is man and woman but there are many types of
different humans. Processes in a computer system can also be categorized in many classes, for example a
process of a user or a process of a program.

Chairs can also be categorized in many classes. Theres rocket chairs and theres oother chairs as well,
but they are all chairs and objects. Objects in computer systems can also be categorized. There are
files and directories etcetera.

If you want to manage all these subjects and objects than you will want to categorize them. So that you
can create policy for each.

Subjects interact, objects dont. Lets look at some policy for the examples i gave.

real life:
allow man chair:rocket_chair sit;

computer system:
allow user file:dir read;

So in the real life example we allow a subject: human of the type: man to sit on a chair that is of the
class rocket_chair.

In the computer system example we allow a subject: process of the type user to read a file that is of
the class dir.

Our rule start with allow to signal that we want to allow the rule that follows, than follow our source
of the interaction. Which is always a subject since subject interact and object do not. Next is the
target. targets can be either subject or objects. subjects can interact with other subjects. for example
a man talking with a woman. Next is the class of the target. in our man/woman interaction the class
would of the target human would be woman. The last part defines the permission. What interaction is
allowed? in our man/chair example the man is allowed to site on a rocket_chair in our computer system
example the user process is allowed to read a dir. In our recent man talks to woman example we allow a
man to talk to a woman.

So back to SELinux. How does SELinux relates to all this. SELinux is for a large part in the kernel. It
is a framework. That means that SELinux provides us with some attributes so that we can create policy to
define what may and what may not. The attributes that SELinux provides are classes and permissions.
SELinux knows the classes of the parties involved in interaction in a computer system. It knows
subjects and the different classes of objects. SELinux also knows how subject interact with the
different object. In the real life example: SELinux knows theres a human interacting with a chair. It
knows the chair is a rocket chair and it know in what ways humans interact with chairs (sit for example)

So the framework provides us with the attributes to create rules. What it cannot do is make further
destictions between different subjects and objects. And to be able to manage everything we must make
distinctions as much as possible. This is what policy authors do. They make categorize sources and
targets in an interaction. for example. SELinux knows a human wants to site in a chair. It even knows it
is a rocket chair. But what if we want to make a destinction between a yellow rocket chair and a red
rocket chair? We want to be able to allow the human to site in the red rocket chair but not the yellow
one. SELinux framework does not know the color, we do. This is where types come in.

Policy authors assign types to subjects and objects. so in the real life example:

allow human chair:rocket_chair sit;

allow human_man_type red_chair_type:rocket_chair sit;

In the computer system:

allow process file:dir read;

allow user_process_type home_file_type:dir read;

Types allow us to further categorize the parties in an interaction.

If sufficient for now to know that the SELinux framework provides us with the classes and permission
attributes and that it allows us the further categorize the source and target in an interaction, be it
subjects or objects.

Type enforcement is a model where policy is enforcement for interaction between the types of the parties
involved. The types can be defined by the policy author and the best types depend on the environment.

In a computer environment you might want to make a destinction between a log file and a library file, a
program or a user. In a real life environment you might want to make a destinction between man or woman,
red rocket chair or yellow rocket chair. It depends on what colors rocket chairs exist in you
environment. Types enable us to define the properties of our environment.

By default all interaction is forbidden. if we want to allow something we have define what is allowed.
If there are many types and classes of parties in interaction in an environment you might be able to
imagine to amount of rules required to manage all this. For now it is sufficient to know that there are
also ways to group or tag different types.

If you want a human to be able to sit on all colored rocket chairs you could for example tag the
red_chair_type and the yellow_chair_type to be colored_chair_types and use the tag to make one single
rule for both colored chairs.

allow human_man_type colored_chair_types:rocket_chair sit;

So that is a very important thing to understand about SELinux and security in general. The enforcement
of types is the most important security model of SELinux.

Besides the "allow source target:target_class permission;" rules, there is another thing to understand
and that is called a type transition. You can make one type transition to another type.

For now it is suffice to know that subject and object types can be triggered to change. Subject types
can change via rules that define what should happen if a process executes a file and object
types can transition via rule that define what should happen if a file is created under a certain
parents type.

Type transitions help you futher categorize parties which will let you define rule for types in certain scenarios.

This is the basics about SELinux. Types are configured by policy authors. The have special meanings and those meanings can vary per
policy. So the only thing that really always applies are classes and permissions they stay the same. Types are defined by humans and
to learn what a certail type is allowed you would have to reference the policy to determine that.

And that is want you we are often confronted with, types. rules that govern how one type can interact with another. What we dont know
is what a certain type of a subject is supposed to be allowed to do to a certain type of a object.

These things can be figured out by referencing the policy and asking yourself the question what is the meaning of the type? what are
its properties? This is what makes SELinux environments complex because policy is based on a policy authors vision on a system. And
that vision may differ per policy model and environment.

SELinux itself is not complicated but if you want to manage a complex system you will have to create many different types and thats
where SELinux gets complex. If you have a simple system to manage than SELinux will also be simpeler. If you have a simple security
goal on a complex system you may also be able to implement a simpler policy that is targeted towards just reaching your simple
security goal.

Eventually its all just subjects, objects, classes and permissions when it comes to the SELinux framework and the type enforcement
security model.

The more granular the policy to govern how subject can interact with objects gets,the complexer selinux gets. But this is the strenght
of SELinux: it allows you to define very granular what is allowed and what not in a system.

Blame the policy author and the policy for the complexity of managing your Security-Enhanced Linux ( i bet the policy author will
blame Linux ;) )

A quick note about the tools:

What are the tools for:

labeling objects
parsing access vector denials
translating access vector denials to policy
finding suggestions to solutions for access vector denials
finding what type a object should have
changing types of objects
restoring types of objects
searching rules in the policy database
mapping linux logins to subject types

donderdag 10 september 2009

Some SELinux experiences that i want to share with you:


Disclaimer: I am just thinking out loud here, and i am sure that in some cases i do not fully understand the complexity or the underlying ideas of, and behind the issues that i am about to describe.

1. (not fedora specific)
User space processes own files on tmpfs for pulseaudio. These user space processes want to read (and unlink) each others pulseaudio files on tmpfs. To facilitate this, it requires much policy and also by allowing a user space process to read another user space processes pulseaudio tmpfs files , you also give it access to the user space process non pulseaudio tmpfs files. which might not be desired.

maybe somehow we can implement a attribute for user space processes pulseaudio files on tmpfs. and/or create a generic interface for this interaction.

3. (fedora specific)
xserver policy has been modified and xserver_user_x_domain_template and xserver_x_domain_template have been added. These templates could be used instead of xserver_user_client and xserver_common_app.

By calling these templates other xserver related policy in the domain that call it can for a large part also be removed. The interfaces mentioned above include most of the required xserver policy for user and application processes to function.

There are some notable exceptions:

xserver_rw_xdm_home_files

Also it appears that the interfaces mentioned above were designed with mls policy in mind. To be able to enable xserver object manager in a way that could benefit targeted policy i think a solution could be found so that xserver policy can be easily extended to provide a basic multi purpose useable policy for targeted as well ( maybe create interfaces for the various scenarios ) so that interfaces (or maybe tunable policy) can be called to make xserver object manager work in a basic form and/or specific form in targeted policy.

So that the admin can easily extend xserver policy for his custom needs without having to write local policy himself or having to implement his own custom interfaces, at least as much as possible.

An example of stuff that currently has no policy implemented but in many cases is required is for example the functionality to change mouse button (for left handed people) and the use of acceleration (3d)

Also we should keep in mind that there is a allow_write_xshm boolean that probably should be used where ever required instead of allowing access to this by adding fixed policy.

My point is that i think xserver object manager could at least to some extend be usable in a targeted policy, and that it could be extendible. Currently in fedora there is no easy way to make openoffice work nice with XACE. I cannot extend its policy due to 'not within scope issues' (user domain prefixes). The java SELinux implementation suffers similar issues.

3. (not fedora specific)
This also brings me to staff and user domains. These domains do not have access to some devices (cannot rw to dri, cannot rw to wifi, webcam etc) maybe we should implement some booleans for this with a $1. e.g. userdom_$1_use_dri etc. or maybe create users domains that add this functionality. I think this is a requirement to makes confined domains acceptable for day-to-day GUI use. Also the allow_execmem boolean is a bit too coarse. Lets face it we are not close to a working none execmem/execstack environment yet. For example nautilus requires it, totem, etc. many of these apps run in the user domain. Setting allow_execmem would in my view be overkill to just allow a single user domain execmem permission. allow_$1_execmem, where $1 is a specific user domain would in my view be a reasonable temporary solution. In either case i do not think we should just ignore the issue.

The "easy" access to execmem and devices like dri are in my view important to help make confined user domains usable for the general public in a GUI environment.

zondag 12 juli 2009

Policy development: optional policy

If you have looked into source policy you might have noticed optional policy blocks of policy in the type enforcement source policy files. Optional policy is used to make policy modular.

If you call a interface in your policy module that is hosted by another policy module then your module is dependent on that other module. If you decide to de-install the policy module that hosts the interface that you called in your policy module than your policy will no longer be able to build. This is because you're calling shared policy that no longer exists.

To avoid these dependencies, optional policy block are used.

Let's look at some examples:

http://oss.tresys.com/projects/refpolicy/browser/trunk/policy/modules/apps/mozilla.te

On line 244 to line 246 there is an optional policy block defined with policy that is borrowed from the gnome policy module.
This can determined since the interface is prefixed by the name (gnome) of the policy module that hosts the interface that is called by mozilla.

The interface facilitates permissions that allows firefox to connect to a unix stream socket that is owned by gnome gconf.

The interface is defined here:

http://oss.tresys.com/projects/refpolicy/browser/trunk/policy/modules/apps/gnome.if
(line 38 to line 55)

Let's use the semodule command to list both mozilla and gnome modules:

# semodule -l | grep gnome

gnome 2.0.0
gnomeclock 1.0.0

# semodule -l | grep mozilla
mozilla 2.0.1

We should be able to de-install both modules without getting into dependency troubles. If i decide to de-install the gnome module then the gnome_stream_connect_gconf interface becomes unavailable since it is defined in the gnome policy module that i just de-installed.

If we would have called gnome_stream_connect_gconf(mozilla_t) without using the optional policy block than we would run into trouble if we tried to de-install the gnome module. The compiler would complain about missing dependencies.

You should note that not all policy comes as a stand alone module. Some policies are not optional and they go into a single policy module called base.
As a rule keep in mind that if you can list a module with the semodule command then it can be de-installed.

If you borrow shared policy from another (optional) policy module then remember to place it into the optional policy block. For example all policy borrowed from gnome module can be placed into a optional policy block for gnome policy.

http://oss.tresys.com/projects/refpolicy/browser/trunk/policy/modules/apps/mozilla.te
(line 225 to line 227)

These are two interfaces that are hosted by the apache policy module. Both interfaces can go into a single optional policy block since both interfaces are dependent on the same apache module.

FAQ: SELinux denies access but AVC denials can not be found.

It happens. There are a few reasons for this:

1. Silenced AVC denials (access vector cache).

In policy one can define to silently deny access vectors. This means access is denied and attempts are not logged. Such a rule (access vector) would look like this for example (fictional):

dontaudit user_t var_t:dir { read open };

When a user that operates in the user_t user domain tries to read a var_t directory object type, access is denied. The attempt that was denied would not be logged.

In general the use of "dontaudit" rules should be kept to a minimum. The issue of being denied access and not finding an audit trail for this reason should not happen often at all.

There are exceptions, like restricted user domains. These processes are restricted/limited for reason and those restrictions/limits might give violation attempts when a user operating in such a domain tries to do something that is not allowed. In this case the AVC denials are anticipated and silenced to avoid flooding of the logs with meaning less entries.

There is a way to expose these silenced AVC denials, but be aware that this may fill up your logs quicker than expected.

The semodule command used with the -DB options unloads "dontaudit" rules on-the-fly. All attempts to violate policy are now logged.

The semodule command used with the -B option builds the policy with the "dontaudit" rules included. Silenced AVC denials are back in policy.

2. User space object managers.

User space object managers are SELinux extensions on application layers. Applications that implement a SELinux Access Control Extension provides classes and permissions to be used for SELinux Policy. The application itself enforces policy that is defined using the classes and permissions it has provided.

There are only few applications that are also user space object managers. DBus implements this and this feature is enabled by default. If some access is denied and you've unloaded the "dontaudit" rules using the semodule command with -DB option, but you still cannot find any audit trail, then chances are the DBUS access control extension is responsible.

In some cases, which might be due to a bug, DBUS sends its user_avc denials to /var/log/messages instead of the expected /var/log/audit/audit.log

So it is recommended to also see /var/log/messages or dmesg if you suspect SELinux denied access but you cannot find any audit trail.

SELinux denials are called AVC denials and can also be listed using the ausearch command with -m option and avc parameter.

User space object manager denials are called USER_AVC denials and can also be listed using the ausearch command with the -m option and user_avc parameter. Note that this only works for denials logged to /var/log/audit/audit.log

Conclusion:

If you suspect SELinux denied some access but you can not find the audit trail then consider building the policy without the "dontaudit" rules using semodule -DB. If you still cannot find any audit trail than maybe a user space object manager denied access. Look for USER_AVC denials in audit.log or look in /var/log/messages, or dmesg. The log file for the application itself may also have them.

I think the goal is to have everything log to audit.log for simplicity but at the moment this is not the case.

Tip:

You can use the sesearch command to list "dontaudit" rules that are currently built-in policy. For example to list "dontaudit" rules where the httpd_t is the source domain:

sesearch --dontaudit -s httpd_t

Have a look at "man sesearch"