Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve audit_rules_privileged_commands #12607

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,27 @@ SYSCALL=""
KEY="privileged"
SYSCALL_GROUPING=""

FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,)
PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid|/proc($|/.*$)" | awk '{ print $1 }')
for PARTITION in $PARTITIONS; do
PRIV_CMDS=$(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null)
for PRIV_CMD in $PRIV_CMDS; do
OTHER_FILTERS="-F path=$PRIV_CMD -F perm=x"
function add_audit_rule()
{
local PRIV_CMD="$1"
local OTHER_FILTERS="-F path=$PRIV_CMD -F perm=x"
# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
{{{ bash_fix_audit_syscall_rule("augenrules", "$ACTION_ARCH_FILTERS", "$OTHER_FILTERS", "$AUID_FILTERS", "$SYSCALL", "$SYSCALL_GROUPING", "$KEY") | indent(4) }}}
{{{ bash_fix_audit_syscall_rule("auditctl", "$ACTION_ARCH_FILTERS", "$OTHER_FILTERS", "$AUID_FILTERS", "$SYSCALL", "$SYSCALL_GROUPING", "$KEY") | indent(4) }}}
}

if {{{ bash_bootc_build() }}} ; then
PRIV_CMDS=$(find / -perm /6000 -type f -not -path "/sysroot/*" 2>/dev/null)
for PRIV_CMD in $PRIV_CMDS; do
add_audit_rule $PRIV_CMD
done
else
FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,)
PARTITIONS=$(findmnt -n -l -k -it "$FILTER_NODEV" | grep -Pv "noexec|nosuid|/proc($|/.*$)" | awk '{ print $1 }')
for PARTITION in $PARTITIONS; do
PRIV_CMDS=$(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null)
for PRIV_CMD in $PRIV_CMDS; do
add_audit_rule $PRIV_CMD
done
done
done
fi
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,50 @@
<criteria operator="AND">
<extend_definition definition_ref="audit_rules_augenrules"
comment="audit augenrules format is used"/>
<criterion test_ref="test_augenrules_all_priv_cmds_covered"
comment="augenrules cover all privileged commands on the system"/>
<criterion test_ref="test_augenrules_count_matches_system_priv_cmds"
comment="count of augenrules for priv cmds matches count of priv cmds in the system"/>
<criteria operator="OR">
<criteria operator="AND">
<extend_definition comment="The system is RHEL Image Mode" definition_ref="bootc" />
<criterion test_ref="test_augenrules_all_priv_cmds_covered_bootc"
comment="augenrules cover all privileged commands on the system"/>
<criterion test_ref="test_augenrules_count_matches_system_priv_cmds_bootc"
comment="count of augenrules for priv cmds matches count of priv cmds in the system"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="The system isn't RHEL Image Mode" definition_ref="bootc" negate="true" />
<criterion test_ref="test_augenrules_all_priv_cmds_covered"
comment="augenrules cover all privileged commands on the system"/>
<criterion test_ref="test_augenrules_count_matches_system_priv_cmds"
comment="count of augenrules for priv cmds matches count of priv cmds in the system"/>
</criteria>
</criteria>
</criteria>

<criteria operator="AND">
<extend_definition definition_ref="audit_rules_auditctl"
comment="audit auditctl format is used"/>
<criterion test_ref="test_auditctl_all_priv_cmds_covered"
comment="auditctl covers all privileged commands on the system"/>
<criterion test_ref="test_auditctl_count_matches_system_priv_cmds"
comment="count of auditctl for priv cmds matches count of priv cmds in the system"/>
<criteria operator="OR">
<criteria operator="AND">
<extend_definition comment="The system is RHEL Image Mode" definition_ref="bootc" />
<criterion test_ref="test_auditctl_all_priv_cmds_covered"
comment="auditctl covers all privileged commands on the system"/>
<criterion test_ref="test_auditctl_count_matches_system_priv_cmds"
comment="count of auditctl for priv cmds matches count of priv cmds in the system"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="The system isn't RHEL Image Mode" definition_ref="bootc" negate="true" />
<criterion test_ref="test_auditctl_all_priv_cmds_covered"
comment="auditctl covers all privileged commands on the system"/>
<criterion test_ref="test_auditctl_count_matches_system_priv_cmds"
comment="count of auditctl for priv cmds matches count of priv cmds in the system"/>
</criteria>
</criteria>
</criteria>
</criteria>
</definition>

<!-- First define OVAL entities that can be reused across tests below -->
<linux:partition_state id="state_audit_rules_privileged_commands_dev_partitons" version="1">
<linux:device operation="pattern match">^/dev/.*$</linux:device>
<linux:device operation="pattern match">^(/dev/.*|composefs)$</linux:device>
</linux:partition_state>

<linux:partition_state id="state_audit_rules_privileged_commands_nosuid_partitons" version="1">
Expand Down Expand Up @@ -64,6 +88,11 @@
<unix:filepath operation="pattern match">^/var/tmp/dracut.*</unix:filepath>
</unix:file_state>

<unix:file_state id="state_audit_rules_privileged_commands_sysroot" version="1"
comment="Used to filter out all files in the /sysroot directory">
<unix:filepath operation="pattern match">^/sysroot/.*$</unix:filepath>
</unix:file_state>

<!-- This file_object will only find privileged commands located only in file systems that allow
their execution. The recurse_file_system parameter is set to defined in order to make sure
the probe doesn't leave the scope of that mount point. For example, when probing "/", the
Expand All @@ -79,11 +108,25 @@
<filter action="include">state_setuid_or_setgid_set</filter>
<filter action="exclude">state_dracut_tmp_files</filter>
</unix:file_object>
<unix:file_object id="object_audit_rules_privileged_commands_bootc" version="1"
comment="Files with setuid or setgid permission in file systems that allow their execution">
<unix:behaviors recurse="directories" recurse_direction="down"
recurse_file_system="defined" max_depth="-1"/>
<unix:path operation="equals">/</unix:path>
<unix:filename operation="pattern match">^\w+</unix:filename>
<filter action="include">state_setuid_or_setgid_set</filter>
<filter action="exclude">state_dracut_tmp_files</filter>
<filter action="exclude">state_audit_rules_privileged_commands_sysroot</filter>
</unix:file_object>

<local_variable id="var_audit_rules_privileged_commands_priv_cmds" version="1"
datatype="string" comment="Filepath of all privileged commands found in the system">
<object_component item_field="filepath" object_ref="object_audit_rules_privileged_commands"/>
</local_variable>
<local_variable id="var_audit_rules_privileged_commands_priv_cmds_bootc" version="1"
datatype="string" comment="Filepath of all privileged commands found in the system">
<object_component item_field="filepath" object_ref="object_audit_rules_privileged_commands_bootc"/>
</local_variable>

<local_variable id="var_audit_rules_privileged_commands_priv_cmds_count" version="1"
datatype="int" comment="Count all privileged commands present in the system">
Expand All @@ -92,11 +135,22 @@
object_ref="object_audit_rules_privileged_commands"/>
</count>
</local_variable>
<local_variable id="var_audit_rules_privileged_commands_priv_cmds_count_bootc" version="1"
datatype="int" comment="Count all privileged commands present in the system">
<count>
<object_component item_field="filepath"
object_ref="object_audit_rules_privileged_commands_bootc"/>
</count>
</local_variable>

<ind:variable_object id="object_audit_rules_privileged_commands_priv_cmds_count" version="1"
comment="Number of all privileged commands in the system, regardless of audit rules.">
<ind:var_ref>var_audit_rules_privileged_commands_priv_cmds_count</ind:var_ref>
</ind:variable_object>
<ind:variable_object id="object_audit_rules_privileged_commands_priv_cmds_count_bootc" version="1"
comment="Number of all privileged commands in the system, regardless of audit rules.">
<ind:var_ref>var_audit_rules_privileged_commands_priv_cmds_count_bootc</ind:var_ref>
</ind:variable_object>

<!-- The intention of the first test is to ensure that exists at least one rule for each
privileged command found in the system. Therefore, a list of objects will be extracted
Expand All @@ -114,6 +168,10 @@
<ind:subexpression datatype="string" operation="not equal" var_check="all"
var_ref="var_audit_rules_privileged_commands_priv_cmds"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="state_unprivileged_commands_bootc" version="1">
<ind:subexpression datatype="string" operation="not equal" var_check="all"
var_ref="var_audit_rules_privileged_commands_priv_cmds_bootc"/>
</ind:textfilecontent54_state>

<!-- augenrules -->
<ind:textfilecontent54_object id="object_priv_cmds_from_augenrules" version="1">
Expand All @@ -123,37 +181,70 @@
<ind:instance operation="greater than or equal" datatype="int">1</ind:instance>
<filter action="exclude">state_unprivileged_commands</filter>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="object_priv_cmds_from_augenrules_bootc" version="1">
<ind:filepath operation="pattern match">^/etc/audit/rules\.d/.*\.rules$</ind:filepath>
<ind:pattern operation="pattern match"
var_ref="var_audit_rules_privileged_commands_rule_regex"/>
<ind:instance operation="greater than or equal" datatype="int">1</ind:instance>
<filter action="exclude">state_unprivileged_commands_bootc</filter>
</ind:textfilecontent54_object>

<ind:textfilecontent54_state id="state_priv_cmds_from_system" version="1">
<ind:subexpression datatype="string" operation="pattern match" var_check="at least one"
var_ref="var_audit_rules_privileged_commands_priv_cmds"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="state_priv_cmds_from_system_bootc" version="1">
<ind:subexpression datatype="string" operation="pattern match" var_check="at least one"
var_ref="var_audit_rules_privileged_commands_priv_cmds_bootc"/>
</ind:textfilecontent54_state>

<ind:textfilecontent54_test id="test_augenrules_all_priv_cmds_covered" version="1"
check="all" check_existence="all_exist"
comment="There is one augenrules rule for each privileged command on the system.">
<ind:object object_ref="object_priv_cmds_from_augenrules" />
<ind:state state_ref="state_priv_cmds_from_system" />
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="test_augenrules_all_priv_cmds_covered_bootc" version="1"
check="all" check_existence="all_exist"
comment="There is one augenrules rule for each privileged command on the system.">
<ind:object object_ref="object_priv_cmds_from_augenrules_bootc" />
<ind:state state_ref="state_priv_cmds_from_system_bootc" />
</ind:textfilecontent54_test>

<local_variable id="var_priv_cmds_from_augenrules_count" version="1"
datatype="int" comment="Count privileged commands found in audit rules in augenrules format">
<count>
<object_component item_field="subexpression" object_ref="object_priv_cmds_from_augenrules"/>
</count>
</local_variable>
<local_variable id="var_priv_cmds_from_augenrules_count_bootc" version="1"
datatype="int" comment="Count privileged commands found in audit rules in augenrules format">
<count>
<object_component item_field="subexpression" object_ref="object_priv_cmds_from_augenrules_bootc"/>
</count>
</local_variable>

<ind:variable_state id="state_priv_cmds_from_augenrules_count" version="1">
<ind:value datatype="int" operation="equals" var_check="at least one"
var_ref="var_priv_cmds_from_augenrules_count"/>
</ind:variable_state>
<ind:variable_state id="state_priv_cmds_from_augenrules_count_bootc" version="1">
<ind:value datatype="int" operation="equals" var_check="at least one"
var_ref="var_priv_cmds_from_augenrules_count_bootc"/>
</ind:variable_state>

<ind:variable_test id="test_augenrules_count_matches_system_priv_cmds" version="1"
check="all" check_existence="all_exist"
comment="Count of augenrules for priv cmds matches the count of priv cmds in the system">
<ind:object object_ref="object_audit_rules_privileged_commands_priv_cmds_count"/>
<ind:state state_ref="state_priv_cmds_from_augenrules_count"/>
</ind:variable_test>
<ind:variable_test id="test_augenrules_count_matches_system_priv_cmds_bootc" version="1"
check="all" check_existence="all_exist"
comment="Count of augenrules for priv cmds matches the count of priv cmds in the system">
<ind:object object_ref="object_audit_rules_privileged_commands_priv_cmds_count_bootc"/>
<ind:state state_ref="state_priv_cmds_from_augenrules_count_bootc"/>
</ind:variable_test>

<!-- auditctl -->
<ind:textfilecontent54_object id="object_priv_cmds_from_auditctl" version="1">
Expand All @@ -163,30 +254,59 @@
<ind:instance operation="greater than or equal" datatype="int">1</ind:instance>
<filter action="exclude">state_unprivileged_commands</filter>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="object_priv_cmds_from_auditctl_bootc" version="1">
<ind:filepath>/etc/audit/audit.rules</ind:filepath>
<ind:pattern operation="pattern match"
var_ref="var_audit_rules_privileged_commands_rule_regex"/>
<ind:instance operation="greater than or equal" datatype="int">1</ind:instance>
<filter action="exclude">state_unprivileged_commands_bootc</filter>
</ind:textfilecontent54_object>

<ind:textfilecontent54_test id="test_auditctl_all_priv_cmds_covered" version="1"
check="all" check_existence="all_exist"
comment="There is one auditctl rule for each privileged command on the system.">
<ind:object object_ref="object_priv_cmds_from_auditctl"/>
<ind:state state_ref="state_priv_cmds_from_system"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="test_auditctl_all_priv_cmds_covered_bootc" version="1"
check="all" check_existence="all_exist"
comment="There is one auditctl rule for each privileged command on the system.">
<ind:object object_ref="object_priv_cmds_from_auditctl_bootc"/>
<ind:state state_ref="state_priv_cmds_from_system_bootc"/>
</ind:textfilecontent54_test>

<local_variable id="var_priv_cmds_from_auditctl_count" version="1"
datatype="int" comment="Count privileged commands found in audit rules in auditctl format">
<count>
<object_component object_ref="object_priv_cmds_from_auditctl" item_field="subexpression"/>
</count>
</local_variable>
<local_variable id="var_priv_cmds_from_auditctl_count_bootc" version="1"
datatype="int" comment="Count privileged commands found in audit rules in auditctl format">
<count>
<object_component object_ref="object_priv_cmds_from_auditctl_bootc" item_field="subexpression"/>
</count>
</local_variable>

<ind:variable_state id="state_priv_cmds_from_auditctl_count" version="1">
<ind:value datatype="int" operation="equals" var_check="at least one"
var_ref="var_priv_cmds_from_auditctl_count"/>
</ind:variable_state>
<ind:variable_state id="state_priv_cmds_from_auditctl_count_bootc" version="1">
<ind:value datatype="int" operation="equals" var_check="at least one"
var_ref="var_priv_cmds_from_auditctl_count_bootc"/>
</ind:variable_state>

<ind:variable_test id="test_auditctl_count_matches_system_priv_cmds" version="1"
check="all" check_existence="all_exist"
comment="Count of auditctl rules for priv cmds matches the count of priv cmds in the system">
<ind:object object_ref="object_audit_rules_privileged_commands_priv_cmds_count" />
<ind:state state_ref="state_priv_cmds_from_auditctl_count" />
</ind:variable_test>
<ind:variable_test id="test_auditctl_count_matches_system_priv_cmds_bootc" version="1"
check="all" check_existence="all_exist"
comment="Count of auditctl rules for priv cmds matches the count of priv cmds in the system">
<ind:object object_ref="object_audit_rules_privileged_commands_priv_cmds_count_bootc" />
<ind:state state_ref="state_priv_cmds_from_auditctl_count_bootc" />
</ind:variable_test>
</def-group>
Loading