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

Add test to check if files can be accessed while FIM has them opened #705

Merged
merged 35 commits into from
Jan 27, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d6fe5fb
Add test to check if files can be accessed while FIM has them opened
jesusjimsa May 11, 2020
4573a51
Write to the file in chunks to avoid MemoryError
jesusjimsa May 12, 2020
09735ff
Update path of test
CamiRomero Oct 20, 2021
fd0d423
Add wait_for_initial_scan fixture
CamiRomero Oct 20, 2021
1f559cc
Add restart_syscheck fixture
CamiRomero Oct 20, 2021
d19040b
fix Copyright
CamiRomero Oct 20, 2021
c678fdf
Add descriptive name
CamiRomero Oct 20, 2021
d9cdee7
modify fixture in order to delete the file
CamiRomero Oct 20, 2021
c806811
Style simple squotes
CamiRomero Oct 20, 2021
3bf4974
remove space
CamiRomero Oct 22, 2021
6eaf225
Changed restart_syscheckd_function
CamiRomero Oct 22, 2021
b8fa517
Added new fixture
CamiRomero Oct 25, 2021
a6e50d1
Changed directory_str
CamiRomero Oct 27, 2021
3e1adda
Added delete_path_recursively
CamiRomero Oct 27, 2021
6699773
changed docstring
CamiRomero Oct 27, 2021
e227d07
Added file_path variable
CamiRomero Oct 27, 2021
900393d
Add single quotes
CamiRomero Oct 27, 2021
82c464e
added blank line
CamiRomero Oct 27, 2021
353682c
Changed pycodestyle
CamiRomero Oct 27, 2021
973c687
Merge remote-tracking branch 'origin/2040-4.3-full-green' into 697-ac…
Deblintrake09 Nov 25, 2021
4a7322d
updated test and added docu schema 2.0
Deblintrake09 Nov 29, 2021
5ce43e9
updated Docu
Deblintrake09 Nov 29, 2021
d043a9e
Updated docu references and system
Deblintrake09 Nov 29, 2021
612e75b
fix pr suggestions
Deblintrake09 Nov 30, 2021
40735e2
separated test in two diferent - modify - delete
Deblintrake09 Nov 30, 2021
b510e4a
Merge branch '697-access-while-open' of https://www.github.com/wazuh/…
Deblintrake09 Nov 30, 2021
5633550
Updated wazuh_min_version
Deblintrake09 Dec 1, 2021
67d6f8c
fixed formatting and removed unused confs
Deblintrake09 Dec 1, 2021
b8dd033
Limited test to only scheduled
Deblintrake09 Dec 3, 2021
3ace334
fix code typos with code suggestions from review
Deblintrake09 Dec 3, 2021
5f87994
fix code format
Deblintrake09 Dec 3, 2021
672bffb
modified hardcoded variables and refacored some functions
Deblintrake09 Dec 3, 2021
ccf111c
fix imports
Deblintrake09 Dec 3, 2021
ddaeafb
Merge branch 'master' into 697-access-while-open
Deblintrake09 Dec 6, 2021
e00cd1b
Merge branch 'master' into 697-access-while-open
CamiRomero Jan 27, 2022
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
46 changes: 46 additions & 0 deletions deps/wazuh_testing/wazuh_testing/fim.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,31 @@ def callback_detect_end_scan(line):
logger.warning(f"Couldn't load a log line into json object. Reason {e}")


def callback_detect_scan_start(line):
msg = r'.*Sending FIM event: (.+)$'
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
match = re.match(msg, line)
if not match:
return None

try:
if json.loads(match.group(1))['type'] == 'scan_start':
return True
except (JSONDecodeError, AttributeError, KeyError) as e:
logger.warning(f"Couldn't load a log line into json object. Reason {e}")


def callback_get_scan_timestap(line):
msg = r'.*Sending FIM event: (.+)$'
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
match = re.match(msg, line)
if not match:
return None
try:
if json.loads(match.group(1))['type'] == 'scan_end':
return json.loads(match.group(1))['data']['timestamp']
except (JSONDecodeError, AttributeError, KeyError) as e:
logger.warning(f"Couldn't load a log line into json object. Reason {e}")


def callback_detect_event(line):
msg = r'.*Sending FIM event: (.+)$'
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
match = re.match(msg, line)
Expand Down Expand Up @@ -2259,6 +2284,16 @@ def detect_initial_scan(file_monitor):
error_message='Did not receive expected "File integrity monitoring scan ended" event')


def detect_initial_scan_start(file_monitor):
"""Detect initial scan start when restarting Wazuh.

Args:
file_monitor (FileMonitor): file log monitor to detect events
"""
file_monitor.start(timeout=60, callback=callback_detect_scan_start,
error_message='Did not receive expected "File integrity monitoring scan started" event')


def detect_realtime_start(file_monitor):
"""Detect realtime engine start when restarting Wazuh.

Expand All @@ -2280,6 +2315,17 @@ def detect_whodata_start(file_monitor):
'"File integrity monitoring real-time Whodata engine started" event')


def get_scan_timestamp(file_monitor):
"""Get the timestamp for the for the end of a scan

Args:
file_monitor (FileMonitor): file log monitor to detect events
"""
timestamp = file_monitor.start(timeout=60, callback=callback_get_scan_timestap,
error_message='Did not receive expected "File integrity monitoring scan ended" event').result()
return timestamp


def wait_for_audit(whodata, monitor):
"""Wait for the audit callback if we are using whodata monitoring.
Args:
Expand Down
31 changes: 31 additions & 0 deletions tests/integration/test_fim/test_files/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ def restart_syscheckd(get_configuration, request):
control_service('start', daemon='wazuh-syscheckd')


@pytest.fixture(scope='function')
def restart_syscheckd_function(get_configuration, request):
"""
Restart syscheckd daemon.
"""
control_service('stop', daemon='wazuh-syscheckd')
truncate_file(LOG_FILE_PATH)
file_monitor = FileMonitor(LOG_FILE_PATH)
setattr(request.module, 'wazuh_log_monitor', file_monitor)
control_service('start', daemon='wazuh-syscheckd')


@pytest.fixture(scope='module')
def wait_for_fim_start(get_configuration, request):
"""
Expand All @@ -39,3 +51,22 @@ def wait_for_fim_start(get_configuration, request):
detect_initial_scan(file_monitor)
except KeyError:
detect_initial_scan(file_monitor)


@pytest.fixture(scope='function')
def wait_for_fim_start_function(get_configuration, request):
"""
Wait for realtime start, whodata start or end of initial FIM scan.
"""
file_monitor = getattr(request.module, 'wazuh_log_monitor')
mode_key = 'fim_mode' if 'fim_mode2' not in get_configuration['metadata'] else 'fim_mode2'

try:
if get_configuration['metadata'][mode_key] == 'realtime':
detect_realtime_start(file_monitor)
elif get_configuration['metadata'][mode_key] == 'whodata':
detect_whodata_start(file_monitor)
else: # scheduled
detect_initial_scan(file_monitor)
except KeyError:
detect_initial_scan(file_monitor)
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
"""
copyright: Copyright (C) 2015-2021, Wazuh Inc.

Created by Wazuh, Inc. <info@wazuh.com>.

This program is free software; you can redistribute it and/or modify it under the terms of GPLv2

type: integration

brief: Check that files that are being scanned by the syscheckd daemon can
modified (renamed/deleted), and that wazuh is not blocking the files.

tier: 0
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved

modules:
- syscheck

components:
- manager
- agent

path: tests/integration/test_fim/test_files/test_basic_usage/test_basic_usage_access_opened_files.py

daemons:
- wazuh-syscheckd

modes:
- scheduled

os_platform:
- linux
- windows
- solaris
- macos

os_version:
- Arch Linux
- Amazon Linux 2
- Amazon Linux 1
- CentOS 8
- CentOS 7
- CentOS 6
- Ubuntu Focal
- Ubuntu Bionic
- Ubuntu Xenial
- Ubuntu Trusty
- Debian Buster
- Debian Stretch
- Debian Jessie
- Debian Wheezy
- Red Hat 8
- Red Hat 7
- Red Hat 6
- Windows 10

references:
- https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/fim-configuration.html
- https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/localfile.html

tags:
- syscheck
"""

import os
import random
import string
import pytest
import time

from wazuh_testing.fim import (
LOG_FILE_PATH,
generate_params,
detect_initial_scan_start,
get_scan_timestamp,
)
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
from wazuh_testing.tools import PREFIX
from wazuh_testing.tools.configuration import (
load_wazuh_configurations,
check_apply_test,
)
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
from wazuh_testing.tools.monitoring import FileMonitor
from wazuh_testing.tools.file import delete_path_recursively


# Marks
pytestmark = [pytest.mark.tier(level=0)]
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved

# Variables
directory_str = os.path.join(PREFIX, "testdir1")
file_path = os.path.join(directory_str, "large_file")
wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)
test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data")
configurations_path = os.path.join(test_data_path, "wazuh_conf.yaml")

# configurations
conf_params = {"TEST_DIRECTORIES": directory_str, "MODULE_NAME": __name__}
parameters, metadata = generate_params(extra_params=conf_params)
configurations = load_wazuh_configurations(
configurations_path, __name__, params=parameters, metadata=metadata
)
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved


# Fixtures
@pytest.fixture(scope="module", params=configurations)
def get_configuration(request):
"""Get configurations from the module."""
return request.param


@pytest.fixture(scope="function")
def create_and_delete_large_file(get_configuration, request):
"""
Create a large file and later delete the path.
"""
if get_configuration["metadata"]["fim_mode"] != "scheduled":
pytest.skip("This test does not apply to realtime or whodata modes")
# If path exists delete it
if os.path.exists(directory_str):
delete_path_recursively(directory_str)
# create directory
os.mkdir(directory_str)
file_size = 1024 * 1024 * 960 # 968 MB
chunksize = 1024 * 768
# create file and write to it.
with open(file_path, "a") as f:
while os.stat(file_path).st_size < file_size:
f.write(random.choice(string.printable) * chunksize)
yield
# delete the file and path
delete_path_recursively(directory_str)
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved


@pytest.fixture(scope="function")
def wait_for_scan_start(get_configuration, request):
"""
Wait for start of initial FIM scan.
"""
file_monitor = getattr(request.module, "wazuh_log_monitor")
try:
detect_initial_scan_start(file_monitor)
except KeyError:
detect_initial_scan_start(file_monitor)

Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved

# Tests
@pytest.mark.parametrize(
"operation, tags_to_apply", [("delete", {"ossec_conf"}), ("rename", {"ossec_conf"})]
)
def test_basic_usage_access_opened_files(
operation,
tags_to_apply,
get_configuration,
configure_environment,
create_and_delete_large_file,
restart_syscheckd_function,
wait_for_scan_start,
):
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved
"""
description: Check that files that are being scanned by syscheckd daemon
can modified (renamed/deleted), and that wazuh is not
blocking the files.

wazuh_min_version: 4.3
Copy link
Member

Choose a reason for hiding this comment

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

Could you check if the min version that covers it is 4.3, please? I think that it also works to 4.2


parameters:
- operation:
type: string
brief: Tells which operation has to be performed.
- tags_to_apply:
type: string
brief: Tells which configuration to use.
- get_configuration:
type: fixture
brief: Get configurations from the module.
- configure_environment:
type: fixture
brief: Configure a custom environment for testing.
- create_and_delete_large_file:
type: fixture
brief: Creates file to be monitored. Cleans enviroment after test.
- restart_syscheckd_function:
type: fixture
brief: Restart the `wazuh-syscheckd` daemon.
- wait for scan start:
type: fixture
brief: Wait for start of initial FIM scan start.

assertions:
- Verify that the file hast been modified (renamed/deleted).
- Verify that the modificaction is done before the initial scan ends.

input_description: Two use cases are found in the test module and include
parameters for operation (`delete` and `rename`).
"""

check_apply_test(tags_to_apply, get_configuration["tags"])

# Wait a few seconds for scan to run on created file.
time.sleep(3)

modify_time = None
# Modify/Delete the file
if operation == "rename":
changed_path = os.path.join(directory_str, "changed_name")
try:
modify_time = time.time()
os.rename(file_path, changed_path)
# Assert the file has been changed
assert os.path.isfile(changed_path) == True
except (OSError, IOError, PermissionError) as error:
pytest.fail(f"Could not rename file - Error: {error}")
elif operation == "delete":
try:
os.remove(file_path)
modify_time = time.time()
# Assert the file has been deleted
assert os.path.isfile(file_path) == False
except (OSError, IOError, PermissionError) as error:
pytest.fail(f"Could not delete file - Error: {error}")

# Capture scan end timestamp & assert the file was modified before scan end
scan_timestamp = get_scan_timestamp(wazuh_log_monitor)
assert modify_time < scan_timestamp
Deblintrake09 marked this conversation as resolved.
Show resolved Hide resolved