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

Minor modifications to RHEL STIG profiles #11327

Merged
merged 3 commits into from
Dec 4, 2023

Conversation

vojtapolasek
Copy link
Collaborator

Description:

  • remove RHEL 8 STIG reference from the rule audit_immutable_login_uids because it is no longer selected in the profile
  • replace audit_immutable_login_uids rule with audit_rules_immutable_login_uids in RHEL 9 STIG profile
  • remove RHEL 7 STIG reference from the rule passwd_system-auth_substack because it is currently not selected in the relevant profile; I will create an issue to evaluate if this rule should be added to the profile.
  • remove RHEL8 STIG reference from the rule package_libreport-plugin-rhtsupport_removed because it is not part of the relevant profile

Rationale:

Cleaning up rule references. It can create confusions when comparing reports of our content with the content provided by DISA.

Review Hints:

@vojtapolasek vojtapolasek added RHEL9 Red Hat Enterprise Linux 9 product related. Update Rule Issues or pull requests related to Rules updates. Update Profile Issues or pull requests related to Profiles updates. RHEL7 Red Hat Enterprise Linux 7 product related. RHEL8 Red Hat Enterprise Linux 8 product related. STIG STIG Benchmark related. labels Dec 1, 2023
@vojtapolasek vojtapolasek added this to the 0.1.72 milestone Dec 1, 2023
Copy link

github-actions bot commented Dec 1, 2023

Start a new ephemeral environment with changes proposed in this pull request:

Fedora Environment
Open in Gitpod

Oracle Linux 8 Environment
Open in Gitpod

@@ -19,7 +19,6 @@ identifiers:
references:
disa: CCI-000381
srg: SRG-OS-000095-GPOS-00049
stigid@rhel8: RHEL-08-040001
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ grep -r 'package_libreport-plugin-rhtsupport_removed' products/rhel8/profiles/stig*
products/rhel8/profiles/stig_gui.profile:    - '!package_libreport-plugin-rhtsupport_removed'
products/rhel8/profiles/stig.profile:    - package_libreport-plugin-rhtsupport_removed

This rule is in the RHEL 8 STIG profile please either remove the rule from the profiles or drop this commit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to keep the rule as it is. It aligns with the spirit of the rule. In the GUI profile unfortunately we can't select it because it is Anaconda dependency. Do you agree with this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works for me.

Copy link

github-actions bot commented Dec 4, 2023

This datastream diff is auto generated by the check Compare DS/Generate Diff

Click here to see the full diff
ansible remediation for rule 'xccdf_org.ssgproject.content_rule_sudo_remove_no_authenticate' differs.
--- xccdf_org.ssgproject.content_rule_sudo_remove_no_authenticate
+++ xccdf_org.ssgproject.content_rule_sudo_remove_no_authenticate
@@ -1,5 +1,5 @@
 - name: Find /etc/sudoers.d/ files
-  find:
+  ansible.builtin.find:
     paths:
     - /etc/sudoers.d/
   register: sudoers
@@ -16,7 +16,7 @@
   - sudo_remove_no_authenticate
 
 - name: Remove lines containing !authenticate from sudoers files
-  replace:
+  ansible.builtin.replace:
     regexp: (^(?!#).*[\s]+\!authenticate.*$)
     replace: '# \g<1>'
     path: '{{ item.path }}'

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_sudo_remove_nopasswd' differs.
--- xccdf_org.ssgproject.content_rule_sudo_remove_nopasswd
+++ xccdf_org.ssgproject.content_rule_sudo_remove_nopasswd
@@ -1,5 +1,5 @@
 - name: Find /etc/sudoers.d/ files
-  find:
+  ansible.builtin.find:
     paths:
     - /etc/sudoers.d/
   register: sudoers
@@ -16,7 +16,7 @@
   - sudo_remove_nopasswd
 
 - name: Remove lines containing NOPASSWD from sudoers files
-  replace:
+  ansible.builtin.replace:
     regexp: (^(?!#).*[\s]+NOPASSWD[\s]*\:.*$)
     replace: '# \g<1>'
     path: '{{ item.path }}'

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_sudo_require_authentication' differs.
--- xccdf_org.ssgproject.content_rule_sudo_require_authentication
+++ xccdf_org.ssgproject.content_rule_sudo_require_authentication
@@ -1,5 +1,5 @@
 - name: Find /etc/sudoers.d/ files
-  find:
+  ansible.builtin.find:
     paths:
     - /etc/sudoers.d/
   register: sudoers
@@ -16,7 +16,7 @@
   - sudo_require_authentication
 
 - name: Remove lines containing NOPASSWD from sudoers files
-  replace:
+  ansible.builtin.replace:
     regexp: (^(?!#).*[\s]+NOPASSWD[\s]*\:.*$)
     replace: '# \g<1>'
     path: '{{ item.path }}'
@@ -37,7 +37,7 @@
   - sudo_require_authentication
 
 - name: Find /etc/sudoers.d/ files
-  find:
+  ansible.builtin.find:
     paths:
     - /etc/sudoers.d/
   register: sudoers
@@ -54,7 +54,7 @@
   - sudo_require_authentication
 
 - name: Remove lines containing !authenticate from sudoers files
-  replace:
+  ansible.builtin.replace:
     regexp: (^(?!#).*[\s]+\!authenticate.*$)
     replace: '# \g<1>'
     path: '{{ item.path }}'

OVAL for rule 'xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod' differs.
--- oval:ssg-audit_rules_privileged_commands_kmod:def:1
+++ oval:ssg-audit_rules_privileged_commands_kmod:def:1
@@ -1,7 +1,7 @@
 criteria OR
 criteria AND
 extend_definition oval:ssg-audit_rules_augenrules:def:1
-criterion oval:ssg-test_kmod_augenrules:tst:1
+criterion oval:ssg-test_audit_rules_privileged_commands_kmod_augenrules:tst:1
 criteria AND
 extend_definition oval:ssg-audit_rules_auditctl:def:1
-criterion oval:ssg-test_kmod_auditctl:tst:1
+criterion oval:ssg-test_audit_rules_privileged_commands_kmod_auditctl:tst:1

bash remediation for rule 'xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod' differs.
--- xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod
+++ xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod
@@ -1,139 +1,318 @@
 # Remediation is applicable only in certain platforms
 if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && rpm --quiet -q audit; then
 
+ACTION_ARCH_FILTERS="-a always,exit"
+OTHER_FILTERS="-F path=/usr/bin/kmod -F perm=x"
+AUID_FILTERS="-F auid>=1000 -F auid!=unset"
+SYSCALL=""
+KEY="privileged"
+SYSCALL_GROUPING=""
 # Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
+unset syscall_a
+unset syscall_grouping
+unset syscall_string
+unset syscall
+unset file_to_edit
+unset rule_to_edit
+unset rule_syscalls_to_edit
+unset other_string
+unset auid_string
+unset full_rule
+
+# Load macro arguments into arrays
+read -a syscall_a <<< $SYSCALL
+read -a syscall_grouping <<< $SYSCALL_GROUPING
+
 # Create a list of audit *.rules files that should be inspected for presence and correctness
 # of a particular audit rule. The scheme is as follows:
 #
 # -----------------------------------------------------------------------------------------
-# Tool used to load audit rules	| Rule already defined	|  Audit rules file to inspect	  |
-# -----------------------------------------------------------------------------------------
-#	auditctl		|     Doesn't matter	|  /etc/audit/audit.rules	  |
-# -----------------------------------------------------------------------------------------
-# 	augenrules		|          Yes		|  /etc/audit/rules.d/*.rules	  |
-# 	augenrules		|          No		|  /etc/audit/rules.d/$key.rules  |
-# -----------------------------------------------------------------------------------------
+#  Tool used to load audit rules | Rule already defined  |  Audit rules file to inspect    |
+# -----------------------------------------------------------------------------------------
+#        auditctl                |     Doesn't matter    |  /etc/audit/audit.rules         |
+# -----------------------------------------------------------------------------------------
+#        augenrules              |          Yes          |  /etc/audit/rules.d/*.rules     |
+#        augenrules              |          No           |  /etc/audit/rules.d/$key.rules  |
+# -----------------------------------------------------------------------------------------
+#
 files_to_inspect=()
 
-
-# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules'
-# into the list of files to be inspected
-files_to_inspect+=('/etc/audit/audit.rules')
-
-# Finally perform the inspection and possible subsequent audit rule
-# correction for each of the files previously identified for inspection
-for audit_rules_file in "${files_to_inspect[@]}"
+# If audit tool is 'augenrules', then check if the audit rule is defined
+# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection
+# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection
+default_file="/etc/audit/rules.d/$KEY.rules"
+# As other_filters may include paths, lets use a different delimiter for it
+# The "F" script expression tells sed to print the filenames where the expressions matched
+readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules)
+# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet
+if [ ${#files_to_inspect[@]} -eq "0" ]
+then
+    file_to_inspect="/etc/audit/rules.d/$KEY.rules"
+    files_to_inspect=("$file_to_inspect")
+    if [ ! -e "$file_to_inspect" ]
+    then
+        touch "$file_to_inspect"
+        chmod 0640 "$file_to_inspect"
+    fi
+fi
+
+# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
+skip=1
+
+for audit_file in "${files_to_inspect[@]}"
 do
-    # Check if audit watch file system object rule for given path already present
-    if grep -q -P -- "^[\s]*-w[\s]+/usr/bin/kmod" "$audit_rules_file"
-    then
-        # Rule is found => verify yet if existing rule definition contains
-        # all of the required access type bits
-
-        # Define BRE whitespace class shortcut
-        sp="[[:space:]]"
-        # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
-        current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/bin/kmod $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
-        # Split required access bits string into characters array
-        # (to check bit's presence for one bit at a time)
-        for access_bit in $(echo "x" | grep -o .)
+    # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
+    # i.e, collect rules that match:
+    # * the action, list and arch, (2-nd argument)
+    # * the other filters, (3-rd argument)
+    # * the auid filters, (4-rd argument)
+    readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d"  -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
+
+    candidate_rules=()
+    # Filter out rules that have more fields then required. This will remove rules more specific than the required scope
+    for s_rule in "${similar_rules[@]}"
+    do
+        # Strip all the options and fields we know of,
+        # than check if there was any field left over
+        extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//"  -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
+        grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
+    done
+
+    if [[ ${#syscall_a[@]} -ge 1 ]]
+    then
+        # Check if the syscall we want is present in any of the similar existing rules
+        for rule in "${candidate_rules[@]}"
         do
-            # For each from the required access bits (e.g. 'w', 'a') check
-            # if they are already present in current access bits for rule.
-            # If not, append that bit at the end
-            if ! grep -q "$access_bit" <<< "$current_access_bits"
+            rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
+            all_syscalls_found=0
+            for syscall in "${syscall_a[@]}"
+            do
+                grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
+                   # A syscall was not found in the candidate rule
+                   all_syscalls_found=1
+                   }
+            done
+            if [[ $all_syscalls_found -eq 0 ]]
             then
-                # Concatenate the existing mask with the missing bit
-                current_access_bits="$current_access_bits$access_bit"
+                # We found a rule with all the syscall(s) we want; skip rest of macro
+                skip=0
+                break
             fi
+
+            # Check if this rule can be grouped with our target syscall and keep track of it
+            for syscall_g in "${syscall_grouping[@]}"
+            do
+                if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
+                then
+                    file_to_edit=${audit_file}
+                    rule_to_edit=${rule}
+                    rule_syscalls_to_edit=${rule_syscalls}
+                fi
+            done
         done
-        # Propagate the updated rule's access bits (original + the required
-        # ones) back into the /etc/audit/audit.rules file for that rule
-        sed -i "s#\($sp*-w$sp\+/usr/bin/kmod$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
     else
-        # Rule isn't present yet. Append it at the end of $audit_rules_file file
-        # with proper key
-
-        echo "-w /usr/bin/kmod -p x -k modules" >> "$audit_rules_file"
+        # If there is any candidate rule, it is compliant; skip rest of macro
+        if [ "${#candidate_rules[@]}" -gt 0 ]
+        then
+            skip=0
+        fi
+    fi
+
+    if [ "$skip" -eq 0 ]; then
+        break
     fi
 done
+
+if [ "$skip" -ne 0 ]; then
+    # We checked all rules that matched the expected resemblance pattern (action, arch & auid)
+    # At this point we know if we need to either append the $full_rule or group
+    # the syscall together with an exsiting rule
+
+    # Append the full_rule if it cannot be grouped to any other rule
+    if [ -z ${rule_to_edit+x} ]
+    then
+        # Build full_rule while avoid adding double spaces when other_filters is empty
+        if [ "${#syscall_a[@]}" -gt 0 ]
+        then
+            syscall_string=""
+            for syscall in "${syscall_a[@]}"
+            do
+                syscall_string+=" -S $syscall"
+            done
+        fi
+        other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
+        auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
+        full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
+        echo "$full_rule" >> "$default_file"
+        chmod o-rwx ${default_file}
+    else
+        # Check if the syscalls are declared as a comma separated list or
+        # as multiple -S parameters
+        if grep -q -- "," <<< "${rule_syscalls_to_edit}"
+        then
+            delimiter=","
+        else
+            delimiter=" -S "
+        fi
+        new_grouped_syscalls="${rule_syscalls_to_edit}"
+        for syscall in "${syscall_a[@]}"
+        do
+            grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
+               # A syscall was not found in the candidate rule
+               new_grouped_syscalls+="${delimiter}${syscall}"
+               }
+        done
+
+        # Group the syscall in the rule
+        sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
+    fi
+fi
+unset syscall_a
+unset syscall_grouping
+unset syscall_string
+unset syscall
+unset file_to_edit
+unset rule_to_edit
+unset rule_syscalls_to_edit
+unset other_string
+unset auid_string
+unset full_rule
+
+# Load macro arguments into arrays
+read -a syscall_a <<< $SYSCALL
+read -a syscall_grouping <<< $SYSCALL_GROUPING
+
 # Create a list of audit *.rules files that should be inspected for presence and correctness
 # of a particular audit rule. The scheme is as follows:
 #
 # -----------------------------------------------------------------------------------------
-# Tool used to load audit rules	| Rule already defined	|  Audit rules file to inspect	  |
-# -----------------------------------------------------------------------------------------
-#	auditctl		|     Doesn't matter	|  /etc/audit/audit.rules	  |
-# -----------------------------------------------------------------------------------------
-# 	augenrules		|          Yes		|  /etc/audit/rules.d/*.rules	  |
-# 	augenrules		|          No		|  /etc/audit/rules.d/$key.rules  |
-# -----------------------------------------------------------------------------------------
+#  Tool used to load audit rules | Rule already defined  |  Audit rules file to inspect    |
+# -----------------------------------------------------------------------------------------
+#        auditctl                |     Doesn't matter    |  /etc/audit/audit.rules         |
+# -----------------------------------------------------------------------------------------
+#        augenrules              |          Yes          |  /etc/audit/rules.d/*.rules     |
+#        augenrules              |          No           |  /etc/audit/rules.d/$key.rules  |
+# -----------------------------------------------------------------------------------------
+#
 files_to_inspect=()
 
-# If the audit is 'augenrules', then check if rule is already defined
-# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection.
-# If rule isn't defined, add '/etc/audit/rules.d/modules.rules' to list of files for inspection.
-readarray -t matches < <(grep -HP "[\s]*-w[\s]+/usr/bin/kmod" /etc/audit/rules.d/*.rules)
-
-# For each of the matched entries
-for match in "${matches[@]}"
+
+# If audit tool is 'auditctl', then add '/etc/audit/audit.rules'
+# file to the list of files to be inspected
+default_file="/etc/audit/audit.rules"
+files_to_inspect+=('/etc/audit/audit.rules' )
+
+# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead
+skip=1
+
+for audit_file in "${files_to_inspect[@]}"
 do
-    # Extract filepath from the match
-    rulesd_audit_file=$(echo $match | cut -f1 -d ':')
-    # Append that path into list of files for inspection
-    files_to_inspect+=("$rulesd_audit_file")
+    # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern,
+    # i.e, collect rules that match:
+    # * the action, list and arch, (2-nd argument)
+    # * the other filters, (3-rd argument)
+    # * the auid filters, (4-rd argument)
+    readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d"  -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file")
+
+    candidate_rules=()
+    # Filter out rules that have more fields then required. This will remove rules more specific than the required scope
+    for s_rule in "${similar_rules[@]}"
+    do
+        # Strip all the options and fields we know of,
+        # than check if there was any field left over
+        extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//"  -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule")
+        grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule")
+    done
+
+    if [[ ${#syscall_a[@]} -ge 1 ]]
+    then
+        # Check if the syscall we want is present in any of the similar existing rules
+        for rule in "${candidate_rules[@]}"
+        do
+            rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs)
+            all_syscalls_found=0
+            for syscall in "${syscall_a[@]}"
+            do
+                grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || {
+                   # A syscall was not found in the candidate rule
+                   all_syscalls_found=1
+                   }
+            done
+            if [[ $all_syscalls_found -eq 0 ]]
+            then
+                # We found a rule with all the syscall(s) we want; skip rest of macro
+                skip=0
+                break
+            fi
+
+            # Check if this rule can be grouped with our target syscall and keep track of it
+            for syscall_g in "${syscall_grouping[@]}"
+            do
+                if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls"
+                then
+                    file_to_edit=${audit_file}
+                    rule_to_edit=${rule}
+                    rule_syscalls_to_edit=${rule_syscalls}
+                fi
+            done
+        done
+    else
+        # If there is any candidate rule, it is compliant; skip rest of macro
+        if [ "${#candidate_rules[@]}" -gt 0 ]
+        then
+            skip=0
+        fi
+    fi
+
+    if [ "$skip" -eq 0 ]; then
+        break
+    fi
 done
-# Case when particular audit rule isn't defined yet
-if [ "${#files_to_inspect[@]}" -eq "0" ]
-then
-    # Append '/etc/audit/rules.d/modules.rules' into list of files for inspection
-    key_rule_file="/etc/audit/rules.d/modules.rules"
-    # If the modules.rules file doesn't exist yet, create it with correct permissions
-    if [ ! -e "$key_rule_file" ]
-    then
-        touch "$key_rule_file"
-        chmod 0640 "$key_rule_file"
-    fi
-    files_to_inspect+=("$key_rule_file")
+
+if [ "$skip" -ne 0 ]; then
+    # We checked all rules that matched the expected resemblance pattern (action, arch & auid)
+    # At this point we know if we need to either append the $full_rule or group
+    # the syscall together with an exsiting rule
+
+    # Append the full_rule if it cannot be grouped to any other rule
+    if [ -z ${rule_to_edit+x} ]
+    then
+        # Build full_rule while avoid adding double spaces when other_filters is empty
+        if [ "${#syscall_a[@]}" -gt 0 ]
+        then
+            syscall_string=""
+            for syscall in "${syscall_a[@]}"
+            do
+                syscall_string+=" -S $syscall"
+            done
+        fi
+        other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true
+        auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true
+        full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true
+        echo "$full_rule" >> "$default_file"
+        chmod o-rwx ${default_file}
+    else
+        # Check if the syscalls are declared as a comma separated list or
+        # as multiple -S parameters
+        if grep -q -- "," <<< "${rule_syscalls_to_edit}"
+        then
+            delimiter=","
+        else
+            delimiter=" -S "
+        fi
+        new_grouped_syscalls="${rule_syscalls_to_edit}"
+        for syscall in "${syscall_a[@]}"
+        do
+            grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || {
+               # A syscall was not found in the candidate rule
+               new_grouped_syscalls+="${delimiter}${syscall}"
+               }
+        done
+
+        # Group the syscall in the rule
+        sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
+    fi
 fi
-
-# Finally perform the inspection and possible subsequent audit rule
-# correction for each of the files previously identified for inspection
-for audit_rules_file in "${files_to_inspect[@]}"
-do
-    # Check if audit watch file system object rule for given path already present
-    if grep -q -P -- "^[\s]*-w[\s]+/usr/bin/kmod" "$audit_rules_file"
-    then
-        # Rule is found => verify yet if existing rule definition contains
-        # all of the required access type bits
-
-        # Define BRE whitespace class shortcut
-        sp="[[:space:]]"
-        # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule
-        current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/bin/kmod $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file")
-        # Split required access bits string into characters array
-        # (to check bit's presence for one bit at a time)
-        for access_bit in $(echo "x" | grep -o .)
-        do
-            # For each from the required access bits (e.g. 'w', 'a') check
-            # if they are already present in current access bits for rule.
-            # If not, append that bit at the end
-            if ! grep -q "$access_bit" <<< "$current_access_bits"
-            then
-                # Concatenate the existing mask with the missing bit
-                current_access_bits="$current_access_bits$access_bit"
-            fi
-        done
-        # Propagate the updated rule's access bits (original + the required
-        # ones) back into the /etc/audit/audit.rules file for that rule
-        sed -i "s#\($sp*-w$sp\+/usr/bin/kmod$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file"
-    else
-        # Rule isn't present yet. Append it at the end of $audit_rules_file file
-        # with proper key
-
-        echo "-w /usr/bin/kmod -p x -k modules" >> "$audit_rules_file"
-    fi
-done
 
 else
     >&2 echo 'Remediation is not applicable, nothing was done'

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod' differs.
--- xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod
+++ xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands_kmod
@@ -17,12 +17,124 @@
   - no_reboot_needed
   - restrict_strategy
 
-- name: Check if watch rule for /usr/bin/kmod already exists in /etc/audit/rules.d/
-  find:
-    paths: /etc/audit/rules.d
-    contains: ^\s*-w\s+/usr/bin/kmod\s+-p\s+x(\s|$)+
-    patterns: '*.rules'
-  register: find_existing_watch_rules_d
+- name: Perform remediation of Audit rules for /usr/bin/kmod
+  block:
+
+  - name: Declare list of syscalls
+    set_fact:
+      syscalls: []
+      syscall_grouping: []
+
+  - name: Check existence of  in /etc/audit/rules.d/
+    find:
+      paths: /etc/audit/rules.d
+      contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F
+        path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$
+      patterns: '*.rules'
+    register: find_command
+    loop: '{{ (syscall_grouping + syscalls) | unique }}'
+
+  - name: Reset syscalls found per file
+    set_fact:
+      syscalls_per_file: {}
+      found_paths_dict: {}
+
+  - name: Declare syscalls found per file
+    set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path
+      :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}"
+    loop: '{{ find_command.results | selectattr(''matched'') | list }}'
+
+  - name: Declare files where syscalls were found
+    set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten
+      | map(attribute='path') | list }}"
+
+  - name: Count occurrences of syscalls in paths
+    set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item,
+      0) }) }}"
+    loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'')
+      | list }}'
+
+  - name: Get path with most syscalls
+    set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value')
+      | last).key }}"
+    when: found_paths | length >= 1
+
+  - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules
+    set_fact: audit_file="/etc/audit/rules.d/privileged.rules"
+    when: found_paths | length == 0
+
+  - name: Declare found syscalls
+    set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
+      | list }}"
+
+  - name: Declare missing syscalls
+    set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
+
+  - name: Replace the audit rule in {{ audit_file }}
+    lineinfile:
+      path: '{{ audit_file }}'
+      regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file]
+        | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F
+        auid>=1000 -F auid!=unset (?:-k |-F key=)\w+)
+      line: \1\2\3{{ missing_syscalls | join("\3") }}\4
+      backrefs: true
+      state: present
+    when: syscalls_found | length > 0 and missing_syscalls | length > 0
+
+  - name: Add the audit rule to {{ audit_file }}
+    lineinfile:
+      path: '{{ audit_file }}'
+      line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x
+        -F auid>=1000 -F auid!=unset -F key=privileged
+      create: true
+      mode: o-rwx
+      state: present
+    when: syscalls_found | length == 0
+
+  - name: Declare list of syscalls
+    set_fact:
+      syscalls: []
+      syscall_grouping: []
+
+  - name: Check existence of  in /etc/audit/audit.rules
+    find:
+      paths: /etc/audit
+      contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F
+        path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$
+      patterns: audit.rules
+    register: find_command
+    loop: '{{ (syscall_grouping + syscalls) | unique }}'
+
+  - name: Set path to /etc/audit/audit.rules
+    set_fact: audit_file="/etc/audit/audit.rules"
+
+  - name: Declare found syscalls
+    set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item')
+      | list }}"
+
+  - name: Declare missing syscalls
+    set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}"
+
+  - name: Replace the audit rule in {{ audit_file }}
+    lineinfile:
+      path: '{{ audit_file }}'
+      regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:(
+        -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset
+        (?:-k |-F key=)\w+)
+      line: \1\2\3{{ missing_syscalls | join("\3") }}\4
+      backrefs: true
+      state: present
+    when: syscalls_found | length > 0 and missing_syscalls | length > 0
+
+  - name: Add the audit rule to {{ audit_file }}
+    lineinfile:
+      path: '{{ audit_file }}'
+      line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x
+        -F auid>=1000 -F auid!=unset -F key=privileged
+      create: true
+      mode: o-rwx
+      state: present
+    when: syscalls_found | length == 0
   when:
   - '"audit" in ansible_facts.packages'
   - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
@@ -41,160 +153,3 @@
   - medium_severity
   - no_reboot_needed
   - restrict_strategy
-
-- name: Search /etc/audit/rules.d for other rules with specified key modules
-  find:
-    paths: /etc/audit/rules.d
-    contains: ^.*(?:-F key=|-k\s+)modules$
-    patterns: '*.rules'
-  register: find_watch_key
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
-    == 0
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy
-
-- name: Use /etc/audit/rules.d/modules.rules as the recipient for the rule
-  set_fact:
-    all_files:
-    - /etc/audit/rules.d/modules.rules
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched
-    is defined and find_existing_watch_rules_d.matched == 0
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy
-
-- name: Use matched file as the recipient for the rule
-  set_fact:
-    all_files:
-    - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}'
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched
-    is defined and find_existing_watch_rules_d.matched == 0
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy
-
-- name: Add watch rule for /usr/bin/kmod in /etc/audit/rules.d/
-  lineinfile:
-    path: '{{ all_files[0] }}'
-    line: -w /usr/bin/kmod -p x -k modules
-    create: true
-    mode: '0640'
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched
-    == 0
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy
-
-- name: Check if watch rule for /usr/bin/kmod already exists in /etc/audit/audit.rules
-  find:
-    paths: /etc/audit/
-    contains: ^\s*-w\s+/usr/bin/kmod\s+-p\s+x(\s|$)+
-    patterns: audit.rules
-  register: find_existing_watch_audit_rules
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy
-
-- name: Add watch rule for /usr/bin/kmod in /etc/audit/audit.rules
-  lineinfile:
-    line: -w /usr/bin/kmod -p x -k modules
-    state: present
-    dest: /etc/audit/audit.rules
-    create: true
-    mode: '0640'
-  when:
-  - '"audit" in ansible_facts.packages'
-  - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
-  - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched
-    == 0
-  tags:
-  - CCE-89455-0
-  - DISA-STIG-RHEL-08-030580
-  - NIST-800-53-AU-12(a)
-  - NIST-800-53-AU-12.1(ii)
-  - NIST-800-53-AU-12.1(iv)AU-12(c)
-  - NIST-800-53-AU-3
-  - NIST-800-53-AU-3.1
-  - NIST-800-53-MA-4(1)(a)
-  - audit_rules_privileged_commands_kmod
-  - low_complexity
-  - low_disruption
-  - medium_severity
-  - no_reboot_needed
-  - restrict_strategy

New content has different text for rule 'xccdf_org.ssgproject.content_rule_audit_immutable_login_uids'.
--- xccdf_org.ssgproject.content_rule_audit_immutable_login_uids
+++ xccdf_org.ssgproject.content_rule_audit_immutable_login_uids
@@ -50,12 +50,6 @@
 [reference]:
 SRG-APP-000495-CTR-001235
 
-[reference]:
-RHEL-08-030122
-
-[reference]:
-SV-230403r627750_rule
-
 [rationale]:
 If modification of login UIDs is not prevented, they can be changed by unprivileged users and
 make auditing complicated or impossible.

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_audit_immutable_login_uids' differs.
--- xccdf_org.ssgproject.content_rule_audit_immutable_login_uids
+++ xccdf_org.ssgproject.content_rule_audit_immutable_login_uids
@@ -9,7 +9,6 @@
   when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
   tags:
   - CCE-82828-5
-  - DISA-STIG-RHEL-08-030122
   - NIST-800-53-AU-2(a)
   - audit_immutable_login_uids
   - low_complexity
@@ -25,7 +24,6 @@
   when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
   tags:
   - CCE-82828-5
-  - DISA-STIG-RHEL-08-030122
   - NIST-800-53-AU-2(a)
   - audit_immutable_login_uids
   - low_complexity

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_dir_perms_world_writable_root_owned' differs.
--- xccdf_org.ssgproject.content_rule_dir_perms_world_writable_root_owned
+++ xccdf_org.ssgproject.content_rule_dir_perms_world_writable_root_owned
@@ -142,6 +142,7 @@
     world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list
       }}'
   loop: '{{ result_found_dirs.results }}'
+  when: item is not skipped
   tags:
   - CCE-83375-6
   - DISA-STIG-RHEL-08-010700

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_dir_perms_world_writable_sticky_bits' differs.
--- xccdf_org.ssgproject.content_rule_dir_perms_world_writable_sticky_bits
+++ xccdf_org.ssgproject.content_rule_dir_perms_world_writable_sticky_bits
@@ -163,6 +163,7 @@
     world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list
       }}'
   loop: '{{ result_found_dirs.results }}'
+  when: result_found_dirs is not skipped and item is not skipped
   tags:
   - CCE-80783-4
   - DISA-STIG-RHEL-08-010190

Copy link

codeclimate bot commented Dec 4, 2023

Code Climate has analyzed commit 355ac5f and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (50% is the threshold).

This pull request will bring the total coverage in the repository to 58.5%.

View more on Code Climate.

Copy link
Member

@Mab879 Mab879 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Thanks for the PR.

@Mab879 Mab879 merged commit f1937a7 into ComplianceAsCode:master Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RHEL7 Red Hat Enterprise Linux 7 product related. RHEL8 Red Hat Enterprise Linux 8 product related. RHEL9 Red Hat Enterprise Linux 9 product related. STIG STIG Benchmark related. Update Profile Issues or pull requests related to Profiles updates. Update Rule Issues or pull requests related to Rules updates.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants