Skip to content

Fix aarch64 audit rules for unsupported syscalls#14757

Merged
vojtapolasek merged 2 commits into
ComplianceAsCode:masterfrom
macko1:fix_14196-14372-audit-rules-aarch64
Jun 11, 2026
Merged

Fix aarch64 audit rules for unsupported syscalls#14757
vojtapolasek merged 2 commits into
ComplianceAsCode:masterfrom
macko1:fix_14196-14372-audit-rules-aarch64

Conversation

@macko1

@macko1 macko1 commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Description:

Fix audit_rules_file_deletion_events and audit_rules_unsuccessful_file_modification
for aarch64.

Some syscalls do not exist on aarch64 for 64-bit programs. 32-bit programs (via the
compatibility layer) still have them.

Missing syscalls and their replacements:

  • rmdir, unlink, rename -> unlinkat, renameat, renameat2
  • creat, open -> openat

Both rules had two problems on aarch64:

  • The bash remediation wrote audit rules for nonexistent syscalls. auditctl rejects
    unknown syscalls with "Syscall name unknown" and stops loading all subsequent rules,
    causing audit-rules.service to fail.
  • The OVAL check expected all syscalls to be present in the audit config, including the
    ones that don't exist on aarch64. A correctly configured aarch64 system would fail the
    scan.

Changes:

Bash remediations (bash/shared.sh):

  • Detect aarch64 at runtime via uname -m
  • On aarch64 b64: write only supported syscalls to the audit config
  • On b32 and non-aarch64: write all syscalls as before

OVAL checks (oval/shared.xml):

  • Detect aarch64 at scan time
  • On aarch64: expect only supported syscalls in the audit config
  • On other architectures: expect all syscalls

audit_rules_unsuccessful_file_modification/rule.yml:

  • Remove platform: not aarch64_arch; the rule was completely excluded from aarch64
    because the OVAL and remediation didn't handle it. Now that they do, the exclusion is no
    longer needed.

Rationale:

Per-syscall rules (e.g. audit_rules_file_deletion_events_rename) already handle aarch64
via platform: not aarch64_arch.

audit_rules_file_deletion_events and audit_rules_unsuccessful_file_modification bundle
all syscalls into one rule and had no aarch64 handling:

Review hints:

  1. Build:
./build_product rhel9 --datastream
  1. Run Automatus on an aarch64 VM:
python3 automatus.py rule \
    --libvirt qemu:///session rhel9-aarch64 \
    --datastream build/ssg-rhel9-ds.xml \
    audit_rules_file_deletion_events \
    audit_rules_unsuccessful_file_modification
  1. Manual check -- SSH into the aarch64 VM and verify:
  • auditd loads the rules without errors
  • auditctl -l shows only supported syscalls for b64 rules
auditctl -R /etc/audit/rules.d/*.rules
auditctl -l

Note: I recommend using an aarch64 VM for this, or testing natively on aarch64.

@macko1 macko1 force-pushed the fix_14196-14372-audit-rules-aarch64 branch from 37bac4e to 06e5155 Compare June 3, 2026 09:26
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

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

Click here to see the full diff
New content has different text for rule 'xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events'.
--- xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events
+++ xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events
@@ -16,6 +16,10 @@
 system, or having two lines for both b32 and b64 in case your system is 64-bit:
 -a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat2 -S renameat -F auid>=1000 -F auid!=unset -F key=delete
 
+If the system is aarch64, the 64-bit syscall table does not include
+rmdir, unlink, and rename syscalls. They are replaced by
+unlinkat, renameat, and renameat2, respectively.
+
 [warning]:
 This rule checks for multiple syscalls related to file deletion;
 it was written with DISA STIG in mind. Other policies should use a

OVAL for rule 'xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events' differs.
--- oval:ssg-audit_rules_file_deletion_events:def:1
+++ oval:ssg-audit_rules_file_deletion_events:def:1
@@ -1,4 +1,11 @@
+criteria OR
 criteria AND
+extend_definition oval:ssg-system_info_architecture_aarch_64:def:1
+extend_definition oval:ssg-audit_rules_file_deletion_events_unlinkat:def:1
+extend_definition oval:ssg-audit_rules_file_deletion_events_renameat:def:1
+extend_definition oval:ssg-audit_rules_file_deletion_events_renameat2:def:1
+criteria AND
+extend_definition oval:ssg-system_info_architecture_aarch_64:def:1
 extend_definition oval:ssg-audit_rules_file_deletion_events_rmdir:def:1
 extend_definition oval:ssg-audit_rules_file_deletion_events_unlink:def:1
 extend_definition oval:ssg-audit_rules_file_deletion_events_unlinkat:def:1

bash remediation for rule 'xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events' differs.
--- xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events
+++ xccdf_org.ssgproject.content_rule_audit_rules_file_deletion_events
@@ -1,8 +1,22 @@
 # Remediation is applicable only in certain platforms
 if rpm --quiet -q audit && rpm --quiet -q kernel-core; then
 
-# Perform the remediation for the syscall rule
-# Retrieve hardware architecture of the underlying system
+# Remediation: write audit rules that log all file deletion events
+# ('rmdir', 'unlink', 'unlinkat', 'rename', 'renameat', 'renameat2'),
+# successful or not. Example output:
+#   -a always,exit -F arch=b64 -S unlinkat -F auid>=1000 -F auid!=unset -k delete
+#
+# On aarch64, 'rmdir', 'unlink', and 'rename' do not exist in the b64
+# syscall table and are skipped. The b32 table (for 32-bit programs)
+# still has them.
+#
+# Writes to both '/etc/audit/rules.d/*.rules' (for 'augenrules') and
+# '/etc/audit/audit.rules' (for 'auditctl') so the remediation works
+# regardless of which tool the system uses to load audit rules.
+
+# Audit rules filter by program type: 32-bit programs use a different
+# syscall table than 64-bit programs. On 64-bit systems with a 32-bit
+# compatibility layer, both can run, so rules are written for each.
 [ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")
 
 for ARCH in "${RULE_ARCHS[@]}"
@@ -10,10 +24,21 @@
 	ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
 	OTHER_FILTERS=""
 	AUID_FILTERS="-F auid>=1000 -F auid!=unset"
-	SYSCALL="rmdir unlink unlinkat rename renameat renameat2"
 	KEY="delete"
-	SYSCALL_GROUPING="rmdir unlink unlinkat rename renameat renameat2"
+
+	# aarch64 b64 syscall table does not have rmdir, unlink, rename;
+	# the b32 table (for 32-bit programs, aarch64 can run 32-bit code) still has them
+	if [ "$(uname -m)" = "aarch64" ] && [ "$ARCH" = "b64" ]; then
+		SYSCALL="unlinkat renameat renameat2"
+	else
+		SYSCALL="rmdir unlink unlinkat rename renameat renameat2"
+	fi
+	# SYSCALL_GROUPING tells the macro which syscalls belong together
+	# so it merges them into existing rules instead of creating duplicates
+	SYSCALL_GROUPING="$SYSCALL"
+
 	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
+
 	unset syscall_a
 unset syscall_grouping
 unset syscall_string

New content has different text for rule 'xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification'.
--- xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
+++ xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
@@ -24,6 +24,9 @@
 -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
 -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
 
+If the system is aarch64, the 64-bit syscall table does not include
+creat and open syscalls. They are replaced by openat.
+
 [warning]:
 This rule checks for multiple syscalls related to unsuccessful file modification;
 it was written with DISA STIG in mind. Other policies should use a

OVAL for rule 'xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification' differs.
--- oval:ssg-audit_rules_unsuccessful_file_modification:def:1
+++ oval:ssg-audit_rules_unsuccessful_file_modification:def:1
@@ -1,4 +1,12 @@
+criteria OR
 criteria AND
+extend_definition oval:ssg-system_info_architecture_aarch_64:def:1
+extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_ftruncate:def:1
+extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_openat:def:1
+extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at:def:1
+extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_truncate:def:1
+criteria AND
+extend_definition oval:ssg-system_info_architecture_aarch_64:def:1
 extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_creat:def:1
 extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_ftruncate:def:1
 extend_definition oval:ssg-audit_rules_unsuccessful_file_modification_openat:def:1

bash remediation for rule 'xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification' differs.
--- xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
+++ xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
@@ -1,21 +1,50 @@
 # Remediation is applicable only in certain platforms
-if rpm --quiet -q audit && rpm --quiet -q kernel-core && { ( ! ( ( grep -sqE "^.*\.aarch64$" /proc/sys/kernel/osrelease || grep -sqE "^aarch64$" /proc/sys/kernel/arch; ) ) ); }; then
-
-# Perform the remediation of the syscall rule
-# Retrieve hardware architecture of the underlying system
+if rpm --quiet -q audit && rpm --quiet -q kernel-core; then
+
+# Remediation: write audit rules that log only failed file 'open', 'create',
+# and 'truncate' attempts -- not successful ones.
+# "Failed" means the syscall returned EACCES (permission denied) or
+# EPERM (operation not permitted).
+#
+# For each architecture (b32, b64) and each syscall, two audit rules are
+# written -- one for EACCES and one for EPERM -- because auditd cannot
+# match multiple exit codes in a single rule. Example output:
+#   -a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access
+#   -a always,exit -F arch=b64 -S openat -F exit=-EPERM  -F auid>=1000 -F auid!=unset -k access
+#
+# On aarch64, 'creat' and 'open' do not exist in the b64 syscall table
+# and are skipped. The b32 table (for 32-bit programs) still has them.
+#
+# Writes to both '/etc/audit/rules.d/*.rules' (for 'augenrules') and
+# '/etc/audit/audit.rules' (for 'auditctl') so the remediation works
+# regardless of which tool the system uses to load audit rules.
+
+# Audit rules filter by program type: 32-bit programs use a different
+# syscall table than 64-bit programs. On 64-bit systems with a 32-bit
+# compatibility layer, both can run, so rules are written for each.
 [ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")
 
 for ARCH in "${RULE_ARCHS[@]}"
 do
-
-	# First fix the -EACCES requirement
 	ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
+	AUID_FILTERS="-F auid>=1000 -F auid!=unset"
+	KEY="access"
+
+	# aarch64 b64 syscall table does not have creat or open;
+	# the b32 table (for 32-bit programs, aarch64 can run 32-bit code) still has them
+	if [ "$(uname -m)" = "aarch64" ] && [ "$ARCH" = "b64" ]; then
+		SYSCALL="openat open_by_handle_at truncate ftruncate"
+	else
+		SYSCALL="creat open openat open_by_handle_at truncate ftruncate"
+	fi
+	# SYSCALL_GROUPING tells the macro which syscalls belong together
+	# so it merges them into existing rules instead of creating duplicates
+	SYSCALL_GROUPING="$SYSCALL"
+
+	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
+
+	# First pass: EACCES (permission denied by file mode bits)
 	OTHER_FILTERS="-F exit=-EACCES"
-	AUID_FILTERS="-F auid>=1000 -F auid!=unset"
-	SYSCALL="creat open openat open_by_handle_at truncate ftruncate"
-	KEY="access"
-	SYSCALL_GROUPING="creat open openat open_by_handle_at truncate ftruncate"
-	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
 	unset syscall_a
 unset syscall_grouping
 unset syscall_string
@@ -322,15 +351,8 @@
     fi
 fi
 
-	# Then fix the -EPERM requirement
-	# No need to change content of $GROUP variable - it's the same as for -EACCES case above
-	ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH"
+	# Second pass: EPERM (operation needs a privilege the process lacks)
 	OTHER_FILTERS="-F exit=-EPERM"
-	AUID_FILTERS="-F auid>=1000 -F auid!=unset"
-	SYSCALL="creat open openat open_by_handle_at truncate ftruncate"
-	KEY="access"
-	SYSCALL_GROUPING="creat open openat open_by_handle_at truncate ftruncate"
-	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
 	unset syscall_a
 unset syscall_grouping
 unset syscall_string
@@ -636,7 +658,6 @@
         sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit"
     fi
 fi
-
 done
 
 else

Platform has been changed for rule 'xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification'
--- xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
+++ xccdf_org.ssgproject.content_rule_audit_rules_unsuccessful_file_modification
@@ -1 +1 @@
-oval:ssg-proc_sys_kernel_osrelease_arch_aarch64:def:1
+

@macko1 macko1 force-pushed the fix_14196-14372-audit-rules-aarch64 branch 4 times, most recently from fa595fd to 99aabd2 Compare June 9, 2026 11:44
@macko1 macko1 force-pushed the fix_14196-14372-audit-rules-aarch64 branch 4 times, most recently from dda0ba1 to 0602c82 Compare June 9, 2026 18:53
Fix audit_rules_file_deletion_events and
audit_rules_unsuccessful_file_modification for aarch64.

The aarch64 b64 syscall table does not have some legacy
syscalls. The b32 table (for 32-bit programs) still has
all of them. Both rules wrote audit rules for these
nonexistent syscalls. auditctl rejects unknown syscalls
with "Syscall name unknown" and stops loading all
subsequent rules, causing audit-rules.service to fail.

Missing syscalls and their replacements:
- rmdir, unlink, rename -> unlinkat, renameat, renameat2
- creat, open -> openat

Changes:

Bash remediations:
- Detect aarch64 at runtime via uname -m
- On aarch64 b64: write only supported syscalls
- On b32 and non-aarch64: write all syscalls

OVAL checks:
- Detect aarch64 at scan time
- On aarch64: expect only supported syscalls
- On other architectures: expect all syscalls

rule.yml:
- Remove the aarch64 platform exclusion from
  audit_rules_unsuccessful_file_modification; the rule
  was excluded because it checked for nonexistent
  syscalls on aarch64, which is now fixed

Resolves: ComplianceAsCode#14196
Resolves: ComplianceAsCode#14372
@macko1 macko1 force-pushed the fix_14196-14372-audit-rules-aarch64 branch from 0602c82 to b9d9b93 Compare June 9, 2026 19:34
@macko1 macko1 changed the title DRAFT: Fix aarch64 audit rules for unsupported syscalls Fix aarch64 audit rules for unsupported syscalls Jun 9, 2026
@vojtapolasek vojtapolasek self-assigned this Jun 10, 2026

@vojtapolasek vojtapolasek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good, nice documentation. Do you think you could add explanation of that difference in syscalls into the rule description in rule.yml? Thanks.

Document which syscalls do not exist in the aarch64
64-bit syscall table and what replaces them in
audit_rules_file_deletion_events and
audit_rules_unsuccessful_file_modification rule
descriptions and bash remediation headers.

Missing syscalls and their replacements:
- rmdir, unlink, rename -> unlinkat, renameat, renameat2
- creat, open -> openat
@macko1

macko1 commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

@vojtapolasek Thanks for the review, I've updated the docs. PTAL

@vojtapolasek vojtapolasek left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good now. Thank you.

@vojtapolasek

Copy link
Copy Markdown
Collaborator

/retest

@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

@macko1: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/4.20-images a52d6bf link true /test 4.20-images
ci/prow/4.19-images a52d6bf link true /test 4.19-images
ci/prow/4.21-images a52d6bf link true /test 4.21-images
ci/prow/e2e-aws-openshift-node-compliance a52d6bf link true /test e2e-aws-openshift-node-compliance
ci/prow/e2e-aws-openshift-platform-compliance a52d6bf link true /test e2e-aws-openshift-platform-compliance

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@vojtapolasek vojtapolasek merged commit 6d10f70 into ComplianceAsCode:master Jun 11, 2026
59 of 68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Do not expect auditd rules for obsolete syscalls on arm64/aarch64 architecture audit-rules service fails due to unsupported rule group on aarch64

2 participants