You may find it useful to resolve SELinux denials by using new
policy rules to allow the behavior. The ramifications on security
are impossible to predict. At the worst, you are back to standard
Linux security. Your policy changes may be enough to effectively
disable the confinement for one or more parts of a targeted daemon
policy.
You must take these considerations into account when adjusting
the policy. You can use apol to analyze
the transitions and TE rules, looking for where your policy changes
weaken security. For more information about working with apol, read Section 6.3 Using apol for Policy Analysis.
This procedure takes you through using audit2allow to add minor custom rules to the
existing policy. It assumes that you have one or more avc: denied messages in $AUDIT_LOG.
|
Tip |
|
Put local policy changes in $SELINUX_SRC/domains/misc/local.te, and file
context information in $SELINUX_SRC/file_contexts/misc/local.fc. Your
files are picked up on compile.
Separating your local customizations from the main source is
akin to maintaining a set of patches to pristine source code. When
you update the policy source, your changes won't be clobbered or at
risk.
If you package your own policy, follow a similar methodology.
Use the maintained, upstream source for either the supported
targeted or the unsupported strict policy. You can rebuild the
policy packages, having your changes be in standalone files such as
local.te or new files within $SELINUX_SRC/domains/program/.
If you change the existing TE files, you have to merge the
patches with each new policy. Remember that policy.conf is all of the various source files
concatenated together. It does not need to know where the content
came from, that is a decision made in the Makefile. The files and directories in
$SELINUX_SRC/ are a convenience for the policy writer. Following
the methods prescribed by the SELinux developers helps you in your
policy writing efforts.
|
|
Warning |
|
Just because audit2allow generates a
rule does not make it a good or secure rule.
You must look through the rules generated by audit2allow for a sanity check. For example, an
application generates an SELinux denial asking for read and write permission to /etc/passwd. A rule generated by audit2allow out of the audit log would allow that
permission. You need to understand the underlying application and
decide if it should have those
permissions.
This is one of the ways SELinux can help find flaws in
applications, where excessive and unnecessary levels of access are
attempted.
|
Adding Rules to the Policy Using audit2allow
-
Be sure you are in the policy source directory:
-
If you have an existing file at $SELINUX_SRC/domains/misc/local.te, make a backup
before proceeding with the rule creation:
# The directory domains/unused is ignored during the
# policy build and is a safe place for archiving.
cp domains/misc/local.te domains/unused/local.te.backup
|
-
Tell audit2allow to look in dmesg for denial messages, only since the last
load_policy ran, and write that to
domains/misc/local.te:
audit2allow -d -l -o domains/misc/local.te
|
Look in local.te to be sure you don't
have any duplicate rules. This is one reason for having audit2allow generate rules since the last load_policy, to keep from creating duplicates.
Once you have a complete set of working rules, you may want to
look for ways to rewrite and simplify the rules. One way to do this
is to have audit2allow run one final time
against the entire set of denial messages. It looks for ways to
consolidate rules into single lines:
# For example, two passes of audit2allow yield these rules:
allow httpd_t user_home_t:dir getattr;
allow httpd_t user_home_t:dir search;
# Looking at all of denials in $AUDIT_LOG
# may reveal some consolidation of rules, for example:
audit2allow -d -o domains/misc/consolidated_local.te
grep "user_home_t:dir" domains/misc/consolidated_local.te
allow httpd_t user_home_t:dir { getattr search };
|
-
Test your policy. Run make load and try
your previously denied operation(s).
-
At this point you may need to do multiple iterations of these
steps. Each additional rule allows the operation to get one step
further. You use the subsequent denial to write the next rule, and
the process continues.
After multiple iterations, you have a set of rules. Now you want
to analyze the rules to be sure they follow the principle of least
privilege. This is where policy analysis with apol is useful, as described in Section 6.3 Using apol for Policy Analysis.
To make your policy more elegant and efficient, look for macros
that provide you the permissions created by your new rules. You can
then scrap one or more rules in favor of a macro, which simplifies
code reuse. Ideally, your rules benefit from bug fixes and
enhancements to the entire policy because your rules build on the
policy as a privately maintained set of rules, relying upon the
overall structure of the parent policy.
For example, you are running the targeted policy on a newly
installed server that is using your in-house, custom-configured
syslog-ng instead of sysklogd. You find that the policy for syslogd does not cover all of the non-standard
logging operations that you perform. Some of the additional
operational requirements for your syslog-ng implementation are to open non-standard
files and UDP and TCP ports, as well as call non-standard
routines.
The following are a sampling of the avc: denied messages you have received:
Jan 10 04:02:17 example kernel: audit(1009218137.102:0): \
avc: denied { write } for pid=6109 exe=/sbin/syslog-ng \
name=kmsg dev=proc ino=-268435446 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:proc_kmsg_t tclass=file
Jan 10 04:02:17 example kernel: audit(1009218137.105:0): \
avc: denied { read } for pid=16202 exe=/bin/bash name=mtab \
dev=dm-0 ino=7146016 scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:etc_runtime_t tclass=file
...
Jan 10 16:20:35 example kernel: audit(1009284205.210:0): \
avc: denied { chown } for pid=6109 exe=/sbin/syslog-ng \
capability=0 scontext=system_u:system_r:syslogd_t \
tcontext=system_u:system_r:syslogd_t tclass=capability
Jan 10 16:20:35 example kernel: audit(1009284205.210:0): \
avc: denied { fowner } for pid=6109 exe=/sbin/syslog-ng \
capability=3 scontext=system_u:system_r:syslogd_t \
tcontext=system_u:system_r:syslogd_t tclass=capability
Jan 10 16:20:35 example kernel: audit(1009284205.210:0): \
avc: denied { fsetid } for pid=6109 exe=/sbin/syslog-ng \
capability=4 scontext=system_u:system_r:syslogd_t \
tcontext=system_u:system_r:syslogd_t tclass=capability
...
Jan 10 16:20:35 example kernel: audit(1009284205.422:0): \
avc: denied { search } for pid=1411 exe=/bin/bash \
name=sbin dev=dm-0 ino=7356417 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:sbin_t tclass=dir
Jan 10 16:20:35 example kernel: audit(1009284205.422:0): \
avc: denied { getattr } for pid=1411 exe=/bin/bash \
path=/bin/bash dev=dm-0 ino=1245248 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:shell_exec_t tclass=file
Jan 10 16:20:35 example kernel: audit(1009284205.423:0): \
avc: denied { getattr } for pid=1411 exe=/bin/bash \
path=/bin/rm dev=dm-0 ino=1245243 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:bin_t tclass=file
Jan 10 16:20:35 example kernel: audit(1009284205.423:0): \
avc: denied { execute_no_trans } for pid=1411 \
exe=/bin/bash path=/bin/rm dev=dm-0 ino=1245243 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:bin_t tclass=file
Jan 10 16:20:35 example kernel: audit(1009284205.423:0): \
avc: denied { read } for pid=1411 exe=/bin/bash \
path=/bin/rm dev=dm-0 ino=1245243 \
scontext=system_u:system_r:syslogd_t \
tcontext=system_u:object_r:bin_t tclass=file
|
Running all of the audit messages through audit2allow generates a set of rules:
cd /etc/selinux/targeted/src/policy/domains/misc/
audit2allow -i /var/log/messages -o ./local.te
cat local.te
allow syslogd_t bin_t:dir search;
allow syslogd_t bin_t:file { execute execute_no_trans getattr \
read };
allow syslogd_t bin_t:lnk_file read;
allow syslogd_t etc_runtime_t:file { getattr read };
allow syslogd_t proc_kmsg_t:file write;
allow syslogd_t proc_t:file { getattr read };
allow syslogd_t sbin_t:dir search;
allow syslogd_t shell_exec_t:file { execute execute_no_trans \
getattr read };
allow syslogd_t self:capability { chown fowner fsetid sys_admin };
allow syslogd_t usr_t:dir { add_name remove_name write };
allow syslogd_t usr_t:file { append create getattr read setattr \
unlink write };
|
Looking at the rules, you can see that there are two for
execution permissions, and some other rules that are associated by
having the same object, bin_t.
There is also a permission to search directories of the type
sbin_t, but no execution
permissions.
From your reading of the available macros in $SELINUX_SRC/macros/, you know that can_exec() provides a common set of
permissions for domains wishing to execute certain file types. This
includes permissions that are likely to arise once the first set of
basic rules are used. For example, after audit2allow generates a rule giving read permission
to a process, the process often wants getattr permission. The can_exec() macro includes the permission
rx_file_perms, which grants a
common set of read and execute permissions to a file. Now you can
make this substitution:
# these related rules ...
allow syslogd_t bin_t:dir search;
allow syslogd_t bin_t:file { execute execute_no_trans getattr \
read };
allow syslogd_t shell_exec_t:file { execute execute_no_trans \
getattr read };
# combine into this one rule
can_exec(syslog_t, { bin_t shell_exec_t } )
|
You also see in the rules that two of the rules are from
syslog-ng attempting to use a directory in
/usr/ of the type usr_t:
# These rules can be eliminated by properly labeling
# the files in the target location.
allow syslogd_t usr_t:dir { add_name remove_name write };
allow syslogd_t usr_t:file { append create getattr read setattr \
unlink write };
|
Your configuration uses a directory in /usr/ to write log files to. Because this log data
is not user data, it should have an appropriate label, var_log_t.
# If syslog-ng is configured to put logs in /usr/local/logs/,
# relabel that directory, and new files in the directory
# inherit the proper type.
chcon -R -t var_log_t /usr/local/logs/
|
Now you can trim the rules in $SELINUX_SRC/domains/misc/local.te to read:
can_exec(syslog_t, { bin_t shell_exec_t } )
allow syslogd_t etc_runtime_t:file { getattr read };
allow syslogd_t proc_kmsg_t:file write;
allow syslogd_t proc_t:file { getattr read };
allow syslogd_t bin_t:lnk_file read;
allow syslogd_t sbin_t:dir search;
allow syslogd_t self:capability { chown fowner fsetid sys_admin };
|
You also need to make an appropriate file contexts file so that
the labeling is maintained during relabeling operations. Put the
following context declaration in /etc/selinux/targeted/src/policy/file_contexts/misc/local.fc:
/usr/syslog(/.*)? system_u:object_r:var_log_t
|