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 |