[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