[redhat-lspp] rbac-self-test 0.3
George C. Wilson
ltcgcw at us.ibm.com
Mon Jan 22 21:37:17 UTC 2007
Here is the current self-test. It is not yet ready for prime time.
But you can at least see where it is heading.
--
George Wilson <ltcgcw at us.ibm.com>
IBM Linux Technology Center
-------------- next part --------------
#!/usr/bin/python
################################################################################
# #
# RBACPP Self Test #
# #
# Performs various tests on the system to verify RBACPP compliance. #
# #
# Copyright (C) 2007 IBM Corporation #
# Licensed under GNU General Public License #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; see the file COPYING. If not, write to #
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. #
# #
# Author: George C. Wilson <gcwilson at us.ibm.com> #
# #
# History: #
# 20 Jan 2007 - Add BLP checks, policy, and audit records #
# 30 Oct 2006 - Version 2.0 - Call AIDE, make into class #
# 04 Apr 2006 - Initial version #
# #
################################################################################
# #
# USE #
# #
# 1. First take a snapshot of the filesystem hashes using AIDE. #
# #
# rbacpp-self-test --snapshot --verbose #
# #
# 2. Run the the self test in normal mode. #
# #
# rbacpp-self-test --verbose #
# #
# 3. Add the command to your crontab. #
# #
# rbacpp-self-test #
# #
# 4. Check the audit and system logs for failures. #
# #
################################################################################
import string
import re
import os
import os.path
import sys
import shutil
import pwd
import syslog
import socket
import selinux
import audit
class SelfTest:
#
# init
# Returns: None
#
def __init__(self):
self.default_failure_action = 'shutdown'
self.config_file = '/etc/security/rbac-self-test.conf'
self.program_name = os.path.basename(sys.argv[0])
self.read = False
self.write = True
self.SystemHigh = 'SystemHigh'
self.SystemLow = 'SystemLow'
self.expectSuccess = False
self.expectFailure = True
return(None)
#
# Usage
#
# Returns: 0 - Success
#
def usage(self):
print self.program_name + ': [--snapshot] [--verbose]'
return(0)
#
# Parse args
#
# Returns: rc: 0 - Success, 1 - Failure
#
def args_parse(self):
self.opt_snapshot = False
self.opt_verbose = False
rc = 0
for opt in sys.argv[1:]:
if opt == '--snapshot' or opt == '-s':
self.opt_snapshot = True
elif opt == '--verbose' or opt == '-v':
self.opt_verbose = True
else:
rc = 1
return(rc)
#
# Init failure action from config file.
#
# Returns: 0 - Successfully logged audit message, 1 - Failure
#
def failure_action_init(self):
rc = 0
self.failure_action = self.default_failure_action
try:
action_file = open(self.config_file, 'r')
if action_file.closed == False:
action_list = action_file.readlines()
action = action_list[0]
action = action.strip()
action_file.close()
except:
self.log_error('Cannot read auditd action: ' + filename)
rc = 1
if rc == 0:
if ((action == 'panic') or (action == 'shutdown') or (action == 'log')):
self.failure_action = action
else:
self.log_error('Invalid failure action: ' + action)
rc = 1
return (rc)
#
# Perform the failure action.
#
# Return: Don't care.
#
def failure_action_perform(self):
if self.failure_action == 'panic':
print 'How do you panic the system?'
elif self.failure_action == 'shutdown':
os.system('/sbin/init s')
elif self.failure_action != 'log':
print 'Invalid audit failure action - logging only'
#
# Log an audit message
#
# Returns: 0 - Successfully logged audit message, 1 - Failure
#
def error_log(self, message):
rc = 0
try:
hostname = socket.gethostname()
try:
hostaddr = socket.gethostbyname(hostname)
except:
hostaddr = 'unknown'
except:
hostname = 'unknown'
try:
ttyname = os.readlink('/proc/self/fd/0')
if ttyname.find('/dev') != 0:
ttyname = 'notatty'
except:
ttyname = 'unknown'
message = self.program_name + ': ' + message
try:
audit.audit_log_user_message(self.audit_fd,
audit.AUDIT_ANOM_RBAC_FAIL,
message,
hostname,
hostaddr,
ttyname,
0)
except:
print 'Attention: Cannot log audit record'
rc = 1
try:
syslog.openlog('Security')
syslog.syslog(syslog.LOG_AUTH|syslog.LOG_EMERG,
'Attention: Cannot log audit record (message was: ' + message + ')')
syslog.closelog()
except:
print 'Attention: Cannot log syslog record'
if self.opt_verbose == True:
print message
self.failure_action_perform()
return(rc)
#
# Initialize audit.
#
# Returns: An audit handle; Non-negative integer - Success, -1 - Failure
#
def audit_open(self):
rc = 0
self.audit_fd = -1
rc = self.failure_action_init()
print self.failure_action
if rc != 0:
self.error_log('Cannot set failure action in audit init')
if rc == 0:
try:
self.audit_fd = audit.audit_open()
except:
self.error_log('Cannot open audit')
rc = 1
return(rc)
#
# Deinitialize audit.
#
# Returns: 0 - Success, 1 - Failure
#
def audit_close(self):
rc = 0
if self.audit_fd >= 0:
try:
audit.audit_close(self.audit_fd)
except:
self.error_log('Cannot close audit')
rc = 1
return(rc)
#
# Verify SELinux is enabled, enforcing, and MLS.
#
# Returns: 0 - Success, 1 - Failure
#
def selinux_verify(self):
rc = 0
if selinux.is_selinux_enabled() != 1:
self.error_log('SELinux is not enabled')
rc = 1
if rc == False and selinux.security_getenforce() != 1:
self.error_log('SELinux is not in enforcing mode')
rc = 1
if rc == False and selinux.is_selinux_mls_enabled() != 1:
self.error_log('SELinux MLS is not enabled')
rc = 1
return(rc)
#
# Verify auditd is running
#
# Returns: 0 - Success, 1 - Failure
#
def auditd_verify(self):
print "auditd_verify"
print audit.audit_is_enabled(self.audit_fd)
rc = (audit.audit_is_enabled(self.audit_fd) <= 0)
print rc
if rc != 0:
self.error_log('cannot get audit status')
return(rc)
#
# Take an AIDE snapshot of configuration files.
#
# Returns: 0 - Success, 1 - Failure
#
def snapshot_take(self):
rc = os.system('/usr/sbin/aide --init')
if rc != 0:
self.error_log('Cannot initialize AIDE database')
rc = 1
else:
try:
shutil.move('/var/lib/aide/aide.db.new.gz', '/var/lib/aide/aide.db/gz')
except:
self.error_log('Cannot move new AIDE database into place')
rc = 1
return(rc)
#
# Verify integrity of configuration files.
#
# Returns: 0 - Success, 1 - Failure
#
def snapshot_verify(self):
# print os.tempnam( '', 'rbac-self-test' )
rc = os.system('/usr/sbin/aide --check --report file:///tmp/rbac_self_test.tmp')
if rc != 0:
self.error_log('Cannot verify AIDE database')
rc = 1
return(rc)
#
# mlsfile_test
#
def mlsfile_test(self, write, slevel, olevel, expectfail):
rc = 0
cmd1 = 'runcon -r sysadm_r -t sysadm_t -l ' + olevel + \
' -- echo "Test" > /var/run/rbac-self-test-' + olevel
if write == True:
cmd2 = 'runcon -r sysadm_r -t sysadm_t -l ' + slevel + \
' -- echo "Test Update" > /var/run/rbac-self-test-' + olevel
else:
cmd2 = 'runcon -r sysadm_r -t sysadm_t -l ' + slevel + \
' -- tail /var/run/rbac-self-test' + olevel
rc = os.system(cmd1)
if rc == 0:
rc = os.system(cmd2)
else:
print "Cannot open temp file"
rc = 1
if expectfail == True:
rc = not rc
return(rc)
#
# Main
#
# Exits: 0 - Success, 1 - Failure
#
rc = 0
st = SelfTest()
if rc == 0:
rc = st.args_parse()
if rc != 0:
st.usage()
if rc == 0:
st.audit_open()
if rc == 0 and st.audit_fd < 0:
rc = 1
if rc == 0 and st.opt_snapshot == True:
rc = st.snapshot_take()
else:
if rc == 0:
rc = st.selinux_verify()
if rc == 0:
rc = st.auditd_verify()
if rc == 0:
rc = st.snapshot_verify()
if rc == 0:
rc = st.mlsfile_test(st.read, st.SystemHigh, st.SystemLow, st.expectSuccess)
if rc == 0:
rc = st.mlsfile_test(st.read, st.SystemLow, st.SystemHigh, st.expectFailure)
if rc == 0:
rc = st.mlsfile_test(st.write, st.SystemHigh, st.SystemLow, st.expectFailure)
if rc == 0:
rc = st.mlsfile_test(st.write, st.SystemLow, st.SystemHigh, st.expectSuccess)
if rc == 0 and st.opt_verbose == True:
print 'The RBAC self test succeeded.'
if rc == 0:
st.audit_close()
sys.exit(rc)
-------------- next part --------------
# installation paths
SHAREDIR := /usr/share/selinux
AWK ?= gawk
NAME ?= $(shell $(AWK) -F= '/^SELINUXTYPE/{ print $$2 }' /etc/selinux/config)
MLSENABLED := $(shell cat /selinux/mls)
ifeq ($(MLSENABLED),)
MLSENABLED := 1
endif
ifeq ($(MLSENABLED),1)
MCSFLAG=-mcs
endif
TYPE ?= $(NAME)${MCSFLAG}
HEADERDIR := $(SHAREDIR)/devel/include
include $(HEADERDIR)/Makefile
-------------- next part --------------
policy_module(local,1.0)
gen_require(`
type secadm_t, secadm_devpts_t, secadm_tty_device_t;
role secadm_r;
')
rbacselftest_run(secadm_t, secadm_r, { secadm_tty_device_t secadm_devpts_t })
gen_require(`
type sysadm_t, sysadm_devpts_t, sysadm_tty_device_t;
role sysadm_r;
')
rbacselftest_run(sysadm_t, sysadm_r, { sysadm_tty_device_t sysadm_devpts_t })
gen_require(`
type auditd_log_t;
')
allow secadm_t auditd_log_t:file write;
allow secadm_t rbacselftest_exec_t:file { setattr write };
-------------- next part --------------
/usr/sbin/rbac-self-test -- gen_context(system_u:object_r:rbacselftest_exec_t,mls_systemhigh)
/var/run/rbac-self-test-SystemLow -- gen_context(system_u:object_r:rbacselftest_var_run_t,mls_systemlow)
/var/run/rbac-self-test-SystemHigh -- gen_context(system_u:object_r:rbacselftest_var_run_t,SystemHigh)
/etc/security/rbac-self-test.conf -- gen_context(system_u:object_r:rbacselftest_etc_t,SystemHigh)
-------------- next part --------------
## <summary>RBAC Self Test</summary>
########################################
## <summary>
## Execute rbacselftest in the rbacselftest domain.
## </summary>
## <param name="domain">
## <summary>
## The type of the process performing this action.
## </summary>
## </param>
#
interface(`rbacselftest_domtrans',`
gen_require(`
type rbacselftest_t, rbacselftest_exec_t;
')
corecmd_search_sbin($1)
domain_auto_trans($1,rbacselftest_exec_t,rbacselftest_t)
allow $1 rbacselftest_t:fd use;
allow rbacselftest_t $1:fd use;
allow rbacselftest_t $1:fifo_file rw_file_perms;
allow rbacselftest_t $1:process sigchld;
')
########################################
## <summary>
## Execute rbacselftest programs in the rbacselftest domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <param name="role">
## <summary>
## The role to allow the AIDE domain.
## </summary>
## </param>
## <param name="terminal">
## <summary>
## The type of the terminal allow the AIDE domain to use.
## </summary>
## </param>
#
interface(`rbacselftest_run',`
gen_require(`
type rbacselftest_t;
')
rbacselftest_domtrans($1)
role $2 types rbacselftest_t;
allow rbacselftest_t $3:chr_file rw_file_perms;
')
-------------- next part --------------
policy_module(rbacselftest,1.0)
gen_require(`
type aide_db_t;
type bin_t;
type shell_exec_t;
type ld_so_t;
type var_run_t;
type local_login_t;
')
########################################
#
# Declarations
#
type rbacselftest_t;
type rbacselftest_exec_t;
domain_type(rbacselftest_t)
domain_entry_file(rbacselftest_t,rbacselftest_exec_t)
# rbacselftest database
type rbacselftest_var_run_t;
files_type(rbacselftest_var_run_t)
# rbacselftest etc
type rbacselftest_etc_t;
files_type(rbacselftest_etc_t)
########################################
#
# rbacselftest local policy
#
seutil_use_newrole_fds(rbacselftest_t)
# database actions
allow rbacselftest_t rbacselftest_var_run_t:dir rw_dir_perms;
allow rbacselftest_t rbacselftest_var_run_t:file create_file_perms;
allow rbacselftest_t var_run_t:dir {write add_name};
allow rbacselftest_t var_run_t:file {write create};
# etc actions
allow rbacselftest_t rbacselftest_var_run_t:file read_file_perms;
# audit
allow rbacselftest_t self:capability {audit_write audit_control};
allow rbacselftest_t self:netlink_audit_socket { create_netlink_socket_perms nlmsg_relay };
# aide
allow rbacselftest_t aide_db_t:dir rw_dir_perms;
allow rbacselftest_t aide_db_t:dir create_file_perms;
# binaries
allow rbacselftest_t bin_t:file { entrypoint execute getattr read execute_no_trans};
allow rbacselftest_t bin_t:lnk_file read;
# shell
allow rbacselftest_t shell_exec_t:file {execute execute_no_trans };
# ld.so
allow rbacselftest_t ld_so_t:file execute;
# login
allow rbacselftest_t local_login_t:fd use;
########################################
#
# Local policy
#
allow rbacselftest_t self:capability { dac_override fowner };
files_read_all_files(rbacselftest_t)
libs_use_shared_libs(rbacselftest_t)
More information about the redhat-lspp
mailing list