Configure selinux to allow snmpd to read to a custom location

selinuxsnmp

I have snmpd executing a script under /custom/location/myscript.sh. If I disable selinux all works well. If I enable selinux it stops working and if I do an audit2why I see the following:

type=AVC msg=audit(1371990300.064:23445): avc:  denied  { read open } for  pid=21423 comm="snmpd" name="myscript.sh" dev=dm-0 ino=1046532 scontext=unconfined_u:system_r:snmpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file

    Was caused by:
            Missing type enforcement (TE) allow rule.

            You can use audit2allow to generate a loadable module to allow this access.

type=AVC msg=audit(1371990313.066:23446): avc:  denied  { read open } for  pid=21425 comm="snmpd" name="myscript.sh" dev=dm-0 ino=1046532 scontext=unconfined_u:system_r:snmpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file

    Was caused by:
            Missing type enforcement (TE) allow rule.

            You can use audit2allow to generate a loadable module to allow this access.

If I do an ls -Z /custom/location I see the following:

-rwxr-xr-x. root root unconfined_u:object_r:default_t:s0 myscript.sh

So I need to do an chcon-R on the directory. I tried:

chcon -R -u unconfined_u -r system_r -t snmpd_t /custom/location

Only to get the following error:

chcon: failed to change context of `myscript.sh' to `unconfined_u:system_r:snmpd_t:s0': Permission denied

I also tried using audit2allow to create a custom policy but that didn't seem to work.

I really don't want to disable selinux. Can anyone assist me in understanding how I can allow snmpd the ability to read from /custom/location?

Thanks
Brad

Since the output was so long I am truncating a bit – but here's the results of ausearch:

----
time->Sun Jun 23 08:27:13 2013
type=SYSCALL msg=audit(1371990433.731:23453): arch=c000003e syscall=189 success=no            
exit=-13 a0=11760e0 a1=3e50616319 a2=1178ef0 a3=21 items=0 ppid=20865 pid=21434 auid=0 
uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=3863 comm="chcon"
exe="/usr/bin/chcon" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=   
(null)

type=AVC msg=audit(1371990433.731:23453): avc:  denied  { relabelto } for  pid=21434  
comm="chcon" name="scripts" dev=dm-0 ino=1046530 
scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 
tcontext=unconfined_u:system_r:snmpd_t:s0 tclass=dir
----
time->Sun Jun 23 08:27:24 2013
type=SYSCALL msg=audit(1371990444.075:23454): arch=c000003e syscall=59 success=no     
exit=-13 a0=7fdb8933c6d0 a1=7fdb8933c3a0 a2=7fff16ef1790 a3=1f items=0 ppid=18001 
pid=21435 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) 
ses=3765 comm="snmpd" exe="/usr/sbin/snmpd" subj=unconfined_u:system_r:snmpd_t:s0 key=
(null)

type=AVC msg=audit(1371990444.075:23454): avc:  denied  { read open } for  pid=21435 
comm="snmpd" name="snmp.sh" dev=dm-0 ino=1046532 
scontext=unconfined_u:system_r:snmpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 
tclass=file
----

Best Answer

First of all, you probably don't need to write a custom module at all.

I would place the script in one of the places SELinux expects to find executables, to start with, and only if that is not possible, using the output of audit2allow (and not audit2why, which gives a human friendly message, but is less useful in terms of understanding the real problem), I'd analyze the AVC denial.

Changing the security context of a file is a privileged operation, and you gave no clue with regards to which user you tried to execute that command with. Use root.

Note, however, that the proper thing to do is not to chcon the file, because that won't persist after a system relabel, but to use semanage to add a a security context to the path:

semanage fcontext -a type_enforcement "/path/expression(/.*)?"

Check the output of semanage fcontext -l | less for a first impression on how a path expression should look like.

For a deeper understanding of the problem, you need to know which contexts the snmpd daemon is allowed to transition to. You can find help in the seinfo and sesearch manpages.

The upstream source code of the refpolicy can be checked in order to learn what would be the correct label for an executable to be read by an snmpd_t labeled file. A probably better idea is to download the source policy matching the policy version in use in your OS using your package manager.

This is a good resource to understand the function of the different files (esp. 5b) involved in a module.

First check the file contexts defined for this module (this is what you'll find using semanage fcontext -l | grep snmp, more or less):


# cat refpolicy/policy/modules/contrib/snmp.fc
/etc/rc\.d/init\.d/((snmpd)|(snmptrapd))        --      gen_context(system_u:object_r:snmpd_initrc_exec_t,s0)

/usr/sbin/snmptrap      --      gen_context(system_u:object_r:snmpd_exec_t,s0)
/usr/sbin/snmptrapd     --      gen_context(system_u:object_r:snmpd_exec_t,s0)

/usr/share/snmp/mibs/\.index    --      gen_context(system_u:object_r:snmpd_var_lib_t,s0)

/var/agentx(/.*)?       gen_context(system_u:object_r:snmpd_var_lib_t,s0)
/var/net-snmp(/.*)      gen_context(system_u:object_r:snmpd_var_lib_t,s0)

/var/lib/net-snmp(/.*)? gen_context(system_u:object_r:snmpd_var_lib_t,s0)
/var/lib/snmp(/.*)?     gen_context(system_u:object_r:snmpd_var_lib_t,s0)

/var/log/snmpd\.log.*   --      gen_context(system_u:object_r:snmpd_log_t,s0)

/var/run/net-snmpd(/.*)?        gen_context(system_u:object_r:snmpd_var_run_t,s0)
/var/run/snmpd(/.*)?    gen_context(system_u:object_r:snmpd_var_run_t,s0)
/var/run/snmpd\.pid     --      gen_context(system_u:object_r:snmpd_var_run_t,s0)

Then, the type enforcement rules defined here (snippet):


# head -22 refpolicy/policy/modules/contrib/snmp.te
policy_module(snmp, 1.14.0)

########################################
#
# Declarations
#

type snmpd_t;
type snmpd_exec_t;
init_daemon_domain(snmpd_t, snmpd_exec_t)

type snmpd_initrc_exec_t;
init_script_file(snmpd_initrc_exec_t)

type snmpd_log_t;
logging_log_file(snmpd_log_t)

type snmpd_var_run_t;
files_pid_file(snmpd_var_run_t)

type snmpd_var_lib_t;
files_type(snmpd_var_lib_t)

And finally, the interface (snmp.if), file.

With this information at hand, you need to find out what would be the right context for snmpd to be able to execute a script, and then, manually add a context rule to the path where the executable will be.