What is Spacewalk?
System management system.
- With WebUI and XMLRPC API.
The upstream for Red Hat Network Satellite and SuSE Manager.
Written in Java, Python, and Perl.
Tomcat, httpd with mod_perl and mod_python/mod_wsgi, monitoring, cobbler, database (Oracle, PostgreSQL), jabberd, osa-dispatcher.
700+ thousand lines of code.
http://spacewalk.redhat.com/
https://fedorahosted.org/spacewalk/
What is SELinux?
Yet another access control mechanism.
Orthogonal to Un*x users, groups, access rights.
$ ps uZ | grep bash unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 adelton 32115 0.0 0.0 5248 1744 pts/63 Ss 12:52 0:00 bash $ ps uZ | grep 1380 system_u:system_r:hald_t:s0 root 1380 0.0 0.0 4008 1044 ? S 10:03 0:00 hald-runner
We use targeted policy, only care about types (_t).
What is not explicitly allowed is denied.
The goal for confining
-
All daemons run in their special domains or use domains native in the OS.
httpd_t
(for Apache),java_t
(tomcat)spacewalk_monitoring_t
oracle_db_t
,oracle_tnslsnr_t
jabberd_t
,osa_dispatcher_t
- No unconfined_t, nor initrc_t.
-
And there should be no AVC denials
- Yes, we will see one in a minute.
- You get to love Z. You get to love iterative work.
Creating SELinux policy modules
- Type enforcement
policy_module(swmon,1.0) # Type for the processes type swmon_t; domain_type(swmon_t); # Type for the startup script type swmon_exec_t; files_type(swmon_exec_t); # Various macros that bring many allows init_daemon_domain(swmon_t, swmon_exec_t)
- File contexts
# Define mapping of labels /etc/rc\.d/np\.d/step ⏎ gen_context(system_u:object_r:swmon_exec_t,s0)
Building and loading the module
# ln -s /usr/share/selinux/devel/Makefile # make Compiling targeted swmon module /usr/bin/checkmodule: loading policy configuration from tmp/swmon.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 10) to tmp/swmon.mod Creating targeted swmon.pp policy package rm tmp/swmon.mod tmp/swmon.mod.fc # semodule -i swmon.pp
Check the transition
# cp /bin/sleep .
# chcon -t swmon_exec_t sleep
# cat > init.sh
#!/bin/bash
./sleep 10 &
ps --no-headers -Zp $! | awk '{print $1}'
Ctrl+D
# chmod a+x init.sh
# chcon -t initrc_exec_t init.sh
# ./init.sh
unconfined_u:system_r:swmon_t:s0
- Here we forced the context with
chcon
. - For production we use
restorecon
which sets the context based on file context definitions.
Make it possible to restart
- Type enforcement
require { type java_t; type initrc_t; } type sw_initrc_exec_t; domain_entry_file(initrc_t, sw_initrc_exec_t) domain_auto_trans(java_t, sw_initrc_exec_t, initrc_t)
- File contexts
/sbin/rhn-sat-restart-silent ⏎ gen_context(system_u:object_r:sw_initrc_exec_t,s0)
Oracle RDBMS
- Source not available, prime target for confining.
- Oracle SELinux policy module written by Rob Myers.
- We ended up splitting the file contexts (
.fc
) to separate module:# semodule -l | grep oracle oracle-nofcontext 1.1.2 oracle-port 1.1.2 oracle-xe 10.2.0.19.1
- The
-nofcontext
has all the allows and no paths (file contexts), theoracle-xe
has only the paths. - We ship
oracle-rhnsat
with RHN Satellite for the layout of the embedded Oracle installation.
Example of AVC denial
- In
/var/log/audit/audit.log
. - Process wants to read its own pid file:
avc: denied { read } for pid=3169 comm="osa-dispatcher" name="osa-dispatcher.pid" dev=dm-0 ino=516358 scontext=unconfined_u:system_r:osa_dispatcher_t:s0 tcontext=unconfined_u:object_r:osa_dispatcher_var_run_t:s0 tclass=file
- Should we
allow
it?
allow osa_dispatcher_t osa_dispatcher_var_run_t:file read;
Example of AVC denial (cont'd)
- Actually, the process does not need to read the file, change the application:
- fd = os.open(pid_file, os.O_RDWR | os.O_CREAT, 0644) + fd = os.open(pid_file, \ + os.O_WRONLY | os.O_APPEND | os.O_CREAT, 0644)
- To
allow
is not always the best course of action. - Often, SELinux helps us to find issues in our code.
- Or in someone else's code.
Example: TCP socket connect
avc: denied { name_connect } for pid=12935 comm="osa-dispatcher" dest=5432 scontext=system_u:system_r:osa_dispatcher_t:s0 tcontext=system_u:object_r:postgresql_port_t:s0 tclass=tcp_socket
- The
audit2allow
command printsallow
s needed:
allow osa_dispatcher_t postgresql_port_t:tcp_socket ⏎ name_connect;
- With
-R
option, it tries to use existing interfaces instead of rawallow
s:
corenet_tcp_connect_postgresql_port(osa_dispatcher_t)
Example: directory searched
avc: denied { search } for pid=20967 comm="oracle" name="log" dev=dm-0 ino=657566 scontext=system_u:system_r:oracle_db_t:s0 tcontext=user_u:object_r:oracle_tnslsnr_log_t:s0 tclass=dir
- Setting SELinux to permissive reveals other actions that were stopped by the first failed one:
{ search } for pid=20967 comm="oracle" name="log" dev=dm-0 ino=657566 scontext=system_u:system_r:oracle_db_t:s0 tcontext=user_u:object_r:oracle_tnslsnr_log_t:s0 tclass=dir { write } for pid=20967 comm="oracle" name="log" dev=dm-0 ino=657566 scontext=system_u:system_r:oracle_db_t:s0 tcontext=user_u:object_r:oracle_tnslsnr_log_t:s0 tclass=dir { add_name } for pid=20967 comm="oracle" name="sqlnet.log" scontext=system_u:system_r:oracle_db_t:s0 tcontext=user_u:object_r:oracle_tnslsnr_log_t:s0 tclass=dir { create } for pid=20967 comm="oracle" name="sqlnet.log" scontext=system_u:system_r:oracle_db_t:s0 tcontext=system_u:object_r:oracle_tnslsnr_log_t:s0 tclass=file { append open } for pid=20967 comm="oracle" name="sqlnet.log" dev=dm-0 ino=670163 scontext=system_u:system_r:oracle_db_t:s0 tcontext=system_u:object_r:oracle_tnslsnr_log_t:s0 tclass=file { getattr } for pid=20967 comm="oracle" path="/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/network/log/sqlnet.log" dev=dm-0 ino=670163 scontext=system_u:system_r:oracle_db_t:s0 tcontext=system_u:object_r:oracle_tnslsnr_log_t:s0 tclass=file
Example: directory searched (cont'd)
- Allow Oracle database process to create its error log in listener's directory:
filetrans_pattern(oracle_db_t, oracle_tnslsnr_log_t, ⏎ oracle_db_log_t, { file }) create_files_pattern(oracle_db_t, oracle_tnslsnr_log_t, ⏎ oracle_db_log_t)
/usr/lib/oracle/xe/(.*/)?network/log/sqlnet\.log(.*)? ⏎ gen_context(user_u:object_r:oracle_db_log_t,s0)
- Many AVC denials are about logging errors.
- Which only happen from time to time.
- Clues for this one were found in database's alert log, based on timestamps.
Example: reading from cron's pipe
avc: denied { ioctl } for pid=13527 comm="Monitoring" path="pipe:[4553708]" dev=pipefs ino=4553708 scontext=user_u:system_r:spacewalk_monitoring_t:s0 tcontext=system_u:system_r:crond_t:s0-s0:c0.c1023 tclass=fifo_file
- Our programs reads from crond. How could it happen?
- The reason was that crond run logrotate which then restarted our program.
- And it inherited stdin from crond.
- The actual fix in logrotate's config file:
- /sbin/service Monitoring restart > /dev/null 2>/dev/null || true + /sbin/service Monitoring restart < /dev/null >/dev/null 2>/dev/null || true
Example: Apache and rpm database
- Apache httpd deamon attempts to read the rpm database:
avc: denied { search } for pid=10689 comm="httpd" name="rpm" dev=dm-0 ino=1179651 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:rpm_var_lib_t:s0 tclass=dir avc: denied { getattr } for pid=10689 comm="httpd" path="/var/lib/rpm" dev=dm-0 ino=1179651 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:rpm_var_lib_t:s0 tclass=dir avc: denied { open } for pid=10689 comm="httpd" name="Packages" dev=dm-0 ino=1179656 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:rpm_var_lib_t:s0 tclass=file
Example: Apache and rpm db (cont'd)
- Luckily we knew that it was happening while a mod_python process was processing uploaded rpm.
- And it did not need to look at the database after all:
dontaudit httpd_t rpm_var_lib_t:dir list_dir_perms; dontaudit httpd_t rpm_var_lib_t:file read_file_perms;
Conclusion
https://fedorahosted.org/spacewalk/wiki/Features/SELinux
We put the exact AVC denial to commit message which addresses the problem in Spacewalk git repo.
For our reference.
It also makes it easy for you to search through our fixes.
Comments and patches most welcome.
- Thank you for your attention.