Work with a proper daemon under Red Hat Enterprise Linux. This means it has an
initscript in /etc/init.d/ and can be managed
using chkconfig. For example, this procedure
assumes you are going to use the service command to
control starting and stopping the daemon.
For this procedure, you are writing policy for the fictional
foo package and it's associated
foo daemon. Use a real daemon name in this place
when developing your own policy.
Create a file at
$SELINUX_SRC/domains/program/foo.te.
Put the daemon domain macro call in the file:
Create the file contexts file,
$SELINUX_SRC/file_contexts/program/foo.fc.
Put the first list of file contexts in
file.fc. You may need to add to this later,
depending on the needs of the foo daemon.
/usr/bin/foo -- system_u:object_r:foo_exec_t
/var/run/foo.pid -- system_u:object_r:foo_var_run_t
/etc/foo.conf -- system_u:object_r:foo_conf_t |
Load the new policy with make load.
Label the foo files:
restorecon /usr/bin/foo /var/run/foo.pid /etc/foo.conf |
Start the daemon, service foo start.
Examine your audit log for denial messages:
grep "avc: denied" /var/log/messages > /tmp/avc_denials
cat /tmp/avc_denials |
Familiarize yourself with the errors the daemon is generating. You
are writing policy with the help of audit2allow, but you need to understand
the nature of the denials. You can also use seaudit for viewing the
log messages, as explained in Section 6.2 Using seaudit for Audit Log Analysis.
Use audit2allow to start the first round of policy rules.
audit2allow -l -i /var/log/messages -o \
/etc/selinux/targeted/src/policy/domains/program/foo.te |
When looking at the generated rules, if you see a rule that gives the
foo_t domain
read access to a file or directory,
change the permission to read { read gettatr
}. The domain is likely to need that permission if
it already wants to read a file.
Look to see if the foo_t domain
tries to create a network socket, that is,
udp_socket or
tcp_socket as the object class in the
AVC denial:
avc: denied { create } for pid=7279 exe=/usr/bin/foo \
scontext=root:system_r:foo_t tcontext=root:system_r:foo_t\
tclass=udp_socket |
If this is the case, then add the
can_network() macro to
foo.te:
Continue to iterate through the basic steps to generate all the
rules you need. Each set of rules added to the policy may reveal
additional permission needs from the
foo_t domain.
Start the daemon.
Read the AVC messages.
Write policy from the AVC messages, using audit2allow and your own
knowledge, looking for chances to use macros.
Load new policy.
Go back to beginning, starting the daemon ...
If the domain tries to access
port_t, which relates to
tclass=tcp_socket or
tclass=udp_socket in the AVC log
message, you need to determine what port number foo
needs to use. To diagnose, put these rules in
foo.te:
allow foo_t port_t:tcp_socket name_bind;
auditallow foo_t port_t:tcp_socket name_bind; |
The auditallow rule helps you
determine the nature of the port connection attempt.
Iterate through the remaining AVC denials. When they are resolved
with new policy, you can configure the unique port requirements for
the foo_t domain.
With the daemon started, determine which port
foo is using. Look at the AVC allowed message and
see what port the daemon is connected to:
lsof | grep foo.*TCP
foo 2283 root 3u IPv6 3192 TCP *:4242 (LISTEN) |
The foo daemon is listening on port 4242.
Remove the generic port_t rule,
replacing it with a specific rule for a new port type based on the
foo_t domain.
type foo_port_t, port_type;
allow foo_t foo_port_t:tcp_socket name_bind; |
Add this line to $SELINUX_SRC/file_contexts. This
reserves the port 4242 for the domain
foo_t:
ifdef(`foo.te', `portcon tcp 4242 system_u:object_r:foo_port_t') |