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 Performance on rules probing the whole file system #11319

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c2d2700
Improve OVAL readability in file_permissions_ungroupowned
marcusburghardt Nov 17, 2023
7bf0f75
Refactor OVAL in file_permissions_ungroupowned
marcusburghardt Nov 17, 2023
634f830
Introduce OVAL macro to map local mount points
marcusburghardt Nov 23, 2023
f8f4dd1
Adopt new macro in file_permissions_ungroupowned
marcusburghardt Nov 23, 2023
d9043e9
Update file_permissions_ungroupowned description
marcusburghardt Nov 17, 2023
8730760
Include warning in file_permissions_ungroupowned
marcusburghardt Nov 23, 2023
b29b04a
Update file_permissions_unauthorized_suid description
marcusburghardt Nov 23, 2023
34fb66d
Improve OVAL readability in file_permissions_unauthorized_suid
marcusburghardt Nov 23, 2023
5089cb0
Refactor OVAL check to not collect same objects twice
marcusburghardt Nov 29, 2023
3963ecf
Adopt new macro in file_permissions_unauthorized_suid
marcusburghardt Nov 29, 2023
ec64b7a
Improve rule description in file_permissions_unauthorized_sgid
marcusburghardt Nov 30, 2023
b2589cf
Refactor OVAL in file_permissions_unauthorized_sgid
marcusburghardt Nov 30, 2023
c862b13
Improve rule description in file_permissions_unauthorized_world_writable
marcusburghardt Nov 30, 2023
d8bbe7f
Refactor OVAL in file_permissions_unauthorized_world_writable
marcusburghardt Nov 30, 2023
509f324
Improve Bash in file_permissions_unauthorized_world_writable
marcusburghardt Nov 30, 2023
7d0a19d
Improve rule description in dir_perms_world_writable_system_owned
marcusburghardt Nov 30, 2023
e8894c8
Refactor OVAL in dir_perms_world_writable_system_owned
marcusburghardt Nov 30, 2023
0f5832c
Improve rule description in dir_perms_world_writable_sticky_bits
marcusburghardt Nov 30, 2023
ac35fb2
Refactor OVAL in dir_perms_world_writable_sticky_bits
marcusburghardt Nov 30, 2023
e1a106b
Fix test scenario comment in alignment to the commands
marcusburghardt Nov 30, 2023
57c541e
Improve rule description in no_files_unowned_by_user
marcusburghardt Nov 30, 2023
1269df0
Refactor OVAL in no_files_unowned_by_user
marcusburghardt Nov 30, 2023
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
@@ -1,22 +1,39 @@
<def-group>
<definition class="compliance" id="dir_perms_world_writable_sticky_bits" version="1">
<definition class="compliance" id="{{{ rule_id }}}" version="2">
{{{ oval_metadata("The sticky bit should be set for all world-writable directories.") }}}
<criteria>
<criterion comment="all local world writable directories have sticky bit set" test_ref="test_dir_perms_world_writable_sticky_bits" negate="true" />
<criterion test_ref="test_dir_perms_world_writable_sticky_bits"
comment="All local world-writable directories have sticky bit set"/>
</criteria>
</definition>
<unix:file_test check="all" check_existence="all_exist" comment="all local world-writable directories have sticky bit set" id="test_dir_perms_world_writable_sticky_bits" version="1">
<unix:object object_ref="object_only_local_directories" />
<unix:state state_ref="state_world_writable_and_not_sticky" />
</unix:file_test>
<unix:file_object comment="only local directories" id="object_only_local_directories" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1" recurse_file_system="local" />
<unix:path operation="equals">/</unix:path>
<unix:filename xsi:nil="true" />
<filter action="include">state_world_writable_and_not_sticky</filter>
</unix:file_object>
<unix:file_state id="state_world_writable_and_not_sticky" version="1">

<unix:file_state id="state_dir_perms_world_writable_sticky_bits" version="1">
<unix:sticky datatype="boolean">false</unix:sticky>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>

{{%- set var_local_mount_points = "var_" ~ rule_id ~ "_local_mountpoints" -%}}
{{{ create_local_mount_points_list(var_local_mount_points) }}}

<!--
This file_object will only find files located in local and not special file systems. 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 probe will ignore
any child directory which is a mount point for any other partition. This will ensure
considerable performance improvement. -->
<unix:file_object id="object_dir_perms_world_writable_sticky_bits" version="1"
comment="All world-writable directories without sticky bits">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
recurse_file_system="defined"/>
<unix:path operation="equals" var_check="at least one"
var_ref="{{{ var_local_mount_points }}}"/>
<unix:filename xsi:nil="true"/>
<filter action="include">state_dir_perms_world_writable_sticky_bits</filter>
</unix:file_object>

<unix:file_test id="test_dir_perms_world_writable_sticky_bits" version="2"
check="all" check_existence="none_exist"
comment="Check the existence of world-writable directories without sticky bits">
<unix:object object_ref="object_dir_perms_world_writable_sticky_bits"/>
</unix:file_test>
</def-group>
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,25 @@ documentation_complete: true
title: 'Verify that All World-Writable Directories Have Sticky Bits Set'

description: |-
When the so-called 'sticky bit' is set on a directory,
only the owner of a given file may remove that file from the
directory. Without the sticky bit, any user with write access to a
directory may remove any file in the directory. Setting the sticky
bit prevents users from removing each other's files. In cases where
there is no reason for a directory to be world-writable, a better
solution is to remove that permission rather than to set the sticky
bit. However, if a directory is used by a particular application,
consult that application's documentation instead of blindly
changing modes.
When the so-called 'sticky bit' is set on a directory, only the owner of a given file may
remove that file from the directory. Without the sticky bit, any user with write access to a
directory may remove any file in the directory. Setting the sticky bit prevents users from
removing each other's files. In cases where there is no reason for a directory to be
world-writable, a better solution is to remove that permission rather than to set the sticky
bit. However, if a directory is used by a particular application, consult that application's
documentation instead of blindly changing modes.
<br />
To set the sticky bit on a world-writable directory <i>DIR</i>, run the
following command:
To set the sticky bit on a world-writable directory <i>DIR</i>, run the following command:
<pre>$ sudo chmod +t <i>DIR</i></pre>

rationale: |-
Failing to set the sticky bit on public directories allows unauthorized
users to delete files in the directory structure.
Failing to set the sticky bit on public directories allows unauthorized users to delete files
in the directory structure.
<br /><br />
The only authorized public directories are those temporary directories
supplied with the system, or those designed to be temporary file
repositories. The setting is normally reserved for directories used by the
system, by users for temporary file storage (such as <tt>/tmp</tt>), and
for directories requiring global read/write access.
The only authorized public directories are those temporary directories supplied with the
system, or those designed to be temporary file repositories. The setting is normally reserved
for directories used by the system, by users for temporary file storage (such as <tt>/tmp</tt>),
and for directories requiring global read/write access.

severity: medium

Expand Down Expand Up @@ -102,3 +97,10 @@ fixtext: |-

srg_requirement:
A sticky bit must be set on all {{{ full_name }}} public directories to prevent unauthorized and unintended information transferred via shared system resources.

warnings:
- general: |-
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of directories present on the system. It is
not a problem in most cases, but especially systems with a large number of directories can
be affected. See <code>https://access.redhat.com/articles/6999111</code>.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ df --local -P | awk '{if (NR!=1) print $6}' \
mkdir -p /test_dir_1
chmod 1770 /test_dir_1

# Create a new dir that is word-writable but doesn't have sticky bit
# Create a new dir that is word-readable and doesn't have sticky bit
mkdir -p /test_dir_2
chmod 0774 /test_dir_2
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
<def-group>
<definition class="compliance" id="dir_perms_world_writable_system_owned" version="1">
{{{ oval_metadata("All world writable directories should be owned by a system user.") }}}
<criteria comment="check for local directories that are world writable and have uid greater than or equal to {{{ auid }}}" negate="true">
<criterion comment="check for local directories that are world writable and have uid greater than or equal to {{{ auid }}}" test_ref="test_dir_world_writable_uid_gt_value" />
<definition class="compliance" id="{{{ rule_id }}}" version="2">
{{{ oval_metadata("All world writable directories should be owned by a system account.") }}}
<criteria>
<criterion test_ref="test_dir_perms_world_writable_system_owned"
comment="Check world-writable directories with uid greater than or equal to {{{ uid_min }}}"/>
</criteria>
</definition>
<unix:file_test check="all" comment="check for local directories that are world writable and have uid greater than or equal to {{{ auid }}}" id="test_dir_world_writable_uid_gt_value" version="1">
<unix:object object_ref="all_local_directories_uid" />
<unix:state state_ref="state_uid_is_user_and_world_writable" />
</unix:file_test>
<unix:file_object comment="all local directories" id="all_local_directories_uid" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1" recurse_file_system="local" />
<unix:path operation="equals">/</unix:path>
<unix:filename xsi:nil="true" />
<filter action="include">state_uid_is_user_and_world_writable</filter>
</unix:file_object>
<unix:file_state comment="uid greater than or equal to {{{ auid }}} and world writable" id="state_uid_is_user_and_world_writable" version="1">
<unix:user_id datatype="int" operation="greater than or equal">{{{ auid }}}</unix:user_id>

<unix:file_state id="state_dir_perms_world_writable_system_owned" version="1"
comment="uid greater than or equal to {{{ uid_min }}} and world writable">
<unix:user_id datatype="int" operation="greater than or equal">{{{ uid_min }}}</unix:user_id>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>

{{%- set var_local_mount_points = "var_" ~ rule_id ~ "_local_mountpoints" -%}}
{{{ create_local_mount_points_list(var_local_mount_points) }}}

<!--
This file_object will only find files located in local and not special file systems. 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 probe will ignore
any child directory which is a mount point for any other partition. This will ensure
considerable performance improvement. -->
<unix:file_object id="object_dir_perms_world_writable_system_owned" version="1"
comment="All world-writable directories.">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
recurse_file_system="defined"/>
<unix:path operation="equals" var_check="at least one"
var_ref="{{{ var_local_mount_points }}}"/>
<unix:filename xsi:nil="true"/>
<filter action="include">state_dir_perms_world_writable_system_owned</filter>
</unix:file_object>

<unix:file_test id="test_dir_perms_world_writable_system_owned" version="2"
check="all" check_existence="none_exist"
comment="Check the existence of world-writable directories not owned by system accounts.">
<unix:object object_ref="object_dir_perms_world_writable_system_owned"/>
</unix:file_test>
</def-group>
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@ prodtype: fedora,ol7,ol8,rhel7,rhel8,rhv4
title: 'Ensure All World-Writable Directories Are Owned by a System Account'

description: |-
All directories in local partitions which are
world-writable should be owned by root or another
system account. If any world-writable directories are not
owned by a system account, this should be investigated.
Following this, the files should be deleted or assigned to an
All directories in local partitions which are world-writable should be owned by root or
another system account. If any world-writable directories are not owned by a system account,
this should be investigated. Following this, the files should be deleted or assigned to an
appropriate owner.

rationale: |-
Allowing a user account to own a world-writable directory is
undesirable because it allows the owner of that directory to remove
or replace any files that may be placed in the directory by other
users.
Allowing a user account to own a world-writable directory is undesirable because it allows the
owner of that directory to remove or replace any files that may be placed in the directory by
other users.

severity: medium

Expand All @@ -40,7 +37,14 @@ references:
ocil_clause: 'there is output'

ocil: |-
The following command will discover and print world-writable directories that
are not owned by a system account, given the assumption that only system
accounts have a uid lower than 500. Run it once for each local partition <i>PART</i>:
<pre>$ sudo find <i>PART</i> -xdev -type d -perm -0002 -uid +499 -print</pre>
The following command will discover and print world-writable directories that are not owned by
a system account, given the assumption that only system accounts have a uid lower than 500.
Run it once for each local partition <i>PART</i>:
<pre>$ sudo find <i>PART</i> -xdev -type d -perm -0002 -uid +{{{ uid_min }}} -print</pre>

warnings:
- general: |-
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of directories present on the system. It is
not a problem in most cases, but especially systems with a large number of directories can
be affected. See <code>https://access.redhat.com/articles/6999111</code>.
Original file line number Diff line number Diff line change
@@ -1,53 +1,77 @@
<def-group>
<definition id="file_permissions_unauthorized_sgid" version="1" class="compliance">
<definition class="compliance" id="{{{ rule_id }}}" version="1">
{{{ oval_metadata("Evaluates to true if all files with SGID set are owned by RPM packages.") }}}
<criteria>
<criterion comment="Check all sgid files" test_ref="test_file_permissions_unauthorized_sgid"/>
<criterion test_ref="test_file_permissions_unauthorized_sgid"
comment="Check if all sgid files present in the system are authorized"/>
</criteria>
</definition>

<unix:file_test check="all" check_existence="none_exist" comment="sgid files outside system RPMs" id="test_file_permissions_unauthorized_sgid" version="1">
<unix:object object_ref="obj_file_permissions_unauthorized_sgid_unowned" />
</unix:file_test>
<!-- Collect all sgid files in the system. -->
<unix:file_state id="state_file_permissions_unauthorized_sgid_set" version="1">
<unix:sgid datatype="boolean">true</unix:sgid>
</unix:file_state>

<unix:file_object comment="files with sgid set which are not owned by any RPM package" id="obj_file_permissions_unauthorized_sgid_unowned" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1" recurse_file_system="local" />
<unix:path operation="equals">/</unix:path>
{{%- set var_local_mount_points = "var_" ~ rule_id ~ "_local_mountpoints" -%}}
{{{ create_local_mount_points_list(var_local_mount_points) }}}

<!-- This file_object will only find files located in local and not special file systems. 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 probe will ignore
any child directory which is a mount point for any other partition. This will ensure
considerable performance improvement. -->
<unix:file_object id="object_file_permissions_unauthorized_sgid_all_sgid_files" version="1"
comment="all files with sgid set">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
recurse_file_system="defined"/>
<unix:path operation="equals" var_check="at least one"
var_ref="{{{ var_local_mount_points }}}"/>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">state_file_permissions_unauthorized_sgid_sgid_set</filter>
<filter action="exclude">state_file_permissions_unauthorized_sgid_filepaths</filter>
<filter action="include">state_file_permissions_unauthorized_sgid_set</filter>
</unix:file_object>

<linux:rpmverifyfile_object id="obj_file_permissions_unauthorized_sgid_rpms" version="1" comment="all files with sgid set that come from a RPM package">
<linux:behaviors nolinkto="true" nomd5="true" nosize="true" nouser="true" nogroup="true" nomtime="true" nomode="true" nordev="true" />
<local_variable id="var_file_permissions_unauthorized_sgid_all_sgid_files" version="1"
datatype="string" comment="all files with sgid set">
<object_component item_field="filepath"
object_ref="object_file_permissions_unauthorized_sgid_all_sgid_files"/>
</local_variable>

<!-- Locate all rpm packages including located system sgid files. -->
<linux:rpmverifyfile_object id="object_file_permissions_unauthorized_sgid_rpms" version="1"
comment="all files with sgid set that come from a RPM package">
<linux:behaviors nolinkto="true" nomd5="true" nosize="true" nouser="true" nogroup="true"
nomtime="true" nomode="true" nordev="true"/>
<linux:name operation="pattern match">.*</linux:name>
<linux:epoch operation="pattern match">.*</linux:epoch>
<linux:version operation="pattern match">.*</linux:version>
<linux:release operation="pattern match">.*</linux:release>
<linux:arch operation="pattern match">.*</linux:arch>
<linux:filepath var_ref="var_file_permissions_unauthorized_sgid_all" operation="equals" var_check="all" />
<linux:filepath operation="equals" var_check="all"
var_ref="var_file_permissions_unauthorized_sgid_all_sgid_files"/>
</linux:rpmverifyfile_object>

<unix:file_object comment="all files with sgid set" id="obj_file_permissions_unauthorized_sgid_files" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1" recurse_file_system="local" />
<unix:path operation="equals">/</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">state_file_permissions_unauthorized_sgid_sgid_set</filter>
</unix:file_object>

<unix:file_state id="state_file_permissions_unauthorized_sgid_sgid_set" version="1">
<unix:sgid datatype="boolean">true</unix:sgid>
</unix:file_state>
<!-- Extract the filepaths of rpm packages containing system sgid files. -->
<local_variable id="var_file_permissions_unauthorized_sgid_rpms" version="1"
datatype="string" comment="all files with sgid set that are managed by a RPM package">
<object_component item_field="filepath"
object_ref="object_file_permissions_unauthorized_sgid_rpms"/>
</local_variable>

<unix:file_state id="state_file_permissions_unauthorized_sgid_filepaths" version="1">
<unix:filepath var_ref="var_file_permissions_unauthorized_sgid_rpms" var_check="at least one" />
</unix:file_state>
<!-- Convert the local variable to a variable state which will be used below as a filter. -->
<ind:variable_state id="state_file_permissions_unauthorized_sgid_rpm_filepaths" version="1">
<ind:value datatype="string" operation="equals" var_check="at least one"
var_ref="var_file_permissions_unauthorized_sgid_rpms"/>
</ind:variable_state>

<local_variable id="var_file_permissions_unauthorized_sgid_rpms" datatype="string" version="1" comment="all files with sgid set that come from a RPM package">
<object_component item_field="filepath" object_ref="obj_file_permissions_unauthorized_sgid_rpms" />
</local_variable>
<!-- Variable object containing only system sgid files not include in rpm packages. -->
<ind:variable_object id="object_file_permissions_unauthorized_sgid_no_rpm_files" version="1">
<ind:var_ref>var_file_permissions_unauthorized_sgid_all_sgid_files</ind:var_ref>
<filter action="exclude">state_file_permissions_unauthorized_sgid_rpm_filepaths</filter>
</ind:variable_object>

<local_variable id="var_file_permissions_unauthorized_sgid_all" datatype="string" version="1" comment="all files with sgid set">
<object_component item_field="filepath" object_ref="obj_file_permissions_unauthorized_sgid_files" />
</local_variable>
<ind:variable_test id="test_file_permissions_unauthorized_sgid" version="1"
check="all" check_existence="none_exist"
comment="Check the existence of sgid files not included in rpm packages.">
<ind:object object_ref="object_file_permissions_unauthorized_sgid_no_rpm_files"/>
</ind:variable_test>
</def-group>
Loading
Loading